internal/lsp: organize imports as a quickfix

This change adds the ability to organize all imports as quickfix on a
diagnostic, in addition to the standard "source.organizeImports" code
action kind. This change still requires a bit of work, since really, we
should only add one import per diagnostic and each edit should be the
edits necessary for the addition or removal of the individual import,
but this is a good start.

Change-Id: I57679446bec833d215c35533240102fb61c86f20
Reviewed-on: https://go-review.googlesource.com/c/tools/+/172397
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
Rebecca Stambler 2019-04-16 12:50:59 -04:00
Родитель 52f869c107
Коммит b8fc0e1722
1 изменённых файлов: 37 добавлений и 19 удалений

Просмотреть файл

@ -28,12 +28,29 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
var codeActions []protocol.CodeAction var codeActions []protocol.CodeAction
// Determine what code actions we should take based on the diagnostics. // Determine what code actions we should take based on the diagnostics.
if findImportErrors(params.Context.Diagnostics) { if findImportErrors(params.Context.Diagnostics) {
codeAction, err := organizeImports(ctx, view, spn) edits, err := organizeImports(ctx, view, spn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if codeAction != nil { if len(edits) > 0 {
codeActions = append(codeActions, *codeAction) // TODO(rstambler): Handle params.Context.Only when VSCode-Go uses a
// version of vscode-languageclient that fixes
// https://github.com/Microsoft/vscode-languageserver-node/issues/442.
codeActions = append(codeActions, protocol.CodeAction{
Title: "Organize Imports",
Kind: protocol.SourceOrganizeImports,
Edit: &protocol.WorkspaceEdit{
Changes: &map[string][]protocol.TextEdit{
string(spn.URI()): edits,
},
},
})
// Add any quick fixes for each import-related diagnostic that we see.
fixes, err := quickFixes(spn.URI(), params.Context.Diagnostics, edits)
if err != nil {
return nil, err
}
codeActions = append(codeActions, fixes...)
} }
} }
return codeActions, nil return codeActions, nil
@ -60,7 +77,7 @@ func findImportErrors(diagnostics []protocol.Diagnostic) bool {
return false return false
} }
func organizeImports(ctx context.Context, v source.View, s span.Span) (*protocol.CodeAction, error) { func organizeImports(ctx context.Context, v source.View, s span.Span) ([]protocol.TextEdit, error) {
f, m, err := newColumnMap(ctx, v, s.URI()) f, m, err := newColumnMap(ctx, v, s.URI())
if err != nil { if err != nil {
return nil, err return nil, err
@ -81,21 +98,22 @@ func organizeImports(ctx context.Context, v source.View, s span.Span) (*protocol
if err != nil { if err != nil {
return nil, err return nil, err
} }
protocolEdits, err := ToProtocolEdits(m, edits) return ToProtocolEdits(m, edits)
if err != nil { }
return nil, err
} // TODO(rstambler): Separate this into a set of codeActions per diagnostic,
if len(protocolEdits) == 0 { // where each action is the addition or removal of one import.
return nil, nil // This can only be done when https://golang.org/issue/31493 is resolved.
} func quickFixes(uri span.URI, diagnostics []protocol.Diagnostic, edits []protocol.TextEdit) ([]protocol.CodeAction, error) {
codeAction := protocol.CodeAction{ return []protocol.CodeAction{
Title: "Organize Imports", {
Kind: protocol.SourceOrganizeImports, Title: "Organize All Imports",
Edit: &protocol.WorkspaceEdit{ Kind: protocol.QuickFix,
Changes: &map[string][]protocol.TextEdit{ Edit: &protocol.WorkspaceEdit{
string(s.URI()): protocolEdits, Changes: &map[string][]protocol.TextEdit{
string(uri): edits,
},
}, },
}, },
} }, nil
return &codeAction, nil
} }