diff options
-rw-r--r-- | compiler/suggest.nim | 89 | ||||
-rw-r--r-- | nimsuggest/nimsuggest.nim | 3 | ||||
-rw-r--r-- | nimsuggest/tester.nim | 3 | ||||
-rw-r--r-- | nimsuggest/tests/tdot4.nim | 16 |
4 files changed, 62 insertions, 49 deletions
diff --git a/compiler/suggest.nim b/compiler/suggest.nim index e5a9f424a..04f5baac4 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -63,6 +63,7 @@ type var suggestionResultHook*: proc (result: Suggest) {.closure.} suggestVersion*: int + suggestMaxResults* = 10_000 #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n" @@ -104,11 +105,11 @@ proc cmpSuggestions(a, b: Suggest): int = # independent of hashing order: result = cmp(a.name.s, b.name.s) -proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; +proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; quality: range[0..100]; prefix: PrefixMatch; inTypeContext: bool; scope: int): Suggest = new(result) - result.section = parseIdeCmd(section) + result.section = section result.quality = quality result.isGlobal = sfGlobal in s.flags result.tokenLen = s.name.s.len @@ -120,15 +121,10 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; result.globalUsages = s.allUsages.len var c = 0 for u in s.allUsages: - if u.fileIndex == li.fileIndex: inc c + if u.fileIndex == info.fileIndex: inc c result.localUsages = c - if optIdeTerse in gGlobalOptions: - result.symkind = s.kind - result.filePath = toFullPath(li) - result.line = toLinenumber(li) - result.column = toColumn(li) - else: - result.symkind = s.kind + result.symkind = s.kind + if optIdeTerse notin gGlobalOptions: result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner @@ -143,11 +139,12 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; result.forth = typeToString(s.typ) else: result.forth = "" - result.filePath = toFullPath(li) - result.line = toLinenumber(li) - result.column = toColumn(li) when not defined(noDocgen): result.doc = s.extractDocComment + let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info + result.filePath = toFullPath(infox) + result.line = toLinenumber(infox) + result.column = toColumn(infox) proc `$`*(suggest: Suggest): string = result = $suggest.section @@ -188,11 +185,6 @@ proc `$`*(suggest: Suggest): string = result.add(sep) result.add($suggest.prefix) -proc symToSuggest(s: PSym, isLocal: bool, section: string; - quality: range[0..100], prefix: PrefixMatch; inTypeContext: bool; - scope: int): Suggest = - result = symToSuggest(s, isLocal, section, s.info, quality, prefix, inTypeContext, scope) - proc suggestResult(s: Suggest) = if not isNil(suggestionResultHook): suggestionResultHook(s) @@ -205,7 +197,7 @@ proc produceOutput(a: var Suggestions) = when false: # debug code writeStackTrace() - if a.len > 10: a.setLen(10) + if a.len > suggestMaxResults: a.setLen(suggestMaxResults) if not isNil(suggestionResultHook): for s in a: suggestionResultHook(s) @@ -241,10 +233,10 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = result = true break -proc suggestField(c: PContext, s: PSym; f: PNode; outputs: var Suggestions) = +proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) = var pm: PrefixMatch if filterSym(s, f, pm) and fieldVisible(c, s): - outputs.add(symToSuggest(s, isLocal=true, $ideSug, 100, pm, c.inTypeContext > 0, 0)) + outputs.add(symToSuggest(s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0)) proc getQuality(s: PSym): range[0..100] = if s.typ != nil and s.typ.len > 1: @@ -263,25 +255,25 @@ template wholeSymTab(cond, section: untyped) = let it {.inject.} = item var pm {.inject.}: PrefixMatch if cond: - outputs.add(symToSuggest(it, isLocal = isLocal, section, getQuality(it), + outputs.add(symToSuggest(it, isLocal = isLocal, section, info, getQuality(it), pm, c.inTypeContext > 0, scopeN)) -proc suggestSymList(c: PContext, list, f: PNode, outputs: var Suggestions) = +proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) = for i in countup(0, sonsLen(list) - 1): if list.sons[i].kind == nkSym: - suggestField(c, list.sons[i].sym, f, outputs) + suggestField(c, list.sons[i].sym, f, info, outputs) #else: InternalError(list.info, "getSymFromList") -proc suggestObject(c: PContext, n, f: PNode, outputs: var Suggestions) = +proc suggestObject(c: PContext, n, f: PNode; info: TLineInfo, outputs: var Suggestions) = case n.kind of nkRecList: - for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], f, outputs) + for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], f, info, outputs) of nkRecCase: var L = sonsLen(n) if L > 0: - suggestObject(c, n.sons[0], f, outputs) - for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), f, outputs) - of nkSym: suggestField(c, n.sym, f, outputs) + suggestObject(c, n.sons[0], f, info, outputs) + for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), f, info, outputs) + of nkSym: suggestField(c, n.sym, f, info, outputs) else: discard proc nameFits(c: PContext, s: PSym, n: PNode): bool = @@ -305,8 +297,9 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool = result = false proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var Suggestions) = + let info = n.info wholeSymTab(filterSym(it, nil, pm) and nameFits(c, it, n) and argsFit(c, it, n, nOrig), - $ideCon) + ideCon) proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil: @@ -323,7 +316,8 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Suggestions) = assert typ != nil - wholeSymTab(filterSymNoOpr(it, f, pm) and typeFits(c, it, typ), $ideSug) + let info = n.info + wholeSymTab(filterSymNoOpr(it, f, pm) and typeFits(c, it, typ), ideSug) proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = # do not produce too many symbols: @@ -335,7 +329,8 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = for it in items(scope.symbols): var pm: PrefixMatch if filterSym(it, f, pm): - outputs.add(symToSuggest(it, isLocal = isLocal, $ideSug, 0, pm, c.inTypeContext > 0, scopeN)) + outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, n.info, 0, pm, + c.inTypeContext > 0, scopeN)) #if scope == c.topLevelScope and f.isNil: break proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) = @@ -356,8 +351,8 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) else: for it in items(n.sym.tab): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -100)) - outputs.add(symToSuggest(m, isLocal=false, $ideMod, 100, PrefixMatch.None, + outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100)) + outputs.add(symToSuggest(m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None, c.inTypeContext > 0, -99)) if typ == nil: @@ -367,11 +362,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # all symbols accessible, because we are in the current module: for it in items(c.topLevelScope.symbols): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: for it in items(n.sym.tab): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: # fallback: suggestEverything(c, n, field, outputs) @@ -379,7 +374,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # look up if the identifier belongs to the enum: var t = typ while t != nil: - suggestSymList(c, t.n, field, outputs) + suggestSymList(c, t.n, field, n.info, outputs) t = t.sons[0] suggestOperations(c, n, field, typ, outputs) else: @@ -388,11 +383,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) if typ.kind == tyObject: var t = typ while true: - suggestObject(c, t.n, field, outputs) + suggestObject(c, t.n, field, n.info, outputs) if t.sons[0] == nil: break t = skipTypes(t.sons[0], skipPtrs) elif typ.kind == tyTuple and typ.n != nil: - suggestSymList(c, typ.n, field, outputs) + suggestSymList(c, typ.n, field, n.info, outputs) suggestOperations(c, n, field, orig, outputs) if typ != orig: suggestOperations(c, n, field, typ, outputs) @@ -436,23 +431,23 @@ proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) = if suggestVersion == 1: if usageSym == nil and isTracked(info, s.name.s.len): usageSym = s - suggestResult(symToSuggest(s, isLocal=false, $ideUse, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) elif s == usageSym: if lastLineInfo != info: - suggestResult(symToSuggest(s, isLocal=false, $ideUse, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) 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" + let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse suggestResult(symToSuggest(s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) proc findDefinition(info: TLineInfo; s: PSym) = if s.isNil: return if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) suggestQuit() proc ensureIdx[T](x: var T, y: int) = @@ -476,13 +471,13 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in findDefinition(info, s) elif gIdeCmd == ideDus and s != nil: if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) findUsages(info, s, usageSym) elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: - suggestResult(symToSuggest(s, isLocal=false, $ideHighlight, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and isDecl: - suggestResult(symToSuggest(s, isLocal=false, $ideOutline, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) = incl(s.flags, sfUsed) @@ -574,7 +569,7 @@ proc suggestSentinel*(c: PContext) = for it in items(scope.symbols): var pm: PrefixMatch if filterSymNoOpr(it, nil, pm): - outputs.add(symToSuggest(it, isLocal = isLocal, $ideSug, 0, PrefixMatch.None, false, scopeN)) + outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN)) dec(c.compilesContextId) produceOutput(outputs) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 8f2e4ff1e..188d7fb5a 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -40,6 +40,7 @@ Options: --log enable verbose logging to nimsuggest.log file --v1 use version 1 of the protocol; for backwards compatibility --refresh perform automatic refreshes to keep the analysis precise + --maxresults:N limit the number of suggestions to N --tester implies --stdin and outputs a line '""" & DummyEof & """' for the tester @@ -550,6 +551,8 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = gRefresh = parseBool(p.val) else: gRefresh = true + of "maxresults": + suggestMaxResults = parseInt(p.val) else: processSwitch(pass, p) of cmdArgument: options.gProjectName = unixToNativePath(p.key) diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 16f70beb5..4cda272af 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -304,8 +304,7 @@ proc runTest(filename: string): int = proc main() = var failures = 0 if os.paramCount() > 0: - let f = os.paramStr(1) - let x = getAppDir() / f + let x = os.paramStr(1) let xx = expandFilename x failures += runTest(xx) failures += runEpcTest(xx) diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim new file mode 100644 index 000000000..3d98f9132 --- /dev/null +++ b/nimsuggest/tests/tdot4.nim @@ -0,0 +1,16 @@ +discard """ +$nimsuggest --tester --maxresults:2 $file +>sug $1 +sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;10;;5;;"";;100;;None +sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1497;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None +""" + +import strutils + +proc main(inp: string): string = + # use replace here and see if it occurs in the result, it should gain + # priority: + result = inp.replace(" ", "a").replace("b", "c") + + +echo "string literal here".#[!]# |