summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/msgs.nim143
1 files changed, 90 insertions, 53 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 2d7094e63..2edb869d8 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -8,7 +8,7 @@
 #
 
 import
-  options, strutils, os, tables, ropes, platform, terminal
+  options, strutils, os, tables, ropes, platform, terminal, macros
 
 type
   TMsgKind* = enum
@@ -605,13 +605,15 @@ proc suggestQuit*() =
 # this format is understood by many text editors: it is the same that
 # Borland and Freepascal use
 const
-  PosErrorFormat* = "$1($2, $3) Error: "
-  PosWarningFormat* = "$1($2, $3) Warning: "
-  PosHintFormat* = "$1($2, $3) Hint: "
-  PosContextFormat = "$1($2, $3) Info: "
-  RawError* = "Error: "
-  RawWarning* = "Warning: "
-  RawHint* = "Hint: "
+  PosFormat    = "$1($2, $3) "
+  ErrorTitle   = "Error: "
+  ErrorColor   = fgRed
+  WarningTitle = "Warning: "
+  WarningColor = fgYellow
+  HintTitle    = "Hint: "
+  HintColor    = fgGreen
+  InfoTitle    = "Info: "
+  InfoColor    = fgCyan
 
 proc getInfoContextLen*(): int = return msgContext.len
 proc setInfoContextLen*(L: int) = setLen(msgContext, L)
@@ -686,27 +688,58 @@ proc outWriteln*(s: string) =
   ## Writes to stdout. Always.
   if eStdOut in errorOutputs: writeln(stdout, s)
 
-proc msgWriteln*(s: string, color: ForegroundColor = fgWhite, coloredText: string = "") =
-  ## Writes to stdout. If --stderr option is given, writes to stderr instead.
+proc msgWriteln*(s: string) =
+  ## Writes to stdout. If --stdout option is given, writes to stderr instead.
 
   #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
 
-  var hasColor = optUseColors in gGlobalOptions
   if not isNil(writelnHook):
-    writelnHook(coloredText & s)
+    writelnHook(s)
+  elif optStdout in gGlobalOptions:
+    if eStdErr in errorOutputs: writeln(stderr, s)
   else:
-    if optStdout in gGlobalOptions:
-      if eStdErr in errorOutputs:
-        if hasColor: setForegroundColor(color)
-        write(stderr, coloredText)
-        if hasColor: resetAttributes()
-        writeln(stderr, s)
-    else:
-      if eStdOut in errorOutputs:
-        if hasColor: setForegroundColor(color)
-        write(stdout, coloredText)
-        if hasColor: resetAttributes()
-        writeln(stdout, s)
+    if eStdOut in errorOutputs: writeln(stdout, s)
+
+macro callIgnoringStyle(theProc: typed, first: typed,
+                        args: varargs[expr]): stmt =
+  let typForegroundColor = bindSym"ForegroundColor".getType
+  let typBackgroundColor = bindSym"BackgroundColor".getType
+  let typStyle = bindSym"Style".getType
+  let typTerminalCmd = bindSym"TerminalCmd".getType
+  result = newCall(theProc)
+  if first.kind != nnkNilLit: result.add(first)
+  for arg in children(args[0][1]):
+    if arg.kind == nnkNilLit: continue
+    let typ = arg.getType
+    if typ.kind != nnkEnumTy or
+       typ != typForegroundColor and
+       typ != typBackgroundColor and
+       typ != typStyle and
+       typ != typTerminalCmd:
+      result.add(arg)
+
+macro callStyledEcho(args: varargs[expr]): stmt =
+  result = newCall(bindSym"styledEcho")
+  for arg in children(args[0][1]):
+    result.add(arg)
+
+template callWritelnHook(args: varargs[string, `$`]) =
+  var s = ""
+  for arg in args:
+    s.add arg
+  writelnHook s
+
+template styledMsgWriteln*(args: varargs[expr]) =
+  if not isNil(writelnHook):
+    callIgnoringStyle(callWritelnHook, nil, args)
+  elif optStdout in gGlobalOptions:
+    if eStdErr in errorOutputs: callIgnoringStyle(writeln, stderr, args)
+  else:
+    if eStdOut in errorOutputs:
+      if optUseColors in gGlobalOptions:
+        callStyledEcho(args)
+      else:
+        callIgnoringStyle(writeln, stdout, args)
 
 proc coordToStr(coord: int): string =
   if coord == -1: result = "???"
@@ -728,7 +761,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
       if stackTraceAvailable() and isNil(writelnHook):
         writeStackTrace()
       else:
