internal/lsp: run source.organizeImports on all codeActions
This change addresses the additional information we received in https://github.com/Microsoft/language-server-protocol/issues/726. Fixes golang/go#31359 Change-Id: Ied7c97ac1f9e429e28cc44563b93acabd80921a3 Reviewed-on: https://go-review.googlesource.com/c/tools/+/172406 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
e2848a0e7d
commit
dd61c98fae
|
@ -26,57 +26,42 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var codeActions []protocol.CodeAction
|
var codeActions []protocol.CodeAction
|
||||||
// Determine what code actions we should take based on the diagnostics.
|
// TODO(rstambler): Handle params.Context.Only when VSCode-Go uses a
|
||||||
if findImportErrors(params.Context.Diagnostics) {
|
// version of vscode-languageclient that fixes
|
||||||
edits, err := organizeImports(ctx, view, spn)
|
// https://github.com/Microsoft/vscode-languageserver-node/issues/442.
|
||||||
if err != nil {
|
edits, err := organizeImports(ctx, view, spn)
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
if len(edits) > 0 {
|
}
|
||||||
// TODO(rstambler): Handle params.Context.Only when VSCode-Go uses a
|
if len(edits) > 0 {
|
||||||
// version of vscode-languageclient that fixes
|
codeActions = append(codeActions, protocol.CodeAction{
|
||||||
// https://github.com/Microsoft/vscode-languageserver-node/issues/442.
|
Title: "Organize Imports",
|
||||||
|
Kind: protocol.SourceOrganizeImports,
|
||||||
|
Edit: &protocol.WorkspaceEdit{
|
||||||
|
Changes: &map[string][]protocol.TextEdit{
|
||||||
|
string(spn.URI()): edits,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// If we also have diagnostics, we can associate them with quick fixes.
|
||||||
|
if findImportErrors(params.Context.Diagnostics) {
|
||||||
|
// TODO(rstambler): Separate this into a set of codeActions per diagnostic,
|
||||||
|
// where each action is the addition or removal of one import.
|
||||||
|
// This can only be done when https://golang.org/issue/31493 is resolved.
|
||||||
codeActions = append(codeActions, protocol.CodeAction{
|
codeActions = append(codeActions, protocol.CodeAction{
|
||||||
Title: "Organize Imports",
|
Title: "Organize All Imports", // clarify that all imports will change
|
||||||
Kind: protocol.SourceOrganizeImports,
|
Kind: protocol.QuickFix,
|
||||||
Edit: &protocol.WorkspaceEdit{
|
Edit: &protocol.WorkspaceEdit{
|
||||||
Changes: &map[string][]protocol.TextEdit{
|
Changes: &map[string][]protocol.TextEdit{
|
||||||
string(spn.URI()): edits,
|
string(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
|
||||||
}
|
}
|
||||||
|
|
||||||
// findImports determines if a given diagnostic represents an error that could
|
|
||||||
// be fixed by organizing imports.
|
|
||||||
// TODO(rstambler): We need a better way to check this than string matching.
|
|
||||||
func findImportErrors(diagnostics []protocol.Diagnostic) bool {
|
|
||||||
for _, diagnostic := range diagnostics {
|
|
||||||
// "undeclared name: X" may be an unresolved import.
|
|
||||||
if strings.HasPrefix(diagnostic.Message, "undeclared name: ") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// "could not import: X" may be an invalid import.
|
|
||||||
if strings.HasPrefix(diagnostic.Message, "could not import: ") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// "X imported but not used" is an unused import.
|
|
||||||
if strings.HasSuffix(diagnostic.Message, " imported but not used") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func organizeImports(ctx context.Context, v source.View, s span.Span) ([]protocol.TextEdit, 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 {
|
||||||
|
@ -101,19 +86,23 @@ func organizeImports(ctx context.Context, v source.View, s span.Span) ([]protoco
|
||||||
return ToProtocolEdits(m, edits)
|
return ToProtocolEdits(m, edits)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rstambler): Separate this into a set of codeActions per diagnostic,
|
// findImports determines if a given diagnostic represents an error that could
|
||||||
// where each action is the addition or removal of one import.
|
// be fixed by organizing imports.
|
||||||
// This can only be done when https://golang.org/issue/31493 is resolved.
|
// TODO(rstambler): We need a better way to check this than string matching.
|
||||||
func quickFixes(uri span.URI, diagnostics []protocol.Diagnostic, edits []protocol.TextEdit) ([]protocol.CodeAction, error) {
|
func findImportErrors(diagnostics []protocol.Diagnostic) bool {
|
||||||
return []protocol.CodeAction{
|
for _, diagnostic := range diagnostics {
|
||||||
{
|
// "undeclared name: X" may be an unresolved import.
|
||||||
Title: "Organize All Imports",
|
if strings.HasPrefix(diagnostic.Message, "undeclared name: ") {
|
||||||
Kind: protocol.QuickFix,
|
return true
|
||||||
Edit: &protocol.WorkspaceEdit{
|
}
|
||||||
Changes: &map[string][]protocol.TextEdit{
|
// "could not import: X" may be an invalid import.
|
||||||
string(uri): edits,
|
if strings.HasPrefix(diagnostic.Message, "could not import: ") {
|
||||||
},
|
return true
|
||||||
},
|
}
|
||||||
},
|
// "X imported but not used" is an unused import.
|
||||||
}, nil
|
if strings.HasSuffix(diagnostic.Message, " imported but not used") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue