diff --git a/compiler/tools/suggest.nim b/compiler/tools/suggest.nim index 2348bc38f66..7a8394a5ccf 100644 --- a/compiler/tools/suggest.nim +++ b/compiler/tools/suggest.nim @@ -56,6 +56,7 @@ import options, ], compiler/modules/[ + modules, modulegraphs, ], compiler/sem/[ @@ -66,7 +67,8 @@ import compiler/utils/[ prefixmatches, astrepr, - debugutils + debugutils, + pathutils ] @@ -466,6 +468,52 @@ proc isTracked*(current, trackPos: TLineInfo, tokenLen: int): bool = if col >= current.col and col <= current.col+tokenLen-1: return true +proc findTrackedNode(n: PNode; trackPos: TLineInfo): PSym = + if n.kind == nkSym: + if isTracked(n.info, trackPos, n.sym.name.s.len): return n.sym + else: + for i in 0 ..< safeLen(n): + let res = findTrackedNode(n[i], trackPos) + if res != nil: return res + +proc findTrackedSym*(g: ModuleGraph;): PSym = + let m = g.getModule(g.config.m.trackPos.fileIndex) + if m != nil and m.ast != nil: + # xxx: the node finding should be specialized per symbol kind + result = findTrackedNode(m.ast, g.config.m.trackPos) + +proc executeCmd*(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; + graph: ModuleGraph) = + ## executes the given suggest command, `cmd`, for a given `file`, at the + ## position described by `line` and `col`umn. If `dirtyFile` is non-empty, + ## then its contents are used as part of the analysis. + let conf = graph.config + conf.ideCmd = cmd + var isKnownFile = true + let dirtyIdx = fileInfoIdx(conf, file, isKnownFile) + + if dirtyfile.isEmpty: msgs.setDirtyFile(conf, dirtyIdx, AbsoluteFile"") + else: msgs.setDirtyFile(conf, dirtyIdx, dirtyfile) + + conf.m.trackPos = newLineInfo(dirtyIdx, line, col) + conf.m.trackPosAttached = false + conf.errorCounter = 0 + if not isKnownFile: + graph.compileProject(dirtyIdx) + if conf.ideCmd in {ideUse, ideDus} and + dirtyfile.isEmpty: + discard "no need to recompile anything" + else: + let modIdx = graph.parentModule(dirtyIdx) + graph.markDirty dirtyIdx + graph.markClientsDirty dirtyIdx + # partially recompiling the project means that that VM and JIT state + # would become stale, which we prevent by discarding all of it: + graph.vm = nil + if conf.ideCmd != ideMod: + if isKnownFile: + graph.compileProject(modIdx) + when defined(nimsuggest): proc addNoDup(s: PSym; info: TLineInfo) = diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 2a235dec7cf..edf987ad869 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -63,7 +63,7 @@ from compiler/ast/reports import Report, from compiler/front/main import customizeForBackend -from compiler/tools/suggest import isTracked, listUsages, suggestSym, `$` +from compiler/tools/suggest import findTrackedSym, executeCmd, listUsages, suggestSym, `$` when defined(windows): import winlean @@ -204,20 +204,6 @@ proc listEpc(): SexpNode = methodDesc.add(docstring) result.add(methodDesc) -proc findNode(n: PNode; trackPos: TLineInfo): PSym = - #echo "checking node ", n.info - if n.kind == nkSym: - if isTracked(n.info, trackPos, n.sym.name.s.len): return n.sym - else: - for i in 0 ..< safeLen(n): - let res = findNode(n[i], trackPos) - if res != nil: return res - -proc symFromInfo(graph: ModuleGraph; trackPos: TLineInfo): PSym = - let m = graph.getModule(trackPos.fileIndex) - if m != nil and m.ast != nil: - result = findNode(m.ast, trackPos) - proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; graph: ModuleGraph) = let conf = graph.config @@ -227,33 +213,9 @@ proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; dirtyfile.string & "[" & $line & ":" & $col & "]" ) - conf.ideCmd = cmd - var isKnownFile = true - let dirtyIdx = fileInfoIdx(conf, file, isKnownFile) - - if not dirtyfile.isEmpty: msgs.setDirtyFile(conf, dirtyIdx, dirtyfile) - else: msgs.setDirtyFile(conf, dirtyIdx, AbsoluteFile"") - - conf.m.trackPos = newLineInfo(dirtyIdx, line, col) - conf.m.trackPosAttached = false - conf.errorCounter = 0 - if not isKnownFile: - graph.compileProject(dirtyIdx) - if conf.ideCmd in {ideUse, ideDus} and - dirtyfile.isEmpty: - discard "no need to recompile anything" - else: - let modIdx = graph.parentModule(dirtyIdx) - graph.markDirty dirtyIdx - graph.markClientsDirty dirtyIdx - # partially recompiling the project means that that VM and JIT state - # would become stale, which we prevent by discarding all of it: - graph.vm = nil - if conf.ideCmd != ideMod: - if isKnownFile: - graph.compileProject(modIdx) + executeCmd(cmd, file, dirtyfile, line, col, graph) if conf.ideCmd in {ideUse, ideDus}: - let u = graph.symFromInfo(conf.m.trackPos) + let u = graph.findTrackedSym() if u != nil: listUsages(graph, u) else: