@@ -2039,14 +2039,15 @@ type FormattedDiagnosticDetailedInfo =
20392039        Location:  FormattedDiagnosticLocation option 
20402040        Canonical:  FormattedDiagnosticCanonicalInformation 
20412041        Message:  string 
2042+         Context:  string option 
20422043    } 
20432044
20442045[<RequireQualifiedAccess>] 
20452046type  FormattedDiagnostic  = 
20462047    |  Short of  FSharpDiagnosticSeverity  *  string 
20472048    |  Long of  FSharpDiagnosticSeverity  *  FormattedDiagnosticDetailedInfo 
20482049
2049- let  FormatDiagnosticLocation   ( tcConfig :  TcConfig )  m  :  FormattedDiagnosticLocation  = 
2050+ let  FormatDiagnosticLocation   ( tcConfig :  TcConfig )  ( m :   Range )  :  FormattedDiagnosticLocation  = 
20502051    if  equals m rangeStartup ||  equals m rangeCmdArgs then 
20512052        { 
20522053            Range =  m
@@ -2073,7 +2074,7 @@ let FormatDiagnosticLocation (tcConfig: TcConfig) m : FormattedDiagnosticLocatio
20732074            |  DiagnosticStyle.Default -> 
20742075                let  file  =  file.Replace( '/' ,  Path.DirectorySeparatorChar) 
20752076                let  m  =  withStart ( mkPos m.StartLine ( m.StartColumn +  1 ))  m
2076-                 ( sprintf " %s  (%d  ,%d  ):  "   file m.StartLine m.StartColumn),  m,  file
2077+                 ( sprintf " ◦→  %s   (%d  ,%d  )"   file m.StartLine m.StartColumn),  m,  file
20772078
20782079            // We may also want to change Test to be 1-based 
20792080            |  DiagnosticStyle.Test -> 
@@ -2150,7 +2151,7 @@ let CollectFormattedDiagnostics (tcConfig: TcConfig, severity: FSharpDiagnosticS
21502151                match  tcConfig.diagnosticStyle with 
21512152                // Show the subcategory for --vserrors so that we can fish it out in Visual Studio and use it to determine error stickiness. 
21522153                |  DiagnosticStyle.VisualStudio ->  sprintf " %s   %s   FS%04d  : "   subcategory message errorNumber
2153-                 |  _  ->  sprintf " %s   FS%04d  : "   message errorNumber
2154+                 |  _  ->  sprintf " \n ◦→  %s   FS%04d  : "   message errorNumber
21542155
21552156            let  canonical :  FormattedDiagnosticCanonicalInformation  = 
21562157                { 
@@ -2159,11 +2160,37 @@ let CollectFormattedDiagnostics (tcConfig: TcConfig, severity: FSharpDiagnosticS
21592160                    TextRepresentation =  text
21602161                } 
21612162
2162-             let  message  =  diagnostic.FormatCore( tcConfig.flatErrors,  suggestNames) 
2163+             let  message  = 
2164+                 diagnostic.FormatCore( tcConfig.flatErrors,  suggestNames) .Split([|  '\n'  |]) 
2165+                 |>  Array.map ( fun  msg  ->  " \n ◦   "   +  msg) 
2166+                 |>  String.Concat
2167+ 
2168+             let  context  = 
2169+                 match  diagnostic.Range with 
2170+                 |  Some m -> 
2171+                     let  content  = 
2172+                         m.FileName
2173+                         |>  FileSystem.GetFullFilePathInDirectoryShim tcConfig.implicitIncludeDir
2174+                         |>  System.IO.File.ReadAllLines
2175+ 
2176+                     if  m.StartLine =  m.EndLine then 
2177+                         $" \n ◦ {m.StartLine} |{content[m.StartLine - 1]}\n " 
2178+                         +  $""" ◦ {String.init (m.StartColumn + 3) (fun _ -> " ")}^{String.init (m.EndColumn - m.StartColumn) (fun _ -> "~")}""" 
2179+                         |>  Some
2180+                     else 
2181+                         None
2182+                 // Untested multi-line support: 
2183+                 //    content 
2184+                 //    |> fun lines -> Array.sub lines (m.StartLine - 1) (m.EndLine - m.StartLine - 1) 
2185+                 //    |> Array.fold (fun (context, lineNumber) line -> (context + $"\n◦ {lineNumber} |{line}", lineNumber + 1)) ("", (m.StartLine)) 
2186+                 //    |> fst 
2187+                 //    |> Some 
2188+                 |  None ->  None
21632189
21642190            let  entry :  FormattedDiagnosticDetailedInfo  = 
21652191                { 
21662192                    Location =  where
2193+                     Context =  context
21672194                    Canonical =  canonical
21682195                    Message =  message
21692196                } 
@@ -2194,7 +2221,10 @@ type PhasedDiagnostic with
21942221            |  FormattedDiagnostic.Short(_,  txt)  ->  buf.AppendString txt
21952222            |  FormattedDiagnostic.Long(_,  details)  -> 
21962223                match  details.Location with 
2197-                 |  Some l when  not  l.IsEmpty ->  buf.AppendString l.TextRepresentation
2224+                 |  Some l when  not  l.IsEmpty -> 
2225+                     buf.AppendString l.TextRepresentation
2226+                     // Because details.Context depends on the value of details.Location, if details.Location is not None, details.Context can be accessed directly. 
2227+                     buf.AppendString details.Context.Value
21982228                |  _  ->  () 
21992229
22002230                buf.AppendString details.Canonical.TextRepresentation
0 commit comments