Skip to content

Commit 7d5dac2

Browse files
committed
internal/lsp: added a code action which generates key-value pairs of individual
fields and default values between a struct's enclosing braces Fixes #37576
1 parent 9ee5ef7 commit 7d5dac2

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

internal/lsp/code_action.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
134134
})
135135
}
136136
}
137+
fillActions, err := source.StructFill(ctx, params, snapshot, fh)
138+
if err != nil {
139+
return nil, err
140+
}
141+
codeActions = append(codeActions, fillActions...)
137142
default:
138143
// Unsupported file kind for a code action.
139144
return nil, nil

internal/lsp/source/fill_struct.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package source
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"go/types"
11+
12+
"golang.org/x/tools/go/ast/astutil"
13+
"golang.org/x/tools/internal/lsp/protocol"
14+
)
15+
16+
func StructFill(ctx context.Context, params *protocol.CodeActionParams, snapshot Snapshot, fh FileHandle) ([]protocol.CodeAction, error) {
17+
rangeOfTarget := params.Range
18+
19+
pkg, pgh, err := getParsedFile(ctx, snapshot, fh, NarrowestPackageHandle)
20+
if err != nil {
21+
return nil, fmt.Errorf("getting file for Completion: %v", err)
22+
}
23+
file, _, m, _, err := pgh.Cached()
24+
if err != nil {
25+
return nil, err
26+
}
27+
spn, err := m.PointSpan(rangeOfTarget.Start)
28+
if err != nil {
29+
return nil, err
30+
}
31+
rng, err := spn.Range(m.Converter)
32+
if err != nil {
33+
return nil, err
34+
}
35+
path, _ := astutil.PathEnclosingInterval(file, rng.Start, rng.End)
36+
if path == nil {
37+
return nil, nil
38+
}
39+
40+
ecl := enclosingCompositeLiteral(path, rng.Start, pkg.GetTypesInfo())
41+
if ecl == nil || !ecl.isStruct() {
42+
return nil, nil
43+
}
44+
45+
// If in F{ Bar<> : V} or anywhere in F{Bar : V, ...}
46+
// we should not fill the struct.
47+
if ecl.inKey || len(ecl.cl.Elts) != 0 {
48+
return nil, nil
49+
}
50+
51+
// the range to replace all text between enclosing braces {<> ... <>}
52+
newMappedRange := newMappedRange(snapshot.View().Session().Cache().FileSet(), m, ecl.cl.Lbrace+1, ecl.cl.Rbrace)
53+
newProtoRange, err := newMappedRange.Range()
54+
if err != nil {
55+
return nil, err
56+
}
57+
var codeActions []protocol.CodeAction
58+
qfFunc := qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo())
59+
switch obj := ecl.clType.(type) {
60+
case *types.Struct:
61+
62+
fieldCount := obj.NumFields()
63+
if fieldCount == 0 {
64+
return nil, nil
65+
}
66+
var edit string
67+
for i := 0; i < fieldCount; i++ {
68+
field := obj.Field(i)
69+
// Ignore fields that are not accessible in the current package.
70+
if field.Pkg() != nil && field.Pkg() != pkg.GetTypes() && !field.Exported() {
71+
continue
72+
}
73+
74+
label := field.Name()
75+
value := formatZeroValue(field.Type(), qfFunc)
76+
text := "\n" + label + " : " + value + ","
77+
edit += text
78+
}
79+
edit += "\n"
80+
81+
codeActions = append(codeActions, protocol.CodeAction{
82+
Title: "Fill struct",
83+
Kind: protocol.RefactorRewrite,
84+
Edit: protocol.WorkspaceEdit{
85+
DocumentChanges: []protocol.TextDocumentEdit{
86+
{
87+
TextDocument: protocol.VersionedTextDocumentIdentifier{
88+
Version: fh.Identity().Version,
89+
TextDocumentIdentifier: protocol.TextDocumentIdentifier{
90+
URI: protocol.URIFromSpanURI(fh.Identity().URI),
91+
},
92+
},
93+
Edits: []protocol.TextEdit{
94+
{
95+
Range: newProtoRange,
96+
NewText: edit,
97+
},
98+
},
99+
},
100+
},
101+
},
102+
})
103+
}
104+
105+
return codeActions, nil
106+
}

internal/lsp/source/options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func DefaultOptions() Options {
6969
protocol.SourceFixAll: true,
7070
protocol.SourceOrganizeImports: true,
7171
protocol.QuickFix: true,
72+
protocol.RefactorRewrite: true,
7273
},
7374
Mod: {
7475
protocol.SourceOrganizeImports: true,

0 commit comments

Comments
 (0)