diff options
author | Nikolay Nikolov <nickysn@gmail.com> | 2023-11-04 09:51:09 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-04 08:51:09 +0100 |
commit | 3f2b9c8bcf9faf30b6844e5222ffe6ec501064e8 (patch) | |
tree | 2a2633cfe9de1e8262ee9f9b251a13e7110c8ed7 /compiler | |
parent | 95e5ad6927af309552857686bf2c74bfac36cbb7 (diff) | |
download | Nim-3f2b9c8bcf9faf30b6844e5222ffe6ec501064e8.tar.gz |
Inlay hints support (#22896)
This adds inlay hints support to nimsuggest. It adds a new command to nimsuggest, called 'inlayHints'. Currently, it provides type information to 'var' and 'let' variables. In the future, inlay hints can also be added for 'const' and for function parameters. The protocol also reserves space for a tooltip field, which is not used, yet, but support for it can be added in the future, without further changing the protocol. The change includes refactoring to allow the 'inlayHints' command to return a completely different structure, compared to the other nimsuggest commands. This will allow other future commands to have custom return types as well. All the previous commands return the same structure as before, so perfect backwards compatibility is maintained. To use this feature, an update to the nim language server, as well as the VS code extension is needed. Related PRs: nimlangserver: https://github.com/nim-lang/langserver/pull/53 VS code extension: https://github.com/saem/vscode-nim/pull/134 --------- Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 1 | ||||
-rw-r--r-- | compiler/modulegraphs.nim | 1 | ||||
-rw-r--r-- | compiler/options.nim | 18 | ||||
-rw-r--r-- | compiler/semstmts.nim | 4 | ||||
-rw-r--r-- | compiler/suggest.nim | 114 |
5 files changed, 96 insertions, 42 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 5ee9afa02..661a82703 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -903,6 +903,7 @@ type info*: TLineInfo when defined(nimsuggest): endInfo*: TLineInfo + hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints owner*: PSym flags*: TSymFlags ast*: PNode # syntax tree of proc, iterator, etc.: diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index ba636eb5a..5c23325e8 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -57,6 +57,7 @@ type SymInfoPair* = object sym*: PSym info*: TLineInfo + isDecl*: bool PipelinePass* = enum NonePass diff --git a/compiler/options.nim b/compiler/options.nim index f2d93a9b3..704248d78 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -199,7 +199,7 @@ type IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod, ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols, - ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand + ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints Feature* = enum ## experimental features; DO NOT RENAME THESE! dotOperators, @@ -288,9 +288,24 @@ type version*: int endLine*: uint16 endCol*: int + inlayHintInfo*: SuggestInlayHint Suggestions* = seq[Suggest] + SuggestInlayHintKind* = enum + sihkType = "Type", + sihkParameter = "Parameter" + + SuggestInlayHint* = ref object + kind*: SuggestInlayHintKind + line*: int # Starts at 1 + column*: int # Starts at 0 + label*: string + paddingLeft*: bool + paddingRight*: bool + allowInsert*: bool + tooltip*: string + ProfileInfo* = object time*: float count*: int @@ -1071,6 +1086,7 @@ proc `$`*(c: IdeCmd): string = of ideRecompile: "recompile" of ideChanged: "changed" of ideType: "type" + of ideInlayHints: "inlayHints" proc floatInt64Align*(conf: ConfigRef): int16 = ## Returns either 4 or 8 depending on reasons. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a4de874ba..0196b9d03 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -672,9 +672,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, b) continue + var hasUserSpecifiedType = false var typ: PType = nil if a[^2].kind != nkEmpty: typ = semTypeNode(c, a[^2], nil) + hasUserSpecifiedType = true var typFlags: TTypeAllowedFlags = {} @@ -746,6 +748,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, n, a) continue var v = semIdentDef(c, a[j], symkind, false) + when defined(nimsuggest): + v.hasUserSpecifiedType = hasUserSpecifiedType styleCheckDef(c, v) onDef(a[j].info, v) if sfGenSym notin v.flags: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 5714c6d21..1d84fada5 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -107,7 +107,7 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int result = 0 elif ident[0] in linter.Letters and ident[^1] != '=': result = identLen(line, column) - if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0: + if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0: result = 0 else: var sourceIdent: string = "" @@ -177,7 +177,7 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info result.filePath = toFullPath(g.config, infox) result.line = toLinenumber(infox) result.column = toColumn(infox) - result.tokenLen = if section != ideHighlight: + result.tokenLen = if section notin {ideHighlight, ideInlayHints}: s.name.s.len else: getTokenLenFromSource(g.config, s.name.s, infox) @@ -185,50 +185,82 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info result.endLine = endLine result.endCol = endCol -proc `$`*(suggest: Suggest): string = - result = $suggest.section +proc `$`*(suggest: SuggestInlayHint): string = + result = $suggest.kind result.add(sep) - if suggest.section == ideHighlight: - if suggest.symkind.TSymKind == skVar and suggest.isGlobal: - result.add("skGlobalVar") - elif suggest.symkind.TSymKind == skLet and suggest.isGlobal: - result.add("skGlobalLet") - else: - result.add($suggest.symkind.TSymKind) - result.add(sep) - result.add($suggest.line) - result.add(sep) - result.add($suggest.column) - result.add(sep) - result.add($suggest.tokenLen) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + result.add(suggest.label) + result.add(sep) + result.add($suggest.paddingLeft) + result.add(sep) + result.add($suggest.paddingRight) + result.add(sep) + result.add($suggest.allowInsert) + result.add(sep) + result.add(suggest.tooltip) + +proc `$`*(suggest: Suggest): string = + if suggest.section == ideInlayHints: + result = $suggest.inlayHintInfo else: - result.add($suggest.symkind.TSymKind) - result.add(sep) - if suggest.qualifiedPath.len != 0: - result.add(suggest.qualifiedPath.join(".")) - result.add(sep) - result.add(suggest.forth) - result.add(sep) - result.add(suggest.filePath) + result = $suggest.section result.add(sep) - result.add($suggest.line) - result.add(sep) - result.add($suggest.column) - result.add(sep) - when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): - result.add(suggest.doc.escape) - if suggest.version == 0 or suggest.version == 3: + if suggest.section == ideHighlight: + if suggest.symkind.TSymKind == skVar and suggest.isGlobal: + result.add("skGlobalVar") + elif suggest.symkind.TSymKind == skLet and suggest.isGlobal: + result.add("skGlobalLet") + else: + result.add($suggest.symkind.TSymKind) + result.add(sep) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + result.add($suggest.tokenLen) + else: + result.add($suggest.symkind.TSymKind) result.add(sep) - result.add($suggest.quality) - if suggest.section == ideSug: + if suggest.qualifiedPath.len != 0: + result.add(suggest.qualifiedPath.join(".")) + result.add(sep) + result.add(suggest.forth) + result.add(sep) + result.add(suggest.filePath) + result.add(sep) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): + result.add(suggest.doc.escape) + if suggest.version == 0 or suggest.version == 3: result.add(sep) - result.add($suggest.prefix) + result.add($suggest.quality) + if suggest.section == ideSug: + result.add(sep) + result.add($suggest.prefix) - if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}): - result.add(sep) - result.add($suggest.endLine) - result.add(sep) - result.add($suggest.endCol) + if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}): + result.add(sep) + result.add($suggest.endLine) + result.add(sep) + result.add($suggest.endCol) + +proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint = + SuggestInlayHint( + kind: sihkType, + line: sug.line, + column: sug.column + sug.tokenLen, + label: ": " & sug.forth, + paddingLeft: false, + paddingRight: false, + allowInsert: true, + tooltip: "" + ) proc suggestResult*(conf: ConfigRef; s: Suggest) = if not isNil(conf.suggestionResultHook): @@ -537,7 +569,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i ## misnamed: should be 'symDeclared' let conf = g.config when defined(nimsuggest): - g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info) + g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info, isDecl: isDecl) if conf.suggestVersion == 0: if s.allUsages.len == 0: |