-        msgWriteln("", fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
+        styledMsgWriteln(fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
     quit 1
 
   if msg >= fatalMin and msg <= fatalMax:
@@ -750,10 +783,12 @@ proc writeContext(lastinfo: TLineInfo) =
   var info = lastinfo
   for i in countup(0, len(msgContext) - 1):
     if msgContext[i] != lastinfo and msgContext[i] != info:
-      msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
-                                   coordToStr(msgContext[i].line),
-                                   coordToStr(msgContext[i].col+1),
-                                   getMessageStr(errInstantiationFrom, "")])
+      styledMsgWriteln(styleBright,
+                       PosFormat % [toMsgFilename(msgContext[i]),
+                                    coordToStr(msgContext[i].line),
+                                    coordToStr(msgContext[i].col+1)],
+                       styleDim,
+                       getMessageStr(errInstantiationFrom, ""))
     info = msgContext[i]
 
 proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
@@ -761,29 +796,29 @@ proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
 
 proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
   var
-    frmt: string
+    title: string
     color: ForegroundColor
   case msg
   of errMin..errMax:
     writeContext(unknownLineInfo())
-    frmt = RawError
-    color = fgRed
+    title = ErrorTitle
+    color = ErrorColor
   of warnMin..warnMax:
     if optWarns notin gOptions: return
     if msg notin gNotes: return
     writeContext(unknownLineInfo())
-    frmt = RawWarning
+    title = WarningTitle
+    color = WarningColor
     inc(gWarnCounter)
-    color = fgYellow
   of hintMin..hintMax:
     if optHints notin gOptions: return
     if msg notin gNotes: return
-    frmt = RawHint
+    title = HintTitle
+    color = HintColor
     inc(gHintCounter)
-    color = fgGreen
   let s = `%`(msgKindToString(msg), args)
   if not ignoreMsgBecauseOfIdeTools(msg):
-    msgWriteln(s, color, frmt)
+    styledMsgWriteln(color, title, resetStyle, s)
   handleError(msg, doAbort, s)
 
 proc rawMessage*(msg: TMsgKind, arg: string) =
@@ -795,47 +830,49 @@ proc writeSurroundingSrc(info: TLineInfo) =
   msgWriteln(indent & spaces(info.col) & '^')
 
 proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
-  let frmt = case msg
-             of warnMin..warnMax: PosWarningFormat
-             of hintMin..hintMax: PosHintFormat
-             else: PosErrorFormat
-  result = frmt % [toMsgFilename(info), coordToStr(info.line),
-                   coordToStr(info.col+1), getMessageStr(msg, arg)]
+  let title = case msg
+              of warnMin..warnMax: WarningTitle
+              of hintMin..hintMax: HintTitle
+              else: ErrorTitle
+  result = PosFormat % [toMsgFilename(info), coordToStr(info.line),
+                        coordToStr(info.col+1)] &
+           title &
+           getMessageStr(msg, arg)
 
 proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
                eh: TErrorHandling) =
   var
-    frmt: string
+    title: string
     ignoreMsg = false
     color: ForegroundColor
   case msg
   of errMin..errMax:
     writeContext(info)
-    frmt = PosErrorFormat
+    title = ErrorTitle
+    color = ErrorColor
     # we try to filter error messages so that not two error message
     # in the same file and line are produced:
     #ignoreMsg = lastError == info and eh != doAbort
     lastError = info
-    color = fgRed
   of warnMin..warnMax:
     ignoreMsg = optWarns notin gOptions or msg notin gNotes
     if not ignoreMsg: writeContext(info)
-    frmt = PosWarningFormat
+    title = WarningTitle
+    color = WarningColor
     inc(gWarnCounter)
-    color = fgYellow
   of hintMin..hintMax:
     ignoreMsg = optHints notin gOptions or msg notin gNotes
-    frmt = PosHintFormat
+    title = HintTitle
+    color = HintColor
     inc(gHintCounter)
-    color = fgGreen
   # NOTE: currently line info line numbers start with 1,
   # but column numbers start with 0, however most editors expect
   # first column to be 1, so we need to +1 here
-  let x = frmt % [toMsgFilename(info), coordToStr(info.line),
-                  coordToStr(info.col+1)]
+  let x = PosFormat % [toMsgFilename(info), coordToStr(info.line),
+                       coordToStr(info.col+1)]
   let s = getMessageStr(msg, arg)
   if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
-    msgWriteln(s, color, x)
+    styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
     if optPrintSurroundingSrc and msg in errMin..errMax:
       info.writeSurroundingSrc
   handleError(msg, eh, s)