msgs.nim 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2013 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. import
  10. options, strutils, os, tables, ropes, platform, terminal, macros,
  11. lineinfos, pathutils
  12. proc toCChar*(c: char; result: var string) =
  13. case c
  14. of '\0'..'\x1F', '\x7F'..'\xFF':
  15. result.add '\\'
  16. result.add toOctal(c)
  17. of '\'', '\"', '\\', '?':
  18. result.add '\\'
  19. result.add c
  20. else:
  21. result.add c
  22. proc makeCString*(s: string): Rope =
  23. const MaxLineLength = 64
  24. result = nil
  25. var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
  26. add(res, "\"")
  27. for i in countup(0, len(s) - 1):
  28. if (i + 1) mod MaxLineLength == 0:
  29. add(res, "\"\L\"")
  30. toCChar(s[i], res)
  31. add(res, '\"')
  32. add(result, rope(res))
  33. proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
  34. result.fullPath = fullPath
  35. #shallow(result.fullPath)
  36. result.projPath = projPath
  37. #shallow(result.projPath)
  38. let fileName = fullPath.extractFilename
  39. result.shortName = fileName.changeFileExt("")
  40. result.quotedName = fileName.makeCString
  41. result.quotedFullName = fullPath.string.makeCString
  42. result.lines = @[]
  43. when defined(nimpretty):
  44. if not result.fullPath.isEmpty:
  45. try:
  46. result.fullContent = readFile(result.fullPath.string)
  47. except IOError:
  48. #rawMessage(errCannotOpenFile, result.fullPath)
  49. # XXX fixme
  50. result.fullContent = ""
  51. when defined(nimpretty):
  52. proc fileSection*(conf: ConfigRef; fid: FileIndex; a, b: int): string =
  53. substr(conf.m.fileInfos[fid.int].fullContent, a, b)
  54. proc fileInfoKnown*(conf: ConfigRef; filename: AbsoluteFile): bool =
  55. var
  56. canon: AbsoluteFile
  57. try:
  58. canon = canonicalizePath(conf, filename)
  59. except OSError:
  60. canon = filename
  61. result = conf.m.filenameToIndexTbl.hasKey(canon.string)
  62. proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool): FileIndex =
  63. var
  64. canon: AbsoluteFile
  65. pseudoPath = false
  66. try:
  67. canon = canonicalizePath(conf, filename)
  68. shallow(canon.string)
  69. except OSError:
  70. canon = filename
  71. # The compiler uses "filenames" such as `command line` or `stdin`
  72. # This flag indicates that we are working with such a path here
  73. pseudoPath = true
  74. if conf.m.filenameToIndexTbl.hasKey(canon.string):
  75. result = conf.m.filenameToIndexTbl[canon.string]
  76. else:
  77. isKnownFile = false
  78. result = conf.m.fileInfos.len.FileIndex
  79. conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: RelativeFile filename
  80. else: relativeTo(canon, conf.projectPath)))
  81. conf.m.filenameToIndexTbl[canon.string] = result
  82. proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
  83. var dummy: bool
  84. result = fileInfoIdx(conf, filename, dummy)
  85. proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
  86. result.fileIndex = fileInfoIdx
  87. result.line = uint16(line)
  88. result.col = int16(col)
  89. proc newLineInfo*(conf: ConfigRef; filename: AbsoluteFile, line, col: int): TLineInfo {.inline.} =
  90. result = newLineInfo(fileInfoIdx(conf, filename), line, col)
  91. proc concat(strings: openarray[string]): string =
  92. var totalLen = 0
  93. for s in strings: totalLen += s.len
  94. result = newStringOfCap totalLen
  95. for s in strings: result.add s
  96. proc suggestWriteln*(conf: ConfigRef; s: string) =
  97. if eStdOut in conf.m.errorOutputs:
  98. if isNil(conf.writelnHook):
  99. writeLine(stdout, s)
  100. flushFile(stdout)
  101. else:
  102. conf.writelnHook(s)
  103. proc msgQuit*(x: int8) = quit x
  104. proc msgQuit*(x: string) = quit x
  105. proc suggestQuit*() =
  106. raise newException(ESuggestDone, "suggest done")
  107. # this format is understood by many text editors: it is the same that
  108. # Borland and Freepascal use
  109. const
  110. PosFormat = "$1($2, $3) "
  111. KindFormat = " [$1]"
  112. KindColor = fgCyan
  113. ErrorTitle = "Error: "
  114. ErrorColor = fgRed
  115. WarningTitle = "Warning: "
  116. WarningColor = fgYellow
  117. HintTitle = "Hint: "
  118. HintColor = fgGreen
  119. proc getInfoContextLen*(conf: ConfigRef): int = return conf.m.msgContext.len
  120. proc setInfoContextLen*(conf: ConfigRef; L: int) = setLen(conf.m.msgContext, L)
  121. proc pushInfoContext*(conf: ConfigRef; info: TLineInfo; detail: string = "") =
  122. conf.m.msgContext.add((info, detail))
  123. proc popInfoContext*(conf: ConfigRef) =
  124. setLen(conf.m.msgContext, len(conf.m.msgContext) - 1)
  125. proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo =
  126. let L = conf.m.msgContext.len
  127. let i = if index < 0: L + index else: index
  128. if i >=% L: result = unknownLineInfo()
  129. else: result = conf.m.msgContext[i].info
  130. template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string =
  131. if fileIdx.int32 < 0 or conf == nil:
  132. "???"
  133. else:
  134. conf.m.fileInfos[fileIdx.int32].projPath.string
  135. proc toFullPath*(conf: ConfigRef; fileIdx: FileIndex): string =
  136. if fileIdx.int32 < 0 or conf == nil: result = "???"
  137. else: result = conf.m.fileInfos[fileIdx.int32].fullPath.string
  138. proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile) =
  139. assert fileIdx.int32 >= 0
  140. conf.m.fileInfos[fileIdx.int32].dirtyFile = filename
  141. proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
  142. assert fileIdx.int32 >= 0
  143. shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
  144. proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
  145. assert fileIdx.int32 >= 0
  146. shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
  147. proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): AbsoluteFile =
  148. if fileIdx.int32 < 0:
  149. result = AbsoluteFile"???"
  150. elif not conf.m.fileInfos[fileIdx.int32].dirtyFile.isEmpty:
  151. result = conf.m.fileInfos[fileIdx.int32].dirtyFile
  152. else:
  153. result = conf.m.fileInfos[fileIdx.int32].fullPath
  154. template toFilename*(conf: ConfigRef; info: TLineInfo): string =
  155. toFilename(conf, info.fileIndex)
  156. template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
  157. toFullPath(conf, info.fileIndex)
  158. proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
  159. if info.fileIndex.int32 < 0:
  160. result = "???"
  161. return
  162. let absPath = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
  163. let relPath = conf.m.fileInfos[info.fileIndex.int32].projPath.string
  164. if optListFullPaths in conf.globalOptions:
  165. result = absPath
  166. else:
  167. result = if absPath.len < relPath.len: absPath else: relPath
  168. proc toLinenumber*(info: TLineInfo): int {.inline.} =
  169. result = int info.line
  170. proc toColumn*(info: TLineInfo): int {.inline.} =
  171. result = info.col
  172. proc toFileLine*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
  173. result = toFilename(conf, info) & ":" & $info.line
  174. proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
  175. result = toFilename(conf, info) & "(" & $info.line & ", " & $(info.col+1) & ")"
  176. proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
  177. proc `$`*(info: TLineInfo): string {.error.} = discard
  178. proc `??`* (conf: ConfigRef; info: TLineInfo, filename: string): bool =
  179. # only for debugging purposes
  180. result = filename in toFilename(conf, info)
  181. type
  182. MsgFlag* = enum ## flags altering msgWriteln behavior
  183. msgStdout, ## force writing to stdout, even stderr is default
  184. msgSkipHook ## skip message hook even if it is present
  185. MsgFlags* = set[MsgFlag]
  186. proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) =
  187. ## Writes given message string to stderr by default.
  188. ## If ``--stdout`` option is given, writes to stdout instead. If message hook
  189. ## is present, then it is used to output message rather than stderr/stdout.
  190. ## This behavior can be altered by given optional flags.
  191. ## This is used for 'nim dump' etc. where we don't have nimsuggest
  192. ## support.
  193. #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
  194. if not isNil(conf.writelnHook) and msgSkipHook notin flags:
  195. conf.writelnHook(s)
  196. elif optStdout in conf.globalOptions or msgStdout in flags:
  197. if eStdOut in conf.m.errorOutputs:
  198. writeLine(stdout, s)
  199. flushFile(stdout)
  200. else:
  201. if eStdErr in conf.m.errorOutputs:
  202. writeLine(stderr, s)
  203. # On Windows stderr is fully-buffered when piped, regardless of C std.
  204. when defined(windows):
  205. flushFile(stderr)
  206. macro callIgnoringStyle(theProc: typed, first: typed,
  207. args: varargs[typed]): untyped =
  208. let typForegroundColor = bindSym"ForegroundColor".getType
  209. let typBackgroundColor = bindSym"BackgroundColor".getType
  210. let typStyle = bindSym"Style".getType
  211. let typTerminalCmd = bindSym"TerminalCmd".getType
  212. result = newCall(theProc)
  213. if first.kind != nnkNilLit: result.add(first)
  214. for arg in children(args[0][1]):
  215. if arg.kind == nnkNilLit: continue
  216. let typ = arg.getType
  217. if typ.kind != nnkEnumTy or
  218. typ != typForegroundColor and
  219. typ != typBackgroundColor and
  220. typ != typStyle and
  221. typ != typTerminalCmd:
  222. result.add(arg)
  223. macro callStyledWriteLineStderr(args: varargs[typed]): untyped =
  224. result = newCall(bindSym"styledWriteLine")
  225. result.add(bindSym"stderr")
  226. for arg in children(args[0][1]):
  227. result.add(arg)
  228. template callWritelnHook(args: varargs[string, `$`]) =
  229. conf.writelnHook concat(args)
  230. template styledMsgWriteln*(args: varargs[typed]) =
  231. if not isNil(conf.writelnHook):
  232. callIgnoringStyle(callWritelnHook, nil, args)
  233. elif optStdout in conf.globalOptions:
  234. if eStdOut in conf.m.errorOutputs:
  235. callIgnoringStyle(writeLine, stdout, args)
  236. flushFile(stdout)
  237. else:
  238. if eStdErr in conf.m.errorOutputs:
  239. if optUseColors in conf.globalOptions:
  240. callStyledWriteLineStderr(args)
  241. else:
  242. callIgnoringStyle(writeLine, stderr, args)
  243. # On Windows stderr is fully-buffered when piped, regardless of C std.
  244. when defined(windows):
  245. flushFile(stderr)
  246. proc coordToStr(coord: int): string =
  247. if coord == -1: result = "???"
  248. else: result = $coord
  249. proc msgKindToString*(kind: TMsgKind): string =
  250. # later versions may provide translated error messages
  251. result = MsgKindToStr[kind]
  252. proc getMessageStr(msg: TMsgKind, arg: string): string =
  253. result = msgKindToString(msg) % [arg]
  254. type
  255. TErrorHandling = enum doNothing, doAbort, doRaise
  256. proc log*(s: string) {.procvar.} =
  257. var f: File
  258. if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
  259. f.writeLine(s)
  260. close(f)
  261. proc quit(conf: ConfigRef; msg: TMsgKind) =
  262. if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
  263. if stackTraceAvailable() and isNil(conf.writelnHook):
  264. writeStackTrace()
  265. else:
  266. styledMsgWriteln(fgRed, "No stack traceback available\n" &
  267. "To create a stacktrace, rerun compilation with ./koch temp " &
  268. conf.command & " <file>")
  269. quit 1
  270. proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) =
  271. if msg >= fatalMin and msg <= fatalMax:
  272. if conf.cmd == cmdIdeTools: log(s)
  273. quit(conf, msg)
  274. if msg >= errMin and msg <= errMax:
  275. inc(conf.errorCounter)
  276. conf.exitcode = 1'i8
  277. if conf.errorCounter >= conf.errorMax:
  278. quit(conf, msg)
  279. elif eh == doAbort and conf.cmd != cmdIdeTools:
  280. quit(conf, msg)
  281. elif eh == doRaise:
  282. raiseRecoverableError(s)
  283. proc `==`*(a, b: TLineInfo): bool =
  284. result = a.line == b.line and a.fileIndex == b.fileIndex
  285. proc exactEquals*(a, b: TLineInfo): bool =
  286. result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col
  287. proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
  288. const instantiationFrom = "template/generic instantiation from here"
  289. const instantiationOfFrom = "template/generic instantiation of `$1` from here"
  290. var info = lastinfo
  291. for i in 0 ..< len(conf.m.msgContext):
  292. let context = conf.m.msgContext[i]
  293. if context.info != lastinfo and context.info != info:
  294. if conf.structuredErrorHook != nil:
  295. conf.structuredErrorHook(conf, context.info, instantiationFrom,
  296. Severity.Error)
  297. else:
  298. let message = if context.detail == "":
  299. instantiationFrom
  300. else:
  301. instantiationOfFrom.format(context.detail)
  302. styledMsgWriteln(styleBright,
  303. PosFormat % [toMsgFilename(conf, context.info),
  304. coordToStr(context.info.line.int),
  305. coordToStr(context.info.col+1)],
  306. resetStyle,
  307. message)
  308. info = context.info
  309. proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
  310. msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions
  311. proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
  312. var
  313. title: string
  314. color: ForegroundColor
  315. kind: string
  316. sev: Severity
  317. case msg
  318. of errMin..errMax:
  319. sev = Severity.Error
  320. writeContext(conf, unknownLineInfo())
  321. title = ErrorTitle
  322. color = ErrorColor
  323. of warnMin..warnMax:
  324. sev = Severity.Warning
  325. if optWarns notin conf.options: return
  326. if msg notin conf.notes: return
  327. writeContext(conf, unknownLineInfo())
  328. title = WarningTitle
  329. color = WarningColor
  330. kind = WarningsToStr[ord(msg) - ord(warnMin)]
  331. inc(conf.warnCounter)
  332. of hintMin..hintMax:
  333. sev = Severity.Hint
  334. if optHints notin conf.options: return
  335. if msg notin conf.notes: return
  336. title = HintTitle
  337. color = HintColor
  338. if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
  339. inc(conf.hintCounter)
  340. let s = msgKindToString(msg) % args
  341. if conf.structuredErrorHook != nil:
  342. conf.structuredErrorHook(conf, unknownLineInfo(),
  343. s & (if kind.len > 0: KindFormat % kind else: ""), sev)
  344. if not ignoreMsgBecauseOfIdeTools(conf, msg):
  345. if kind.len > 0:
  346. styledMsgWriteln(color, title, resetStyle, s,
  347. KindColor, `%`(KindFormat, kind))
  348. else:
  349. styledMsgWriteln(color, title, resetStyle, s)
  350. handleError(conf, msg, doAbort, s)
  351. proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) =
  352. rawMessage(conf, msg, [arg])
  353. proc resetAttributes*(conf: ConfigRef) =
  354. if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}:
  355. terminal.resetAttributes(stderr)
  356. proc addSourceLine(conf: ConfigRef; fileIdx: FileIndex, line: string) =
  357. conf.m.fileInfos[fileIdx.int32].lines.add line
  358. proc sourceLine*(conf: ConfigRef; i: TLineInfo): string =
  359. if i.fileIndex.int32 < 0: return ""
  360. if not optPreserveOrigSource(conf) and conf.m.fileInfos[i.fileIndex.int32].lines.len == 0:
  361. try:
  362. for line in lines(toFullPath(conf, i)):
  363. addSourceLine conf, i.fileIndex, line.string
  364. except IOError:
  365. discard
  366. assert i.fileIndex.int32 < conf.m.fileInfos.len
  367. # can happen if the error points to EOF:
  368. if i.line.int > conf.m.fileInfos[i.fileIndex.int32].lines.len: return ""
  369. result = conf.m.fileInfos[i.fileIndex.int32].lines[i.line.int-1]
  370. proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) =
  371. const indent = " "
  372. msgWriteln(conf, indent & $sourceLine(conf, info))
  373. msgWriteln(conf, indent & spaces(info.col) & '^')
  374. proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
  375. let title = case msg
  376. of warnMin..warnMax: WarningTitle
  377. of hintMin..hintMax: HintTitle
  378. else: ErrorTitle
  379. result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
  380. coordToStr(info.col+1)] &
  381. title &
  382. getMessageStr(msg, arg)
  383. proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
  384. eh: TErrorHandling) =
  385. var
  386. title: string
  387. color: ForegroundColor
  388. kind: string
  389. ignoreMsg = false
  390. sev: Severity
  391. case msg
  392. of errMin..errMax:
  393. sev = Severity.Error
  394. writeContext(conf, info)
  395. title = ErrorTitle
  396. color = ErrorColor
  397. # we try to filter error messages so that not two error message
  398. # in the same file and line are produced:
  399. #ignoreMsg = lastError == info and eh != doAbort
  400. conf.m.lastError = info
  401. of warnMin..warnMax:
  402. sev = Severity.Warning
  403. ignoreMsg = optWarns notin conf.options or msg notin conf.notes
  404. if not ignoreMsg: writeContext(conf, info)
  405. title = WarningTitle
  406. color = WarningColor
  407. kind = WarningsToStr[ord(msg) - ord(warnMin)]
  408. inc(conf.warnCounter)
  409. of hintMin..hintMax:
  410. sev = Severity.Hint
  411. ignoreMsg = optHints notin conf.options or msg notin conf.notes
  412. title = HintTitle
  413. color = HintColor
  414. if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
  415. inc(conf.hintCounter)
  416. # NOTE: currently line info line numbers start with 1,
  417. # but column numbers start with 0, however most editors expect
  418. # first column to be 1, so we need to +1 here
  419. let x = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
  420. coordToStr(info.col+1)]
  421. let s = getMessageStr(msg, arg)
  422. if not ignoreMsg:
  423. if conf.structuredErrorHook != nil:
  424. conf.structuredErrorHook(conf, info, s & (if kind.len > 0: KindFormat % kind else: ""), sev)
  425. if not ignoreMsgBecauseOfIdeTools(conf, msg):
  426. if kind.len > 0:
  427. styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
  428. KindColor, `%`(KindFormat, kind))
  429. else:
  430. styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
  431. if hintSource in conf.notes:
  432. conf.writeSurroundingSrc(info)
  433. handleError(conf, msg, eh, s)
  434. proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
  435. # this fixes bug #7080 so that it is at least obvious 'fatal'
  436. # was executed.
  437. conf.m.errorOutputs = {eStdOut, eStdErr}
  438. liMessage(conf, info, msg, arg, doAbort)
  439. proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
  440. liMessage(conf, info, msg, arg, doRaise)
  441. proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
  442. liMessage(conf, info, errGenerated, arg, doRaise)
  443. proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
  444. liMessage(conf, info, msg, arg, doNothing)
  445. proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
  446. liMessage(conf, info, errGenerated, arg, doNothing)
  447. proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openarray[string]) =
  448. localError(conf, info, format % params)
  449. proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
  450. liMessage(conf, info, msg, arg, doNothing)
  451. proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
  452. if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
  453. writeContext(conf, info)
  454. liMessage(conf, info, errInternal, errMsg, doAbort)
  455. proc internalError*(conf: ConfigRef; errMsg: string) =
  456. if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
  457. writeContext(conf, unknownLineInfo())
  458. rawMessage(conf, errInternal, errMsg)
  459. template assertNotNil*(conf: ConfigRef; e): untyped =
  460. if e == nil: internalError(conf, $instantiationInfo())
  461. e
  462. template internalAssert*(conf: ConfigRef, e: bool) =
  463. if not e: internalError(conf, $instantiationInfo())
  464. proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
  465. assert i.fileIndex.int32 >= 0
  466. if optExcessiveStackTrace in conf.globalOptions:
  467. result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
  468. else:
  469. result = conf.m.fileInfos[i.fileIndex.int32].quotedName
  470. proc listWarnings*(conf: ConfigRef) =
  471. msgWriteln(conf, "Warnings:")
  472. for warn in warnMin..warnMax:
  473. msgWriteln(conf, " [$1] $2" % [
  474. if warn in conf.notes: "x" else: " ",
  475. lineinfos.WarningsToStr[ord(warn) - ord(warnMin)]
  476. ])
  477. proc listHints*(conf: ConfigRef) =
  478. msgWriteln(conf, "Hints:")
  479. for hint in hintMin..hintMax:
  480. msgWriteln(conf, " [$1] $2" % [
  481. if hint in conf.notes: "x" else: " ",
  482. lineinfos.HintsToStr[ord(hint) - ord(hintMin)]
  483. ])