Skip to content

Commit

Permalink
nimsuggest: move library code into suggest (#892)
Browse files Browse the repository at this point in the history
<!--- The Pull Request (=PR) message is what will get automatically used
as
the commit message when the PR is merged. Make sure that no line is
longer
than 72 characters -->

## Summary

Extract procedures that do not rely on the command-line from the
`nimsuggest` module to the `suggest` module.

## Details

Changes:

- procedure `findNode` was moved and renamed to `findTrackedNode`
- procedure `symFromInfo` was moved and renamed to `findTrackedSym`
- the ide command execution part of `executeNoHooks` was extracted and
  moved into `executeCmd`

This makes the `suggest` module more of a reusable component for other
non-`nimsuggest` tools, e.g. the LSP server.

---------

Co-authored-by: Saem Ghani <saemghani+github@gmail.com>
  • Loading branch information
bung87 and saem authored Sep 15, 2023
1 parent c1607a1 commit a08aa4e
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 42 deletions.
50 changes: 49 additions & 1 deletion compiler/tools/suggest.nim
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import
options,
],
compiler/modules/[
modules,
modulegraphs,
],
compiler/sem/[
Expand All @@ -65,7 +66,8 @@ import
compiler/utils/[
prefixmatches,
astrepr,
debugutils
debugutils,
pathutils
]


Expand Down Expand Up @@ -464,6 +466,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) =
Expand Down
44 changes: 3 additions & 41 deletions nimsuggest/nimsuggest.nim
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,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
Expand Down Expand Up @@ -206,20 +206,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
Expand All @@ -229,33 +215,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:
Expand Down

0 comments on commit a08aa4e

Please sign in to comment.