summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/suggest.nim89
-rw-r--r--nimsuggest/nimsuggest.nim3
-rw-r--r--nimsuggest/tester.nim3
-rw-r--r--nimsuggest/tests/tdot4.nim16
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".#[!]#