diff --git a/compiler/ast.nim b/compiler/ast.nim index 25958f580..e073ce3e1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -819,6 +819,8 @@ type constraint*: PNode # additional constraints like 'lit|result'; also # misused for the codegenDecl pragma in the hope # it won't cause problems + when defined(nimsuggest): + allUsages*: seq[TLineInfo] TTypeSeq* = seq[PType] TLockLevel* = distinct int16 diff --git a/compiler/modules.nim b/compiler/modules.nim index 3893d377e..ef727e200 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -30,7 +30,7 @@ var ## XXX: we should implement recycling of file IDs ## if the user keeps renaming modules, the file IDs will keep growing -proc getModule(fileIdx: int32): PSym = +proc getModule*(fileIdx: int32): PSym = if fileIdx >= 0 and fileIdx < gCompiledModules.len: result = gCompiledModules[fileIdx] diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 7b44b4349..649e28cba 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -815,24 +815,33 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = type TErrorHandling = enum doNothing, doAbort, doRaise -proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = - template quit = - if defined(debug) or msg == errInternal or hintStackTrace in gNotes: - if stackTraceAvailable() and isNil(writelnHook): - writeStackTrace() - else: - styledMsgWriteln(fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " ") - quit 1 +proc quit(msg: TMsgKind) = + if defined(debug) or msg == errInternal or hintStackTrace in gNotes: + if stackTraceAvailable() and isNil(writelnHook): + writeStackTrace() + else: + styledMsgWriteln(fgRed, "No stack traceback available\n" & + "To create a stacktrace, rerun compilation with ./koch temp " & + options.command & " ") + quit 1 +proc log*(s: string) {.procvar.} = + var f: File + if open(f, "nimsuggest.log", fmAppend): + f.writeln(s) + close(f) + +proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = if msg >= fatalMin and msg <= fatalMax: - quit() + if gCmd == cmdIdeTools: log(s) + quit(msg) if msg >= errMin and msg <= errMax: inc(gErrorCounter) options.gExitcode = 1'i8 if gErrorCounter >= gErrorMax: - quit() + quit(msg) elif eh == doAbort and gCmd != cmdIdeTools: - quit() + quit(msg) elif eh == doRaise: raiseRecoverableError(s) diff --git a/compiler/options.nim b/compiler/options.nim index 6dd917ad4..f63757ac0 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -86,7 +86,8 @@ type # please make sure we have under 32 options gcNone, gcBoehm, gcGo, gcMarkAndSweep, gcRefc, gcV2, gcGenerational IdeCmd* = enum - ideNone, ideSug, ideCon, ideDef, ideUse, ideDus + ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, + ideHighlight, ideOutline var gIdeCmd*: IdeCmd @@ -422,6 +423,10 @@ proc parseIdeCmd*(s: string): IdeCmd = of "def": ideDef of "use": ideUse of "dus": ideDus + of "chk": ideChk + of "mod": ideMod + of "highlight": ideHighlight + of "outline": ideOutline else: ideNone proc `$`*(c: IdeCmd): string = @@ -431,4 +436,8 @@ proc `$`*(c: IdeCmd): string = of ideDef: "def" of ideUse: "use" of ideDus: "dus" + of ideChk: "chk" + of ideMod: "mod" of ideNone: "none" + of ideHighlight: "highlight" + of ideOutline: "outline" diff --git a/compiler/sem.nim b/compiler/sem.nim index 041524f84..c6db6fbd3 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -61,8 +61,8 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode; when defined(nimsuggest): assert gCmd == cmdIdeTools if requiresCheck: - if optIdeDebug in gGlobalOptions: - echo "passing to safeSemExpr: ", renderTree(n) + #if optIdeDebug in gGlobalOptions: + # echo "passing to safeSemExpr: ", renderTree(n) discard safeSemExpr(c, n) proc typeMismatch(n: PNode, formal, actual: PType) = @@ -441,6 +441,8 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = result = hloStmt(c, result) if gCmd == cmdInteractive and not isEmptyType(result.typ): result = buildEchoStmt(c, result) + if gCmd == cmdIdeTools: + appendToModule(c.module, result) result = transformStmt(c.module, result) proc recoverContext(c: PContext) = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f1016595a..58c42d410 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2083,11 +2083,6 @@ proc semExport(c: PContext, n: PNode): PNode = x.add(newSymNode(s, a.info)) strTableAdd(c.module.tab, s) s = nextOverloadIter(o, c, a) - when false: - if c.module.ast.isNil: - c.module.ast = newNodeI(nkStmtList, n.info) - assert c.module.ast.kind == nkStmtList - c.module.ast.add x result = n proc shouldBeBracketExpr(n: PNode): bool = diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index ef014963c..29cce9247 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -699,7 +699,7 @@ proc track(tracked: PEffects, n: PNode) = if notGcSafe(op) and not importedFromC(a): # and it's not a recursive call: if not (a.kind == nkSym and a.sym == tracked.owner): - warnAboutGcUnsafe(n) + if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, a) for i in 1 .. = current.col and col <= current.col+tokenLen-1: - return true +proc isTracked*(current: TLineInfo, tokenLen: int): bool = + if current.fileIndex==gTrackPos.fileIndex and current.line==gTrackPos.line: + let col = gTrackPos.col + if col >= current.col and col <= current.col+tokenLen-1: + return true proc findClosestSym(n: PNode): PNode = if n.kind == nkSym and inCheckpoint(n.info) == cpExact: @@ -278,23 +323,43 @@ proc findClosestSym(n: PNode): PNode = result = findClosestSym(n.sons[i]) if result != nil: return +when defined(nimsuggest): + # Since TLineInfo defined a == operator that doesn't include the column, + # we map TLineInfo to a unique int here for this lookup table: + proc infoToInt(info: TLineInfo): int64 = + info.fileIndex + info.line.int64 shl 32 + info.col.int64 shl 48 + + proc addNoDup(s: PSym; info: TLineInfo) = + let infoAsInt = info.infoToInt + for infoB in s.allUsages: + if infoB.infoToInt == infoAsInt: return + s.allUsages.add(info) + var usageSym*: PSym - lastLineInfo: TLineInfo + lastLineInfo*: TLineInfo proc findUsages(info: TLineInfo; s: PSym) = - if usageSym == nil and isTracked(info, s.name.s.len): - usageSym = s - suggestResult(symToSuggest(s, isLocal=false, $ideUse)) - elif s == usageSym: - if lastLineInfo != info: - suggestResult(symToSuggest(s, isLocal=false, $ideUse, info)) - lastLineInfo = info + if suggestVersion < 2: + if usageSym == nil and isTracked(info, s.name.s.len): + usageSym = s + suggestResult(symToSuggest(s, isLocal=false, $ideUse, 100)) + elif s == usageSym: + if lastLineInfo != info: + suggestResult(symToSuggest(s, isLocal=false, $ideUse, info, 100)) + lastLineInfo = info + +when defined(nimsuggest): + proc listUsages*(s: PSym) = + #echo "usages ", len(s.allUsages) + for info in s.allUsages: + let x = if info == s.info and info.col == s.info.col: "def" else: "use" + suggestResult(symToSuggest(s, isLocal=false, x, info, 100)) proc findDefinition(info: TLineInfo; s: PSym) = if s.isNil: return if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, $ideDef)) + suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100)) suggestQuit() proc ensureIdx[T](x: var T, y: int) = @@ -303,23 +368,36 @@ proc ensureIdx[T](x: var T, y: int) = proc ensureSeq[T](x: var seq[T]) = if x == nil: newSeq(x, 0) -proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} = +proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} = ## misnamed: should be 'symDeclared' - if gIdeCmd == ideUse: - findUsages(info, s) - elif gIdeCmd == ideDef: - findDefinition(info, s) - elif gIdeCmd == ideDus and s != nil: - if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, $ideDef)) - findUsages(info, s) + when defined(nimsuggest): + if suggestVersion == 2: + if s.allUsages.isNil: + s.allUsages = @[info] + else: + s.addNoDup(info) + + if gIdeCmd == ideUse: + findUsages(info, s) + elif gIdeCmd == ideDef: + findDefinition(info, s) + elif gIdeCmd == ideDus and s != nil: + if isTracked(info, s.name.s.len): + suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100)) + findUsages(info, s) + elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: + suggestResult(symToSuggest(s, isLocal=false, $ideHighlight, info, 100)) + elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and + isDecl: + suggestResult(symToSuggest(s, isLocal=false, $ideOutline, info, 100)) proc markUsed(info: TLineInfo; s: PSym) = incl(s.flags, sfUsed) if {sfDeprecated, sfError} * s.flags != {}: if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s) if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s) - suggestSym(info, s) + when defined(nimsuggest): + suggestSym(info, s, false) proc useSym*(sym: PSym): PNode = result = newSymNode(sym) @@ -348,8 +426,9 @@ proc suggestExpr*(c: PContext, node: PNode) = if n.kind == nkDotExpr: var obj = safeSemExpr(c, n.sons[0]) suggestFieldAccess(c, obj, outputs) - if optIdeDebug in gGlobalOptions: - echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ) + + #if optIdeDebug in gGlobalOptions: + # echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ) #writeStackTrace() else: suggestEverything(c, n, outputs) @@ -370,7 +449,7 @@ proc suggestExpr*(c: PContext, node: PNode) = suggestCall(c, a, n, outputs) dec(c.compilesContextId) - if outputs > 0 and gIdeCmd notin {ideUse, ideDus}: suggestQuit() + if outputs > 0 and gIdeCmd in {ideSug, ideCon, ideDef}: suggestQuit() proc suggestStmt*(c: PContext, n: PNode) = suggestExpr(c, n)