Skip to content

Commit e21a76f

Browse files
saulKevinRansom
authored andcommitted
Add colours to FSI output (#2156)
* Add colours to FSI output * Update test baselines (made whitespace consistent)
1 parent f8e579f commit e21a76f

13 files changed

+1258
-943
lines changed

src/fsharp/CompileOptions.fs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,27 +1347,34 @@ let GetGeneratedILModuleName (t:CompilerTarget) (s:string) =
13471347
let ext = match t with | Dll -> "dll" | Module -> "netmodule" | _ -> "exe"
13481348
s + "." + ext
13491349

1350-
13511350
let ignoreFailureOnMono1_1_16 f = try f() with _ -> ()
13521351

1353-
let DoWithErrorColor isError f =
1354-
if not enableConsoleColoring then
1352+
let foreBackColor () =
1353+
try
1354+
let c = Console.ForegroundColor // may fail, perhaps on Mac, and maybe ForegroundColor is Black
1355+
let b = Console.BackgroundColor // may fail, perhaps on Mac, and maybe BackgroundColor is White
1356+
Some (c,b)
1357+
with
1358+
e -> None
1359+
1360+
let DoWithColor newColor f =
1361+
match enableConsoleColoring, foreBackColor() with
1362+
| false, _
1363+
| true, None ->
1364+
// could not get console colours, so no attempt to change colours, can not set them back
13551365
f()
1356-
else
1357-
let foreBackColor =
1358-
try
1359-
let c = Console.ForegroundColor // may fail, perhaps on Mac, and maybe ForegroundColor is Black
1360-
let b = Console.BackgroundColor // may fail, perhaps on Mac, and maybe BackgroundColor is White
1361-
Some (c,b)
1362-
with
1363-
e -> None
1364-
match foreBackColor with
1365-
| None -> f() (* could not get console colours, so no attempt to change colours, can not set them back *)
1366-
| Some (c,_) ->
1367-
try
1368-
let warnColor = if Console.BackgroundColor = ConsoleColor.White then ConsoleColor.DarkBlue else ConsoleColor.Cyan
1369-
let errorColor = ConsoleColor.Red
1370-
ignoreFailureOnMono1_1_16 (fun () -> Console.ForegroundColor <- (if isError then errorColor else warnColor))
1371-
f()
1372-
finally
1373-
ignoreFailureOnMono1_1_16 (fun () -> Console.ForegroundColor <- c)
1366+
| true, Some (c,_) ->
1367+
try
1368+
ignoreFailureOnMono1_1_16 (fun () -> Console.ForegroundColor <- newColor)
1369+
f()
1370+
finally
1371+
ignoreFailureOnMono1_1_16 (fun () -> Console.ForegroundColor <- c)
1372+
1373+
let DoWithErrorColor isError f =
1374+
match foreBackColor() with
1375+
| None -> f()
1376+
| Some (_, backColor) ->
1377+
let warnColor = if backColor = ConsoleColor.White then ConsoleColor.DarkBlue else ConsoleColor.Cyan
1378+
let errorColor = ConsoleColor.Red
1379+
let color = if isError then errorColor else warnColor
1380+
DoWithColor color f

src/fsharp/CompileOptions.fsi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ val NormalizeAssemblyRefs : TcImports -> (AbstractIL.IL.ILScopeRef -> AbstractIL
9292
// Miscellany
9393
val ignoreFailureOnMono1_1_16 : (unit -> unit) -> unit
9494
val mutable enableConsoleColoring : bool
95-
val DoWithErrorColor : isError:bool -> (unit -> 'a) -> 'a
95+
val DoWithColor : System.ConsoleColor -> (unit -> 'a) -> 'a
96+
val DoWithErrorColor : bool -> (unit -> 'a) -> 'a
9697
val ReportTime : TcConfig -> string -> unit
9798
val GetAbbrevFlagSet : TcConfigBuilder -> bool -> Set<string>
9899
val PostProcessCompilerArgs : string Set -> string [] -> string list

src/fsharp/fsi/fsi.fs

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ open Microsoft.FSharp.Compiler.Tastops
5555
open Microsoft.FSharp.Compiler.TcGlobals
5656

5757
open Internal.Utilities.Collections
58+
open Internal.Utilities.StructuredFormat
5859

5960
type FormatOptions = Internal.Utilities.StructuredFormat.FormatOptions
6061

@@ -148,6 +149,45 @@ module internal Utilities =
148149
let m = match typeArgs with [||] -> m | _ -> m.MakeGenericMethod(typeArgs)
149150
m.Invoke(obj, [|v1;v2;v3|]) |> unbox
150151

152+
let colorPrintL (outWriter : TextWriter) opts layout =
153+
let renderer =
154+
{ new LayoutRenderer<NoResult,NoState> with
155+
member r.Start () = NoState
156+
157+
member r.AddText z s =
158+
let color =
159+
match s with
160+
| Keyword _ -> ConsoleColor.Blue
161+
| TypeParameter _
162+
| Alias _
163+
| Class _ -> ConsoleColor.Cyan
164+
| StringLiteral _ -> ConsoleColor.Red
165+
| NumericLiteral _ -> ConsoleColor.Magenta
166+
| _ -> Console.ForegroundColor
167+
168+
DoWithColor color (fun () -> outWriter.Write s.Value)
169+
170+
z
171+
172+
member r.AddBreak z n =
173+
outWriter.WriteLine()
174+
outWriter.Write (String.replicate n " ")
175+
z
176+
177+
member r.AddTag z (tag,attrs,start) = z
178+
179+
member r.Finish z =
180+
outWriter.WriteLine()
181+
NoResult
182+
}
183+
184+
layout
185+
|> Internal.Utilities.StructuredFormat.Display.squash_layout opts
186+
|> Layout.renderL renderer
187+
|> ignore
188+
189+
outWriter.WriteLine()
190+
151191
let referencedAssemblies = Dictionary<string, DateTime>()
152192

153193
#if FX_RESHAPED_REFLECTION
@@ -237,7 +277,7 @@ type public FsiEvaluationSessionHostConfig () =
237277

238278
/// Used to print value signatures along with their values, according to the current
239279
/// set of pretty printers installed in the system, and default printing rules.
240-
type internal FsiValuePrinter(fsi: FsiEvaluationSessionHostConfig, g: TcGlobals, generateDebugInfo, resolvePath, outWriter) =
280+
type internal FsiValuePrinter(fsi: FsiEvaluationSessionHostConfig, g: TcGlobals, generateDebugInfo, resolvePath, outWriter: TextWriter) =
241281

242282
/// This printer is used by F# Interactive if no other printers apply.
243283
let DefaultPrintingIntercept (ienv: Internal.Utilities.StructuredFormat.IEnvironment) (obj:obj) =
@@ -405,10 +445,8 @@ type internal FsiValuePrinter(fsi: FsiEvaluationSessionHostConfig, g: TcGlobals,
405445
NicePrint.layoutValOrMember denv vref (* the rhs was suppressed by the printer, so no value to print *)
406446
else
407447
(NicePrint.layoutValOrMember denv vref ++ wordL (TaggedTextOps.tagText "=")) --- rhsL.Value
408-
Internal.Utilities.StructuredFormat.Display.output_layout opts outWriter fullL;
409-
outWriter.WriteLine()
410-
411448

449+
Utilities.colorPrintL outWriter opts fullL
412450

413451
/// Used to make a copy of input in order to include the input when displaying the error text.
414452
type internal FsiStdinSyphon(errorWriter: TextWriter) =
@@ -450,10 +488,9 @@ type internal FsiStdinSyphon(errorWriter: TextWriter) =
450488
Utilities.ignoreAllErrors (fun () ->
451489
let isError = true
452490
DoWithErrorColor isError (fun () ->
453-
errorWriter.WriteLine();
454491
writeViaBufferWithEnvironmentNewLines errorWriter (OutputDiagnosticContext " " syphon.GetLine) err;
455492
writeViaBufferWithEnvironmentNewLines errorWriter (OutputDiagnostic (tcConfig.implicitIncludeDir,tcConfig.showFullPaths,tcConfig.flatErrors,tcConfig.errorStyle,isError)) err;
456-
errorWriter.WriteLine()
493+
errorWriter.WriteLine("\n")
457494
errorWriter.Flush()))
458495

459496

@@ -498,7 +535,7 @@ type internal ErrorLoggerThatStopsOnFirstError(tcConfigB:TcConfigBuilder, fsiStd
498535
fsiConsoleOutput.Error.WriteLine()
499536
writeViaBufferWithEnvironmentNewLines fsiConsoleOutput.Error (OutputDiagnosticContext " " fsiStdinSyphon.GetLine) err
500537
writeViaBufferWithEnvironmentNewLines fsiConsoleOutput.Error (OutputDiagnostic (tcConfigB.implicitIncludeDir,tcConfigB.showFullPaths,tcConfigB.flatErrors,tcConfigB.errorStyle,isError)) err
501-
fsiConsoleOutput.Error.WriteLine())
538+
fsiConsoleOutput.Error.WriteLine("\n"))
502539

503540
override x.ErrorCount = errorCount
504541

@@ -1049,12 +1086,9 @@ type internal FsiDynamicCompiler
10491086

10501087
for (TImplFile(_qname,_,mexpr,_,_)) in declaredImpls do
10511088
let responseL = NicePrint.layoutInferredSigOfModuleExpr false denv infoReader AccessibleFromSomewhere rangeStdin mexpr
1052-
if not (Layout.isEmptyL responseL) then
1053-
fsiConsoleOutput.uprintfn "";
1089+
if not (Layout.isEmptyL responseL) then
10541090
let opts = valuePrinter.GetFsiPrintOptions()
1055-
let responseL = Internal.Utilities.StructuredFormat.Display.squash_layout opts responseL
1056-
Layout.renderL (Layout.channelR outWriter) responseL |> ignore
1057-
fsiConsoleOutput.uprintfnn ""
1091+
Utilities.colorPrintL outWriter opts responseL |> ignore
10581092

10591093
// Build the new incremental state.
10601094
let istate = {istate with optEnv = optEnv;
@@ -1741,7 +1775,7 @@ type internal FsiInteractionProcessor
17411775
initialInteractiveState) =
17421776

17431777
let mutable currState = initialInteractiveState
1744-
let event = Event<unit>()
1778+
let event = Control.Event<unit>()
17451779
let setCurrState s = currState <- s; event.Trigger()
17461780
let runCodeOnEventLoop errorLogger f istate =
17471781
try

tests/fsharp/core/load-script/out.stdout.bsl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,10 @@ Test 3=================================================
2222
Hello
2323
World
2424
-the end
25-
2625
namespace FSI_0002
2726

28-
2927
namespace FSI_0002
3028

31-
3229
namespace FSI_0002
3330

3431
>

0 commit comments

Comments
 (0)