mirror of https://github.com/golang/go.git
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:
parent
a44cc76dc1
commit
871637b647
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 -->
|
||||
|
|
@ -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*
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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}",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue