summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJake Leahy <jake@leahy.dev>2023-12-08 09:05:41 +1100
committerGitHub <noreply@github.com>2023-12-07 23:05:41 +0100
commit0a7094450ec059e10da67d47a76d004d4972b368 (patch)
treef0e3e5abe4197b53b922c17835cf8323b20136da
parent4fdc6c49bd2a9085d40590bd9ba9696b1e6066d9 (diff)
downloadNim-0a7094450ec059e10da67d47a76d004d4972b368.tar.gz
Only suggest symbols that could be pragmas when typing a pragma (#23040)
Currently pragmas just fall through to `suggestSentinel` and show
everything which isn't very useful. Now it filters for symbols that
could be pragmas (templates with `{.pragma.}`, macros, user pragmas) and
only shows them
-rw-r--r--compiler/pragmas.nim5
-rw-r--r--compiler/semstmts.nim4
-rw-r--r--compiler/semtypes.nim2
-rw-r--r--compiler/suggest.nim37
-rw-r--r--nimsuggest/tests/tsug_pragmas.nim40
5 files changed, 85 insertions, 3 deletions
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index fe4ef2b87..0e434e6f7 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -14,6 +14,8 @@ import
   wordrecg, ropes, options, extccomp, magicsys, trees,
   types, lookups, lineinfos, pathutils, linter, modulepaths
 
+from sigmatch import trySuggestPragmas
+
 import std/[os, math, strutils]
 
 when defined(nimPreviewSlimSystem):
@@ -119,6 +121,7 @@ const
 
 proc invalidPragma*(c: PContext; n: PNode) =
   localError(c.config, n.info, "invalid pragma: " & renderTree(n, {renderNoComments}))
+
 proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) =
   var msg = "cannot attach a custom pragma to '" & s.name.s & "'"
   if s != nil:
@@ -790,6 +793,8 @@ proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
     invalidPragma(c, n)
     return n
 
+  trySuggestPragmas(c, callNode[0])
+
   let r = c.semOverloadedCall(c, callNode, n, {skTemplate}, {efNoUndeclared})
   if r.isNil or sfCustomPragma notin r[0].sym.flags:
     invalidPragma(c, n)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 4b08767c0..70818bb67 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -525,6 +525,8 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode =
       let it = pragmas[i]
       let key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it
 
+      trySuggestPragmas(c, key)
+
       if isPossibleMacroPragma(c, it, key):
         # we transform ``var p {.m, rest.}`` into ``m(do: var p {.rest.})`` and
         # let the semantic checker deal with it:
@@ -1741,6 +1743,8 @@ proc semProcAnnotation(c: PContext, prc: PNode;
     let it = n[i]
     let key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it
 
+    trySuggestPragmas(c, key)
+
     if isPossibleMacroPragma(c, it, key):
       # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and
       # let the semantic checker deal with it:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index be33114f5..7968122ed 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1741,10 +1741,10 @@ proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode =
   result = nil
   for p in pragmas:
     let key = if p.kind in nkPragmaCallKinds and p.len >= 1: p[0] else: p
-
     if p.kind == nkEmpty or whichPragma(p) != wInvalid:
       discard "builtin pragma"
     else:
+      trySuggestPragmas(c, key)
       let ident = considerQuotedIdent(c, key)
       if strTableGet(c.userPragmas, ident) != nil:
         discard "User-defined pragma"
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 5053fe669..802da1c3e 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -126,7 +126,7 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
                   inTypeContext: bool; scope: int;
                   useSuppliedInfo = false,
                   endLine: uint16 = 0,
-                  endCol = 0): Suggest =
+                  endCol = 0, extractDocs = true): Suggest =
   new(result)
   result.section = section
   result.quality = quality
@@ -165,7 +165,8 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
     else:
       result.forth = ""
     when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
-      result.doc = extractDocComment(g, s)
+      if extractDocs:
+        result.doc = extractDocComment(g, s)
   if s.kind == skModule and s.ast.len != 0 and section != ideHighlight:
     result.filePath = toFullPath(g.config, s.ast[0].info)
     result.line = 1
@@ -746,6 +747,38 @@ proc suggestEnum*(c: PContext; n: PNode; t: PType) =
   produceOutput(outputs, c.config)
   if outputs.len > 0: suggestQuit()
 
+proc suggestPragmas*(c: PContext, n: PNode) =
+  ## Suggests anything that might be a pragma
+  ## - template that has {.pragma.}
+  ## - macros
+  ## - user pragmas
+  let info = n.info
+  var outputs: Suggestions = @[]
+  # First filter for template/macros
+  wholeSymTab(filterSym(it, n, pm) and
+    (sfCustomPragma in it.flags or it.kind == skMacro),
+    ideSug)
+
+  # Now show suggestions for user pragmas
+  for pragma in c.userPragmas:
+      var pm = default(PrefixMatch)
+      if filterSym(pragma, n, pm):
+        outputs &= symToSuggest(c.graph, pragma, isLocal=true, ideSug, info,
+                                 pragma.getQuality, pm, c.inTypeContext > 0, 0,
+                                 extractDocs=false)
+
+  produceOutput(outputs, c.config)
+  if outputs.len > 0:
+    suggestQuit()
+
+template trySuggestPragmas*(c: PContext, n: PNode) =
+  ## Runs [suggestPragmas] when compiling nimsuggest and
+  ## we are querying the node
+  when defined(nimsuggest):
+    let tmp = n
+    if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, tmp.info):
+      suggestPragmas(c, tmp)
+
 proc suggestSentinel*(c: PContext) =
   if c.config.ideCmd != ideSug or c.module.position != c.config.m.trackPos.fileIndex.int32: return
   if c.compilesContextId > 0: return
diff --git a/nimsuggest/tests/tsug_pragmas.nim b/nimsuggest/tests/tsug_pragmas.nim
new file mode 100644
index 000000000..03a9cba4c
--- /dev/null
+++ b/nimsuggest/tests/tsug_pragmas.nim
@@ -0,0 +1,40 @@
+template fooBar1() {.pragma.}
+proc fooBar2() = discard
+macro fooBar3(x: untyped) = discard
+{.pragma: fooBar4 fooBar3.}
+
+proc test1() {.fooBar#[!]#.} = discard
+
+var test2 {.fooBar#[!]#.} = 9
+
+type
+  Person {.fooBar#[!]#.} = object
+    hello {.fooBar#[!]#.}: string
+  Callback = proc () {.fooBar#[!]#.}
+
+# Check only macros/templates/pragmas are suggested
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix
+sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix
+sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix
+>sug $2
+sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix
+sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix
+sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix
+>sug $3
+sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix
+sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix
+sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix
+>sug $4
+sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix
+sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix
+sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix
+>sug $5
+sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix
+sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix
+sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix
+"""
+
+