Skip to content

Commit def3b95

Browse files
authored
Merge pull request #1280 from simba909/feature/automagically-colored-diagnostics
Implement support for automatically coloring output in DiagnosticsFormatter
2 parents 14ddf4e + 81c8740 commit def3b95

File tree

4 files changed

+71
-10
lines changed

4 files changed

+71
-10
lines changed

Sources/SwiftDiagnostics/DiagnosticsFormatter.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,11 @@ public struct DiagnosticsFormatter {
139139
switch message.severity {
140140
case .error:
141141
let annotation = ANSIAnnotation(color: .red, trait: .bold)
142-
return annotation.applied(to: message.message)
142+
return annotation.applied(to: "error: \(message.message)")
143143
case .warning:
144-
let annotation = ANSIAnnotation(color: .yellow)
145-
return annotation.applied(to: message.message)
144+
let color = ANSIAnnotation(color: .yellow)
145+
let prefix = color.withTrait(.bold).applied(to: "warning: ")
146+
return prefix + color.applied(to: message.message)
146147
case .note:
147148
return message.message
148149
}
@@ -181,6 +182,10 @@ struct ANSIAnnotation {
181182
self.trait = trait
182183
}
183184

185+
func withTrait(_ trait: Trait) -> Self {
186+
return ANSIAnnotation(color: self.color, trait: trait)
187+
}
188+
184189
func applied(to message: String) -> String {
185190
// Resetting after the message ensures that we don't color unintended lines in the output
186191
return "\(code)\(message)\(ANSIAnnotation.normal.code)"
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if canImport(Glibc)
14+
import Glibc
15+
#elseif os(Windows)
16+
import CRT
17+
#else
18+
import Darwin.C
19+
#endif
20+
21+
#if os(Android)
22+
typealias FILEPointer = OpaquePointer
23+
#else
24+
typealias FILEPointer = UnsafeMutablePointer<FILE>
25+
#endif
26+
27+
enum TerminalHelper {
28+
static var isConnectedToTerminal: Bool {
29+
return isTTY(stderr)
30+
}
31+
32+
/// Checks if passed file pointer is a tty.
33+
static func isTTY(_ filePointer: FILEPointer) -> Bool {
34+
return terminalType(filePointer) == .tty
35+
}
36+
37+
/// The type of terminal.
38+
enum TerminalType {
39+
/// The terminal is a TTY.
40+
case tty
41+
42+
/// The terminal is a file stream.
43+
case file
44+
}
45+
46+
/// Computes the terminal type of the stream.
47+
static func terminalType(_ filePointer: FILEPointer) -> TerminalType {
48+
let isTTY = isatty(fileno(filePointer)) != 0
49+
return isTTY ? .tty : .file
50+
}
51+
}

Sources/swift-parser-cli/swift-parser-cli.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,22 @@ class PrintDiags: ParsableCommand {
198198
@Flag(name: .long, help: "Perform sequence folding with the standard operators")
199199
var foldSequences: Bool = false
200200

201-
@Flag(name: .long, help: "Colorize output with ANSI color codes")
201+
@Flag(name: .long, help: "Force output coloring with ANSI color codes")
202202
var colorize: Bool = false
203203

204204
func run() throws {
205205
let source = try getContentsOfSourceFile(at: sourceFile)
206206

207207
source.withUnsafeBufferPointer { sourceBuffer in
208208
let tree = Parser.parse(source: sourceBuffer)
209-
210209
var diags = ParseDiagnosticsGenerator.diagnostics(for: tree)
211-
print(DiagnosticsFormatter.annotatedSource(tree: tree, diags: diags, colorize: colorize))
210+
let annotatedSource = DiagnosticsFormatter.annotatedSource(
211+
tree: tree,
212+
diags: diags,
213+
colorize: colorize || TerminalHelper.isConnectedToTerminal
214+
)
215+
216+
print(annotatedSource)
212217

213218
if foldSequences {
214219
diags += foldAllSequences(tree).1

Tests/SwiftDiagnosticsTest/DiagnosticsFormatterTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ final class DiagnosticsFormatterTests: XCTestCase {
101101

102102
let expectedOutput = """
103103
1 │ var foo = bar +
104-
∣ ╰─ \u{001B}[1;31mexpected expression in variable\u{001B}[0;0m
104+
∣ ╰─ \u{001B}[1;31merror: expected expression in variable\u{001B}[0;0m
105105
106106
"""
107107
AssertStringsEqualWithDiff(expectedOutput, annotate(source: source, colorize: true))
@@ -113,9 +113,9 @@ final class DiagnosticsFormatterTests: XCTestCase {
113113
"""
114114
let expectedOutput = """
115115
1 │ foo.[].[].[]
116-
∣ │ │ ╰─ \u{001B}[1;31mexpected name in member access\u{001B}[0;0m
117-
∣ │ ╰─ \u{001B}[1;31mexpected name in member access\u{001B}[0;0m
118-
∣ ╰─ \u{001B}[1;31mexpected name in member access\u{001B}[0;0m
116+
∣ │ │ ╰─ \u{001B}[1;31merror: expected name in member access\u{001B}[0;0m
117+
∣ │ ╰─ \u{001B}[1;31merror: expected name in member access\u{001B}[0;0m
118+
∣ ╰─ \u{001B}[1;31merror: expected name in member access\u{001B}[0;0m
119119
120120
"""
121121
AssertStringsEqualWithDiff(expectedOutput, annotate(source: source, colorize: true))

0 commit comments

Comments
 (0)