internal/lsp: add settings for inlay hints and enable

This change adds user settings for enabling inlay hints, modeled
roughly after analyzers. This will allow users to turn on specific
inlay hints that they like and leave others off.

With all of the inlay hints turned off by default, we can now enable
inlay hints.

Change-Id: Ie5dfcbbab1e0b7312eafcc4aa08cb4fe8a83fc31
Reviewed-on: https://go-review.googlesource.com/c/tools/+/411906
Run-TryBot: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Suzy Mueller 2022-06-13 19:25:46 -04:00
parent a44cc76dc1
commit 871637b647
9 changed files with 410 additions and 49 deletions

View File

@ -63,6 +63,9 @@ func doMain(baseDir string, write bool) (bool, error) {
if ok, err := rewriteFile(filepath.Join(baseDir, "gopls/doc/analyzers.md"), api, write, rewriteAnalyzers); !ok || err != nil {
return ok, err
}
if ok, err := rewriteFile(filepath.Join(baseDir, "gopls/doc/inlayHints.md"), api, write, rewriteInlayHints); !ok || err != nil {
return ok, err
}
return true, nil
}
@ -102,6 +105,7 @@ func loadAPI() (*source.APIJSON, error) {
} {
api.Analyzers = append(api.Analyzers, loadAnalyzers(m)...)
}
api.Hints = loadHints(source.AllInlayHints)
for _, category := range []reflect.Value{
reflect.ValueOf(defaults.UserOptions),
} {
@ -146,6 +150,14 @@ func loadAPI() (*source.APIJSON, error) {
Default: def,
})
}
case "hints":
for _, a := range api.Hints {
opt.EnumKeys.Keys = append(opt.EnumKeys.Keys, source.EnumKey{
Name: fmt.Sprintf("%q", a.Name),
Doc: a.Doc,
Default: strconv.FormatBool(a.Default),
})
}
}
}
}
@ -488,6 +500,23 @@ func loadAnalyzers(m map[string]*source.Analyzer) []*source.AnalyzerJSON {
return json
}
func loadHints(m map[string]*source.Hint) []*source.HintJSON {
var sorted []string
for _, h := range m {
sorted = append(sorted, h.Name)
}
sort.Strings(sorted)
var json []*source.HintJSON
for _, name := range sorted {
h := m[name]
json = append(json, &source.HintJSON{
Name: h.Name,
Doc: h.Doc,
})
}
return json
}
func lowerFirst(x string) string {
if x == "" {
return x
@ -699,6 +728,21 @@ func rewriteAnalyzers(doc []byte, api *source.APIJSON) ([]byte, error) {
return replaceSection(doc, "Analyzers", section.Bytes())
}
func rewriteInlayHints(doc []byte, api *source.APIJSON) ([]byte, error) {
section := bytes.NewBuffer(nil)
for _, hint := range api.Hints {
fmt.Fprintf(section, "## **%v**\n\n", hint.Name)
fmt.Fprintf(section, "%s\n\n", hint.Doc)
switch hint.Default {
case true:
fmt.Fprintf(section, "**Enabled by default.**\n\n")
case false:
fmt.Fprintf(section, "**Disabled by default. Enable it by setting `\"hints\": {\"%s\": true}`.**\n\n", hint.Name)
}
}
return replaceSection(doc, "Hints", section.Bytes())
}
func replaceSection(doc []byte, sectionName string, replacement []byte) ([]byte, error) {
re := regexp.MustCompile(fmt.Sprintf(`(?s)<!-- BEGIN %v.* -->\n(.*?)<!-- END %v.* -->`, sectionName, sectionName))
idx := re.FindSubmatchIndex(doc)

73
gopls/doc/inlayHints.md Normal file
View File

@ -0,0 +1,73 @@
# Hints
This document describes the inlay hints that `gopls` uses inside the editor.
<!-- BEGIN Hints: DO NOT MANUALLY EDIT THIS SECTION -->
## **assign_variable_types**
Enable/disable inlay hints for variable types in assign statements:
i/* int/*, j/* int/* := 0, len(r)-1
**Disabled by default. Enable it by setting `"hints": {"assign_variable_types": true}`.**
## **composite_literal_fields**
Enable/disable inlay hints for composite literal field names:
{in: "Hello, world", want: "dlrow ,olleH"}
**Disabled by default. Enable it by setting `"hints": {"composite_literal_fields": true}`.**
## **composite_literal_types**
Enable/disable inlay hints for composite literal types:
for _, c := range []struct {
in, want string
}{
/*struct{ in string; want string }*/{"Hello, world", "dlrow ,olleH"},
}
**Disabled by default. Enable it by setting `"hints": {"composite_literal_types": true}`.**
## **constant_values**
Enable/disable inlay hints for constant values:
const (
KindNone Kind = iota/* = 0*/
KindPrint/* = 1*/
KindPrintf/* = 2*/
KindErrorf/* = 3*/
)
**Disabled by default. Enable it by setting `"hints": {"constant_values": true}`.**
## **function_type_parameters**
Enable/disable inlay hints for implicit type parameters on generic functions:
myFoo/*[int, string]*/(1, "hello")
**Disabled by default. Enable it by setting `"hints": {"function_type_parameters": true}`.**
## **parameter_names**
Enable/disable inlay hints for parameter names:
parseInt(/* str: */ "123", /* radix: */ 8)
**Disabled by default. Enable it by setting `"hints": {"parameter_names": true}`.**
## **range_variable_types**
Enable/disable inlay hints for variable types in range statements:
for k/* int*/, v/* string/* := range []string{} {
fmt.Println(k, v)
}
**Disabled by default. Enable it by setting `"hints": {"range_variable_types": true}`.**
<!-- END Hints: DO NOT MANUALLY EDIT THIS SECTION -->

View File

@ -35,6 +35,7 @@ still be able to independently override specific experimental features.
* [Completion](#completion)
* [Diagnostic](#diagnostic)
* [Documentation](#documentation)
* [Inlayhint](#inlayhint)
* [Navigation](#navigation)
### Build
@ -370,6 +371,18 @@ linksInHover toggles the presence of links to documentation in hover.
Default: `true`.
#### Inlayhint
##### **hints** *map[string]bool*
**This setting is experimental and may be deleted.**
hints specify inlay hints that users want to see.
A full list of hints that gopls uses can be found
[here](https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md).
Default: `{}`.
#### Navigation
##### **importShortcut** *enum*

View File

@ -153,6 +153,7 @@ See https://github.com/golang/go/issues/45732 for more information.`,
HoverProvider: true,
DocumentHighlightProvider: true,
DocumentLinkProvider: protocol.DocumentLinkOptions{},
InlayHintProvider: protocol.InlayHintOptions{},
ReferencesProvider: true,
RenameProvider: renameOpts,
SignatureHelpProvider: protocol.SignatureHelpOptions{

View File

@ -67,6 +67,9 @@ func testLSP(t *testing.T, datum *tests.Data) {
tests.EnableAllAnalyzers(view, options)
view.SetOptions(ctx, options)
// Enable all inlay hints for tests.
tests.EnableAllInlayHints(view, options)
// Only run the -modfile specific tests in module mode with Go 1.14 or above.
datum.ModfileFlagAvailable = len(snapshot.ModFiles()) > 0 && testenv.Go1Point() >= 14
release()

View File

@ -505,6 +505,51 @@ var GeneratedAPIJSON = &APIJSON{
Status: "experimental",
Hierarchy: "ui.diagnostic",
},
{
Name: "hints",
Type: "map[string]bool",
Doc: "hints specify inlay hints that users want to see.\nA full list of hints that gopls uses can be found\n[here](https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md).\n",
EnumKeys: EnumKeys{Keys: []EnumKey{
{
Name: "\"assign_variable_types\"",
Doc: "Enable/disable inlay hints for variable types in assign statements:\n\n\ti/* int/*, j/* int/* := 0, len(r)-1",
Default: "false",
},
{
Name: "\"composite_literal_fields\"",
Doc: "Enable/disable inlay hints for composite literal field names:\n\n\t{in: \"Hello, world\", want: \"dlrow ,olleH\"}",
Default: "false",
},
{
Name: "\"composite_literal_types\"",
Doc: "Enable/disable inlay hints for composite literal types:\n\n\tfor _, c := range []struct {\n\t\tin, want string\n\t}{\n\t\t/*struct{ in string; want string }*/{\"Hello, world\", \"dlrow ,olleH\"},\n\t}",
Default: "false",
},
{
Name: "\"constant_values\"",
Doc: "Enable/disable inlay hints for constant values:\n\n\tconst (\n\t\tKindNone Kind = iota/* = 0*/\n\t\tKindPrint/* = 1*/\n\t\tKindPrintf/* = 2*/\n\t\tKindErrorf/* = 3*/\n\t)",
Default: "false",
},
{
Name: "\"function_type_parameters\"",
Doc: "Enable/disable inlay hints for implicit type parameters on generic functions:\n\n\tmyFoo/*[int, string]*/(1, \"hello\")",
Default: "false",
},
{
Name: "\"parameter_names\"",
Doc: "Enable/disable inlay hints for parameter names:\n\n\tparseInt(/* str: */ \"123\", /* radix: */ 8)",
Default: "false",
},
{
Name: "\"range_variable_types\"",
Doc: "Enable/disable inlay hints for variable types in range statements:\n\n\tfor k/* int*/, v/* string/* := range []string{} {\n\t\tfmt.Println(k, v)\n\t}",
Default: "false",
},
}},
Default: "{}",
Status: "experimental",
Hierarchy: "ui.inlayhint",
},
{
Name: "codelenses",
Type: "map[string]bool",
@ -979,4 +1024,34 @@ var GeneratedAPIJSON = &APIJSON{
Default: true,
},
},
Hints: []*HintJSON{
{
Name: "assign_variable_types",
Doc: "Enable/disable inlay hints for variable types in assign statements:\n\n\ti/* int/*, j/* int/* := 0, len(r)-1",
},
{
Name: "composite_literal_fields",
Doc: "Enable/disable inlay hints for composite literal field names:\n\n\t{in: \"Hello, world\", want: \"dlrow ,olleH\"}",
},
{
Name: "composite_literal_types",
Doc: "Enable/disable inlay hints for composite literal types:\n\n\tfor _, c := range []struct {\n\t\tin, want string\n\t}{\n\t\t/*struct{ in string; want string }*/{\"Hello, world\", \"dlrow ,olleH\"},\n\t}",
},
{
Name: "constant_values",
Doc: "Enable/disable inlay hints for constant values:\n\n\tconst (\n\t\tKindNone Kind = iota/* = 0*/\n\t\tKindPrint/* = 1*/\n\t\tKindPrintf/* = 2*/\n\t\tKindErrorf/* = 3*/\n\t)",
},
{
Name: "function_type_parameters",
Doc: "Enable/disable inlay hints for implicit type parameters on generic functions:\n\n\tmyFoo/*[int, string]*/(1, \"hello\")",
},
{
Name: "parameter_names",
Doc: "Enable/disable inlay hints for parameter names:\n\n\tparseInt(/* str: */ \"123\", /* radix: */ 8)",
},
{
Name: "range_variable_types",
Doc: "Enable/disable inlay hints for variable types in range statements:\n\n\tfor k/* int*/, v/* string/* := range []string{} {\n\t\tfmt.Println(k, v)\n\t}",
},
},
}

