-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathnimcheck.nim
103 lines (89 loc) · 2.82 KB
/
nimcheck.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import std/[strutils]
import regex
import chronos, chronos/asyncproc
import stew/[byteutils]
import chronicles
import protocol/types
import utils
type
CheckStacktrace* = object
file*: string
line*: int
column*: int
msg*: string
CheckResult* = object
file*: string
line*: int
column*: int
msg*: string
severity*: string
stacktrace*: seq[CheckStacktrace]
proc parseCheckResults(lines: seq[string]): seq[CheckResult] =
result = @[]
var
messageText = ""
stacktrace: seq[CheckStacktrace]
lastFile, lastLineStr, lastCharStr: string
m: RegexMatch2
let dotsPattern = re2"^\.+$"
let errorPattern = re2"^([^(]+)\((\d+),\s*(\d+)\)\s*(\w+):\s*(.*)$"
for line in lines:
let line = line.strip()
if line.startsWith("Hint: used config file") or line == "" or line.match(dotsPattern):
continue
if not find(line, errorPattern, m):
if messageText.len < 1024:
messageText &= "\n" & line
else:
try:
let
file = line[m.captures[0]]
lineStr = line[m.captures[1]]
charStr = line[m.captures[2]]
severity = line[m.captures[3]]
msg = line[m.captures[4]]
let
lineNum = parseInt(lineStr)
colNum = parseInt(charStr)
result.add(CheckResult(
file: file,
line: lineNum,
column: colNum,
msg: msg,
severity: severity,
stacktrace: @[]
))
except Exception as e:
error "Error processing line", line = line, msg = e.msg
continue
if messageText.len > 0 and result.len > 0:
result[^1].msg &= "\n" & messageText
proc nimCheck*(filePath: string, nimPath: string): Future[seq[CheckResult]] {.async.} =
debug "nimCheck", filePath = filePath, nimPath = nimPath
let isNimble = filePath.endsWith(".nimble")
let isNimScript = filePath.endsWith(".nims") or isNimble
var extraArgs = newSeq[string]()
if isNimScript:
extraArgs.add("--import: system/nimscript")
if isNimble:
extraArgs.add("--include: " & getNimScriptAPITemplatePath())
let process = await startProcess(
nimPath,
arguments = @["check", "--listFullPaths"] & extraArgs & @[filePath],
options = {UsePath},
stderrHandle = AsyncProcess.Pipe,
stdoutHandle = AsyncProcess.Pipe,
)
try:
let res = await process.waitForExit(15.seconds)
# debug "nimCheck exit", res = res
var output = ""
if res == 0: #Nim check return 0 if there are no errors but we still need to check for hints and warnings
output = string.fromBytes(process.stdoutStream.read().await)
else:
output = string.fromBytes(process.stderrStream.read().await)
let lines = output.splitLines()
parseCheckResults(lines)
finally:
if not process.isNil:
discard process.kill()