internal/lsp: new options to disable certain kinds of semantic tokens
Semantic tokens, as defined by the LSP, have no way of marking parts of
strings or numbers, for instance, to emphasize escape character. But
if gopls returns no semantic tokens for strings, then the editor
will use its coloring for strings, which may be more useful (and
similarly for components of numbers).
This change introduces boolean flags noSemanticString and
noSemanticNumber that can be set to true to suppress the semantic
token and let the editor's formatting shine through.
Fixes: Fixes golang/go#45753
Change-Id: Ibae880a08fb9a67daa73aa172375a1c949431e11
Reviewed-on: https://go-review.googlesource.com/c/tools/+/421256
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Peter Weinberger <pjw@google.com>
diff --git a/internal/lsp/semantic.go b/internal/lsp/semantic.go
index f0c4a11..648d5c4 100644
--- a/internal/lsp/semantic.go
+++ b/internal/lsp/semantic.go
@@ -107,14 +107,16 @@
return nil, err
}
e := &encoded{
- ctx: ctx,
- pgf: pgf,
- rng: rng,
- ti: pkg.GetTypesInfo(),
- pkg: pkg,
- fset: snapshot.FileSet(),
- tokTypes: s.session.Options().SemanticTypes,
- tokMods: s.session.Options().SemanticMods,
+ ctx: ctx,
+ pgf: pgf,
+ rng: rng,
+ ti: pkg.GetTypesInfo(),
+ pkg: pkg,
+ fset: snapshot.FileSet(),
+ tokTypes: s.session.Options().SemanticTypes,
+ tokMods: s.session.Options().SemanticMods,
+ noStrings: vv.Options().NoSemanticString,
+ noNumbers: vv.Options().NoSemanticNumber,
}
if err := e.init(); err != nil {
// e.init should never return an error, unless there's some
@@ -223,6 +225,9 @@
// the generated data
items []semItem
+ noStrings bool
+ noNumbers bool
+
ctx context.Context
tokTypes, tokMods []string
pgf *source.ParsedGoFile
@@ -827,29 +832,36 @@
var j int
var last semItem
for i := 0; i < len(e.items); i++ {
- typ, ok := typeMap[e.items[i].typeStr]
+ item := e.items[i]
+ typ, ok := typeMap[item.typeStr]
if !ok {
continue // client doesn't want typeStr
}
+ if item.typeStr == tokString && e.noStrings {
+ continue
+ }
+ if item.typeStr == tokNumber && e.noNumbers {
+ continue
+ }
if j == 0 {
x[0] = e.items[0].line
} else {
- x[j] = e.items[i].line - last.line
+ x[j] = item.line - last.line
}
- x[j+1] = e.items[i].start
+ x[j+1] = item.start
if j > 0 && x[j] == 0 {
- x[j+1] = e.items[i].start - last.start
+ x[j+1] = item.start - last.start
}
- x[j+2] = e.items[i].len
+ x[j+2] = item.len
x[j+3] = uint32(typ)
mask := 0
- for _, s := range e.items[i].mods {
+ for _, s := range item.mods {
// modMap[s] is 0 if the client doesn't want this modifier
mask |= modMap[s]
}
x[j+4] = uint32(mask)
j += 5
- last = e.items[i]
+ last = item
}
return x[:j]
}
diff --git a/internal/lsp/source/api_json.go b/internal/lsp/source/api_json.go
index a613006..41f66d7 100755
--- a/internal/lsp/source/api_json.go
+++ b/internal/lsp/source/api_json.go
@@ -616,6 +616,22 @@
Hierarchy: "ui",
},
{
+ Name: "noSemanticString",
+ Type: "bool",
+ Doc: "noSemanticString turns off the sending of the semantic token 'string'\n",
+ Default: "false",
+ Status: "experimental",
+ Hierarchy: "ui",
+ },
+ {
+ Name: "noSemanticNumber",
+ Type: "bool",
+ Doc: "noSemanticNumber turns off the sending of the semantic token 'number'\n",
+ Default: "false",
+ Status: "experimental",
+ Hierarchy: "ui",
+ },
+ {
Name: "local",
Type: "string",
Doc: "local is the equivalent of the `goimports -local` flag, which puts\nimports beginning with this string after third-party packages. It should\nbe the prefix of the import path whose imports should be grouped\nseparately.\n",
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 971fa06..9073586 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -317,6 +317,12 @@
// SemanticTokens controls whether the LSP server will send
// semantic tokens to the client.
SemanticTokens bool `status:"experimental"`
+
+ // NoSemanticString turns off the sending of the semantic token 'string'
+ NoSemanticString bool `status:"experimental"`
+
+ // NoSemanticNumber turns off the sending of the semantic token 'number'
+ NoSemanticNumber bool `status:"experimental"`
}
type CompletionOptions struct {
@@ -1033,6 +1039,12 @@
case "semanticTokens":
result.setBool(&o.SemanticTokens)
+ case "noSemanticString":
+ result.setBool(&o.NoSemanticString)
+
+ case "noSemanticNumber":
+ result.setBool(&o.NoSemanticNumber)
+
case "expandWorkspaceToModule":
result.setBool(&o.ExpandWorkspaceToModule)