View File

@ -23,6 +23,87 @@ const (
maxLabelLength = 28
)
type InlayHintFunc func(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint
type Hint struct {
Name string
Doc string
Run InlayHintFunc
}
const (
ParameterNames = "parameter_names"
AssignVariableTypes = "assign_variable_types"
ConstantValues = "constant_values"
RangeVariableTypes = "range_variable_types"
CompositeLiteralTypes = "composite_literal_types"
CompositeLiteralFieldNames = "composite_literal_fields"
FunctionTypeParameters = "function_type_parameters"
)
var AllInlayHints = map[string]*Hint{
AssignVariableTypes: {
Name: AssignVariableTypes,
Doc: `Enable/disable inlay hints for variable types in assign statements:
i/* int/*, j/* int/* := 0, len(r)-1`,
Run: assignVariableTypes,
},
ParameterNames: {
Name: ParameterNames,
Doc: `Enable/disable inlay hints for parameter names:
parseInt(/* str: */ "123", /* radix: */ 8)`,
Run: parameterNames,
},
ConstantValues: {
Name: ConstantValues,
Doc: `Enable/disable inlay hints for constant values:
const (
KindNone Kind = iota/* = 0*/
KindPrint/* = 1*/
KindPrintf/* = 2*/
KindErrorf/* = 3*/
)`,
Run: constantValues,
},
RangeVariableTypes: {
Name: RangeVariableTypes,
Doc: `Enable/disable inlay hints for variable types in range statements:
for k/* int*/, v/* string/* := range []string{} {
fmt.Println(k, v)
}`,
Run: rangeVariableTypes,
},
CompositeLiteralTypes: {
Name: CompositeLiteralTypes,
Doc: `Enable/disable inlay hints for composite literal types:
for _, c := range []struct {
in, want string
}{
/*struct{ in string; want string }*/{"Hello, world", "dlrow ,olleH"},
}`,
Run: compositeLiteralTypes,
},
CompositeLiteralFieldNames: {
Name: CompositeLiteralFieldNames,
Doc: `Enable/disable inlay hints for composite literal field names:
{in: "Hello, world", want: "dlrow ,olleH"}`,
Run: compositeLiteralFields,
},
FunctionTypeParameters: {
Name: FunctionTypeParameters,
Doc: `Enable/disable inlay hints for implicit type parameters on generic functions:
myFoo/*[int, string]*/(1, "hello")`,
Run: funcTypeParams,
},
}
func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol.Range) ([]protocol.InlayHint, error) {
ctx, done := event.Start(ctx, "source.InlayHint")
defer done()
@ -32,38 +113,47 @@ func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol
return nil, fmt.Errorf("getting file for InlayHint: %w", err)
}
// Collect a list of the inlay hints that are enabled.
inlayHintOptions := snapshot.View().Options().InlayHintOptions
var enabledHints []InlayHintFunc
for hint, enabled := range inlayHintOptions.Hints {
if !enabled {
continue
}
if h, ok := AllInlayHints[hint]; ok {
enabledHints = append(enabledHints, h.Run)
}
}
if len(enabledHints) == 0 {
return nil, nil
}
tmap := lsppos.NewTokenMapper(pgf.Src, pgf.Tok)
info := pkg.GetTypesInfo()
q := Qualifier(pgf.File, pkg.GetTypes(), info)
var hints []protocol.InlayHint
ast.Inspect(pgf.File, func(node ast.Node) bool {
switch n := node.(type) {
case *ast.CallExpr:
hints = append(hints, parameterNames(n, tmap, info)...)
hints = append(hints, funcTypeParams(n, tmap, info)...)
case *ast.AssignStmt:
hints = append(hints, assignVariableTypes(n, tmap, info, &q)...)
case *ast.RangeStmt:
hints = append(hints, rangeVariableTypes(n, tmap, info, &q)...)
case *ast.GenDecl:
hints = append(hints, constantValues(n, tmap, info)...)
case *ast.CompositeLit:
hints = append(hints, compositeLiterals(n, tmap, info, &q)...)
for _, fn := range enabledHints {
hints = append(hints, fn(node, tmap, info, &q)...)
}
return true
})
return hints, nil
}
func parameterNames(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
signature, ok := info.TypeOf(node.Fun).(*types.Signature)
func parameterNames(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, _ *types.Qualifier) []protocol.InlayHint {
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return nil
}
signature, ok := info.TypeOf(callExpr.Fun).(*types.Signature)
if !ok {
return nil
}
var hints []protocol.InlayHint
for i, v := range node.Args {
for i, v := range callExpr.Args {
start, ok := tmap.Position(v.Pos())
if !ok {
continue
@ -92,8 +182,12 @@ func parameterNames(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.In
return hints
}
func funcTypeParams(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
id, ok := node.Fun.(*ast.Ident)
func funcTypeParams(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, _ *types.Qualifier) []protocol.InlayHint {
ce, ok := node.(*ast.CallExpr)
if !ok {
return nil
}
id, ok := ce.Fun.(*ast.Ident)
if !ok {
return nil
}
@ -119,12 +213,14 @@ func funcTypeParams(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.In
}}
}
func assignVariableTypes(node *ast.AssignStmt, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
if node.Tok != token.DEFINE {
func assignVariableTypes(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
stmt, ok := node.(*ast.AssignStmt)
if !ok || stmt.Tok != token.DEFINE {
return nil
}
var hints []protocol.InlayHint
for _, v := range node.Lhs {
for _, v := range stmt.Lhs {
if h := variableType(v, tmap, info, q); h != nil {
hints = append(hints, *h)
}
@ -132,12 +228,16 @@ func assignVariableTypes(node *ast.AssignStmt, tmap *lsppos.TokenMapper, info *t
return hints
}
func rangeVariableTypes(node *ast.RangeStmt, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
func rangeVariableTypes(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
rStmt, ok := node.(*ast.RangeStmt)
if !ok {
return nil
}
var hints []protocol.InlayHint
if h := variableType(node.Key, tmap, info, q); h != nil {
if h := variableType(rStmt.Key, tmap, info, q); h != nil {
hints = append(hints, *h)
}
if h := variableType(node.Value, tmap, info, q); h != nil {
if h := variableType(rStmt.Value, tmap, info, q); h != nil {
hints = append(hints, *h)
}
return hints
@ -160,13 +260,14 @@ func variableType(e ast.Expr, tmap *lsppos.TokenMapper, info *types.Info, q *typ
}
}
func constantValues(node *ast.GenDecl, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
if node.Tok != token.CONST {
func constantValues(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, _ *types.Qualifier) []protocol.InlayHint {
genDecl, ok := node.(*ast.GenDecl)
if !ok || genDecl.Tok != token.CONST {
return nil
}
var hints []protocol.InlayHint
for _, v := range node.Specs {
for _, v := range genDecl.Specs {
spec, ok := v.(*ast.ValueSpec)
if !ok {
continue
@ -210,36 +311,26 @@ func constantValues(node *ast.GenDecl, tmap *lsppos.TokenMapper, info *types.Inf
return hints
}
func compositeLiterals(node *ast.CompositeLit, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
typ := info.TypeOf(node)
func compositeLiteralFields(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
compLit, ok := node.(*ast.CompositeLit)
if !ok {
return nil
}
typ := info.TypeOf(compLit)
if typ == nil {
return nil
}
prefix := ""
if t, ok := typ.(*types.Pointer); ok {
typ = t.Elem()
prefix = "&"
}
strct, ok := typ.Underlying().(*types.Struct)
if !ok {
return nil
}
var hints []protocol.InlayHint
if node.Type == nil {
// The type for this struct is implicit, add an inlay hint.
if start, ok := tmap.Position(node.Lbrace); ok {
hints = append(hints, protocol.InlayHint{
Position: &start,
Label: buildLabel(fmt.Sprintf("%s%s", prefix, types.TypeString(typ, *q))),
Kind: protocol.Type,
})
}
}
for i, v := range node.Elts {
for i, v := range compLit.Elts {
if _, ok := v.(*ast.KeyValueExpr); !ok {
start, ok := tmap.Position(v.Pos())
if !ok {
@ -259,6 +350,35 @@ func compositeLiterals(node *ast.CompositeLit, tmap *lsppos.TokenMapper, info *t
return hints
}
func compositeLiteralTypes(node ast.Node, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
compLit, ok := node.(*ast.CompositeLit)
if !ok {
return nil
}
typ := info.TypeOf(compLit)
if typ == nil {
return nil
}
if compLit.Type != nil {
return nil
}
prefix := ""
if t, ok := typ.(*types.Pointer); ok {
typ = t.Elem()
prefix = "&"
}
// The type for this composite literal is implicit, add an inlay hint.
start, ok := tmap.Position(compLit.Lbrace)
if !ok {
return nil
}
return []protocol.InlayHint{{
Position: &start,
Label: buildLabel(fmt.Sprintf("%s%s", prefix, types.TypeString(typ, *q))),
Kind: protocol.Type,
}}
}
func buildLabel(s string) []protocol.InlayHintLabelPart {
label := protocol.InlayHintLabelPart{
Value: s,

View File

@ -130,6 +130,7 @@ func DefaultOptions() *Options {
Nil: true,
},
},
InlayHintOptions: InlayHintOptions{},
DocumentationOptions: DocumentationOptions{
HoverKind: FullDocumentation,
LinkTarget: "pkg.go.dev",
@ -289,6 +290,7 @@ type UIOptions struct {
CompletionOptions
NavigationOptions
DiagnosticOptions
InlayHintOptions
// Codelenses overrides the enabled/disabled state of code lenses. See the
// "Code Lenses" section of the
@ -407,6 +409,13 @@ type DiagnosticOptions struct {
ExperimentalWatchedFileDelay time.Duration `status:"experimental"`
}
type InlayHintOptions struct {
// Hints specify inlay hints that users want to see.
// A full list of hints that gopls uses can be found
// [here](https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md).
Hints map[string]bool `status:"experimental"`
}
type NavigationOptions struct {
// ImportShortcut specifies whether import statements should link to
// documentation or go to definitions.
@ -915,6 +924,9 @@ func (o *Options) set(name string, value interface{}, seen map[string]struct{})
case "analyses":
result.setBoolMap(&o.Analyses)
case "hints":
result.setBoolMap(&o.Hints)
case "annotations":
result.setAnnotationMap(&o.Annotations)
@ -1351,6 +1363,7 @@ type APIJSON struct {
Commands []*CommandJSON
Lenses []*LensJSON
Analyzers []*AnalyzerJSON
Hints []*HintJSON
}
type OptionJSON struct {
@ -1416,12 +1429,8 @@ func collectEnums(opt *OptionJSON) string {
}
func shouldShowEnumKeysInSettings(name string) bool {
// Both of these fields have too many possible options to print.
return !hardcodedEnumKeys(name)
}
func hardcodedEnumKeys(name string) bool {
return name == "analyses" || name == "codelenses"
// These fields have too many possible options to print.
return !(name == "analyses" || name == "codelenses" || name == "hints")
}
type EnumKeys struct {
@ -1489,3 +1498,17 @@ func (a *AnalyzerJSON) String() string {
func (a *AnalyzerJSON) Write(w io.Writer) {
fmt.Fprintf(w, "%s (%s): %v", a.Name, a.Doc, a.Default)
}
type HintJSON struct {
Name string
Doc string
Default bool
}
func (h *HintJSON) String() string {
return h.Name
}
func (h *HintJSON) Write(w io.Writer) {
fmt.Fprintf(w, "%s (%s): %v", h.Name, h.Doc, h.Default)
}

View File

@ -512,6 +512,15 @@ func EnableAllAnalyzers(view source.View, opts *source.Options) {
}
}
func EnableAllInlayHints(view source.View, opts *source.Options) {
if opts.Hints == nil {
opts.Hints = make(map[string]bool)
}
for name := range source.AllInlayHints {
opts.Hints[name] = true
}
}
func WorkspaceSymbolsString(ctx context.Context, data *Data, queryURI span.URI, symbols []protocol.SymbolInformation) (string, error) {
queryDir := filepath.Dir(queryURI.Filename())
var filtered []string