diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go index daf9091741..7bb5cb9c9c 100644 --- a/internal/lsp/cmd/cmd.go +++ b/internal/lsp/cmd/cmd.go @@ -293,6 +293,15 @@ func newConnection(app *Application) *connection { } } +// fileURI converts a DocumentURI to a file:// span.URI, panicking if it's not a file. +func fileURI(uri protocol.DocumentURI) span.URI { + sURI := uri.SpanURI() + if !sURI.IsFile() { + panic(fmt.Sprintf("%q is not a file URI", uri)) + } + return sURI +} + func (c *cmdClient) ShowMessage(ctx context.Context, p *protocol.ShowMessageParams) error { return nil } func (c *cmdClient) ShowMessageRequest(ctx context.Context, p *protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error) { @@ -373,7 +382,7 @@ func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishD c.filesMu.Lock() defer c.filesMu.Unlock() - file := c.getFile(ctx, p.URI.SpanURI()) + file := c.getFile(ctx, fileURI(p.URI)) file.diagnostics = p.Diagnostics return nil } diff --git a/internal/lsp/cmd/definition.go b/internal/lsp/cmd/definition.go index 6a9f2b5458..2b2e3c00cb 100644 --- a/internal/lsp/cmd/definition.go +++ b/internal/lsp/cmd/definition.go @@ -109,7 +109,7 @@ func (d *definition) Run(ctx context.Context, args ...string) error { if hover == nil { return errors.Errorf("%v: not an identifier", from) } - file = conn.AddFile(ctx, locs[0].URI.SpanURI()) + file = conn.AddFile(ctx, fileURI(locs[0].URI)) if file.err != nil { return errors.Errorf("%v: %v", from, file.err) } diff --git a/internal/lsp/cmd/implementation.go b/internal/lsp/cmd/implementation.go index 91c4d590f4..e498372143 100644 --- a/internal/lsp/cmd/implementation.go +++ b/internal/lsp/cmd/implementation.go @@ -72,7 +72,7 @@ func (i *implementation) Run(ctx context.Context, args ...string) error { var spans []string for _, impl := range implementations { - f := conn.AddFile(ctx, impl.URI.SpanURI()) + f := conn.AddFile(ctx, fileURI(impl.URI)) span, err := f.mapper.Span(impl) if err != nil { return err diff --git a/internal/lsp/cmd/imports.go b/internal/lsp/cmd/imports.go index 407509b875..a6d00e9f0d 100644 --- a/internal/lsp/cmd/imports.go +++ b/internal/lsp/cmd/imports.go @@ -74,7 +74,7 @@ func (t *imports) Run(ctx context.Context, args ...string) error { continue } for _, c := range a.Edit.DocumentChanges { - if c.TextDocument.URI.SpanURI() == uri { + if fileURI(c.TextDocument.URI) == uri { edits = append(edits, c.Edits...) } } diff --git a/internal/lsp/cmd/references.go b/internal/lsp/cmd/references.go index 573348d4bb..562601906f 100644 --- a/internal/lsp/cmd/references.go +++ b/internal/lsp/cmd/references.go @@ -73,7 +73,7 @@ func (r *references) Run(ctx context.Context, args ...string) error { } var spans []string for _, l := range locations { - f := conn.AddFile(ctx, l.URI.SpanURI()) + f := conn.AddFile(ctx, fileURI(l.URI)) // convert location to span for user-friendly 1-indexed line // and column numbers span, err := f.mapper.Span(l) diff --git a/internal/lsp/cmd/rename.go b/internal/lsp/cmd/rename.go index 33121aac57..57cf84663f 100644 --- a/internal/lsp/cmd/rename.go +++ b/internal/lsp/cmd/rename.go @@ -81,7 +81,7 @@ func (r *rename) Run(ctx context.Context, args ...string) error { var orderedURIs []string edits := map[span.URI][]protocol.TextEdit{} for _, c := range edit.DocumentChanges { - uri := c.TextDocument.URI.SpanURI() + uri := fileURI(c.TextDocument.URI) edits[uri] = append(edits[uri], c.Edits...) orderedURIs = append(orderedURIs, string(uri)) } diff --git a/internal/lsp/cmd/suggested_fix.go b/internal/lsp/cmd/suggested_fix.go index b92cb257a1..5e8b1fa32d 100644 --- a/internal/lsp/cmd/suggested_fix.go +++ b/internal/lsp/cmd/suggested_fix.go @@ -87,7 +87,7 @@ func (s *suggestedfix) Run(ctx context.Context, args ...string) error { continue } for _, c := range a.Edit.DocumentChanges { - if c.TextDocument.URI.SpanURI() == uri { + if fileURI(c.TextDocument.URI) == uri { edits = append(edits, c.Edits...) } } diff --git a/internal/lsp/code_action.go b/internal/lsp/code_action.go index ea2274a994..c9f85fd067 100644 --- a/internal/lsp/code_action.go +++ b/internal/lsp/code_action.go @@ -20,19 +20,14 @@ import ( ) func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { - return nil, err - } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.UnknownKind) + if !ok { return nil, err } + uri := fh.Identity().URI // Determine the supported actions for this file kind. - supportedCodeActions, ok := view.Options().SupportedCodeActions[fh.Identity().Kind] + supportedCodeActions, ok := snapshot.View().Options().SupportedCodeActions[fh.Identity().Kind] if !ok { return nil, fmt.Errorf("no supported code actions for %v file kind", fh.Identity().Kind) } diff --git a/internal/lsp/command.go b/internal/lsp/command.go index a5bccfcb22..a7907e67f2 100644 --- a/internal/lsp/command.go +++ b/internal/lsp/command.go @@ -5,7 +5,6 @@ import ( "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" errors "golang.org/x/xerrors" ) @@ -15,36 +14,27 @@ func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCom if len(params.Arguments) == 0 || len(params.Arguments) > 1 { return nil, errors.Errorf("expected one file URI for call to `go mod tidy`, got %v", params.Arguments) } - // Confirm that this action is being taken on a go.mod file. - uri := span.URIFromURI(params.Arguments[0].(string)) - view, err := s.session.ViewOf(uri) - if err != nil { + uri := protocol.DocumentURI(params.Arguments[0].(string)) + snapshot, _, ok, err := s.beginFileRequest(uri, source.Mod) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Mod { - return nil, errors.Errorf("%s is not a mod file", uri) - } // Run go.mod tidy on the view. - if _, err := source.InvokeGo(ctx, view.Folder().Filename(), snapshot.Config(ctx).Env, "mod", "tidy"); err != nil { + if _, err := source.InvokeGo(ctx, snapshot.View().Folder().Filename(), snapshot.Config(ctx).Env, "mod", "tidy"); err != nil { return nil, err } case "upgrade.dependency": if len(params.Arguments) < 2 { return nil, errors.Errorf("expected one file URI and one dependency for call to `go get`, got %v", params.Arguments) } - uri := span.URIFromURI(params.Arguments[0].(string)) - view, err := s.session.ViewOf(uri) - if err != nil { + uri := protocol.DocumentURI(params.Arguments[0].(string)) + snapshot, _, ok, err := s.beginFileRequest(uri, source.UnknownKind) + if !ok { return nil, err } dep := params.Arguments[1].(string) // Run "go get" on the dependency to upgrade it to the latest version. - if _, err := source.InvokeGo(ctx, view.Folder().Filename(), view.Snapshot().Config(ctx).Env, "get", dep); err != nil { + if _, err := source.InvokeGo(ctx, snapshot.View().Folder().Filename(), snapshot.Config(ctx).Env, "get", dep); err != nil { return nil, err } } diff --git a/internal/lsp/completion.go b/internal/lsp/completion.go index a4306831d1..ea6af87ced 100644 --- a/internal/lsp/completion.go +++ b/internal/lsp/completion.go @@ -16,14 +16,8 @@ import ( ) func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { - return nil, err - } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.UnknownKind) + if !ok { return nil, err } var candidates []source.CompletionItem @@ -51,7 +45,7 @@ func (s *Server) completion(ctx context.Context, params *protocol.CompletionPara // When using deep completions/fuzzy matching, report results as incomplete so // client fetches updated completions after every key stroke. - options := view.Options() + options := snapshot.View().Options() incompleteResults := options.DeepCompletion || options.Matcher == source.Fuzzy items := toProtocolCompletionItems(candidates, rng, options) diff --git a/internal/lsp/definition.go b/internal/lsp/definition.go index 60087280a3..440a481e06 100644 --- a/internal/lsp/definition.go +++ b/internal/lsp/definition.go @@ -12,19 +12,10 @@ import ( ) func (s *Server) definition(ctx context.Context, params *protocol.DefinitionParams) ([]protocol.Location, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Go { - return nil, nil - } ident, err := source.Identifier(ctx, snapshot, fh, params.Position) if err != nil { return nil, err @@ -42,19 +33,10 @@ func (s *Server) definition(ctx context.Context, params *protocol.DefinitionPara } func (s *Server) typeDefinition(ctx context.Context, params *protocol.TypeDefinitionParams) ([]protocol.Location, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Go { - return nil, nil - } ident, err := source.Identifier(ctx, snapshot, fh, params.Position) if err != nil { return nil, err diff --git a/internal/lsp/folding_range.go b/internal/lsp/folding_range.go index 69c9f68948..5bae8f5afa 100644 --- a/internal/lsp/folding_range.go +++ b/internal/lsp/folding_range.go @@ -8,24 +8,12 @@ import ( ) func (s *Server) foldingRange(ctx context.Context, params *protocol.FoldingRangeParams) ([]protocol.FoldingRange, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - var ranges []*source.FoldingRangeInfo - switch fh.Identity().Kind { - case source.Go: - ranges, err = source.FoldingRange(ctx, snapshot, fh, view.Options().LineFoldingOnly) - case source.Mod: - ranges = nil - } + ranges, err := source.FoldingRange(ctx, snapshot, fh, snapshot.View().Options().LineFoldingOnly) if err != nil { return nil, err } diff --git a/internal/lsp/format.go b/internal/lsp/format.go index 1f70ba7219..33dd4072a7 100644 --- a/internal/lsp/format.go +++ b/internal/lsp/format.go @@ -12,24 +12,11 @@ import ( ) func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - var edits []protocol.TextEdit - switch fh.Identity().Kind { - case source.Go: - edits, err = source.Format(ctx, snapshot, fh) - case source.Mod: - return nil, nil - } - + edits, err := source.Format(ctx, snapshot, fh) if err != nil { return nil, err } diff --git a/internal/lsp/general.go b/internal/lsp/general.go index c476d56c00..d82057679d 100644 --- a/internal/lsp/general.go +++ b/internal/lsp/general.go @@ -234,6 +234,32 @@ func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI, return nil } +// beginFileRequest checks preconditions for a file-oriented request and routes +// it to a snapshot. +// We don't want to return errors for benign conditions like wrong file type, +// so callers should do if !ok { return err } rather than if err != nil. +func (s *Server) beginFileRequest(pURI protocol.DocumentURI, expectKind source.FileKind) (source.Snapshot, source.FileHandle, bool, error) { + uri := pURI.SpanURI() + if !uri.IsFile() { + // Not a file URI. Stop processing the request, but don't return an error. + return nil, nil, false, nil + } + view, err := s.session.ViewOf(uri) + if err != nil { + return nil, nil, false, err + } + snapshot := view.Snapshot() + fh, err := snapshot.GetFile(uri) + if err != nil { + return nil, nil, false, err + } + if expectKind != source.UnknownKind && fh.Identity().Kind != expectKind { + // Wrong kind of file. Nothing to do. + return nil, nil, false, nil + } + return snapshot, fh, true, nil +} + func (s *Server) shutdown(ctx context.Context) error { s.stateMu.Lock() defer s.stateMu.Unlock() diff --git a/internal/lsp/highlight.go b/internal/lsp/highlight.go index c2f50712a9..7386ddcd8a 100644 --- a/internal/lsp/highlight.go +++ b/internal/lsp/highlight.go @@ -14,26 +14,13 @@ import ( ) func (s *Server) documentHighlight(ctx context.Context, params *protocol.DocumentHighlightParams) ([]protocol.DocumentHighlight, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) + rngs, err := source.Highlight(ctx, snapshot, fh, params.Position) if err != nil { - return nil, err - } - var rngs []protocol.Range - switch fh.Identity().Kind { - case source.Go: - rngs, err = source.Highlight(ctx, snapshot, fh, params.Position) - case source.Mod: - return nil, nil - } - - if err != nil { - log.Error(ctx, "no highlight", err, telemetry.URI.Of(uri)) + log.Error(ctx, "no highlight", err, telemetry.URI.Of(params.TextDocument.URI)) } return toProtocolHighlight(rngs), nil } diff --git a/internal/lsp/hover.go b/internal/lsp/hover.go index 4ec04a5ddf..842c72fa5a 100644 --- a/internal/lsp/hover.go +++ b/internal/lsp/hover.go @@ -12,19 +12,10 @@ import ( ) func (s *Server) hover(ctx context.Context, params *protocol.HoverParams) (*protocol.Hover, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Go { - return nil, nil - } ident, err := source.Identifier(ctx, snapshot, fh, params.Position) if err != nil { return nil, nil @@ -37,13 +28,13 @@ func (s *Server) hover(ctx context.Context, params *protocol.HoverParams) (*prot if err != nil { return nil, err } - hover, err := source.FormatHover(h, view.Options()) + hover, err := source.FormatHover(h, snapshot.View().Options()) if err != nil { return nil, err } return &protocol.Hover{ Contents: protocol.MarkupContent{ - Kind: view.Options().PreferredContentFormat, + Kind: snapshot.View().Options().PreferredContentFormat, Value: hover, }, Range: rng, diff --git a/internal/lsp/implementation.go b/internal/lsp/implementation.go index 4fb0219952..e4b3650914 100644 --- a/internal/lsp/implementation.go +++ b/internal/lsp/implementation.go @@ -12,18 +12,9 @@ import ( ) func (s *Server) implementation(ctx context.Context, params *protocol.ImplementationParams) ([]protocol.Location, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Go { - return nil, nil - } return source.Implementation(ctx, snapshot, fh, params.Position) } diff --git a/internal/lsp/link.go b/internal/lsp/link.go index c457d7eb05..fcde27ba7f 100644 --- a/internal/lsp/link.go +++ b/internal/lsp/link.go @@ -21,19 +21,12 @@ import ( ) func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { - return nil, err - } - fh, err := view.Snapshot().GetFile(uri) - if err != nil { - return nil, err - } // TODO(golang/go#36501): Support document links for go.mod files. - if fh.Identity().Kind == source.Mod { - return nil, nil + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { + return nil, err } + view := snapshot.View() file, _, m, _, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx) if err != nil { return nil, err diff --git a/internal/lsp/references.go b/internal/lsp/references.go index 068cfa628e..57e92c09da 100644 --- a/internal/lsp/references.go +++ b/internal/lsp/references.go @@ -12,22 +12,11 @@ import ( ) func (s *Server) references(ctx context.Context, params *protocol.ReferenceParams) ([]protocol.Location, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - // Find all references to the identifier at the position. - if fh.Identity().Kind != source.Go { - return nil, nil - } - - references, err := source.References(ctx, view.Snapshot(), fh, params.Position, params.Context.IncludeDeclaration) + references, err := source.References(ctx, snapshot, fh, params.Position, params.Context.IncludeDeclaration) if err != nil { return nil, err } diff --git a/internal/lsp/rename.go b/internal/lsp/rename.go index 4043b14174..9fe59e9097 100644 --- a/internal/lsp/rename.go +++ b/internal/lsp/rename.go @@ -12,20 +12,10 @@ import ( ) func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Go { - return nil, nil - } - edits, err := source.Rename(ctx, snapshot, fh, params.Position, params.NewName) if err != nil { return nil, err @@ -45,20 +35,10 @@ func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*pr } func (s *Server) prepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.Range, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Go { - return nil, nil - } - // Do not return errors here, as it adds clutter. // Returning a nil result means there is not a valid rename. item, err := source.PrepareRename(ctx, snapshot, fh, params.Position) diff --git a/internal/lsp/server.go b/internal/lsp/server.go index f4ba6b6533..dca4d65273 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -95,17 +95,17 @@ func (s *Server) nonstandardRequest(ctx context.Context, method string, params i paramMap := params.(map[string]interface{}) if method == "gopls/diagnoseFiles" { for _, file := range paramMap["files"].([]interface{}) { - uri := span.URIFromURI(file.(string)) - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(protocol.DocumentURI(file.(string)), source.UnknownKind) + if !ok { return nil, err } - fileID, diagnostics, err := source.FileDiagnostics(ctx, view.Snapshot(), uri) + + fileID, diagnostics, err := source.FileDiagnostics(ctx, snapshot, fh.Identity().URI) if err != nil { return nil, err } if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{ - URI: protocol.URIFromSpanURI(uri), + URI: protocol.URIFromSpanURI(fh.Identity().URI), Diagnostics: toProtocolDiagnostics(diagnostics), Version: fileID.Version, }); err != nil { diff --git a/internal/lsp/signature_help.go b/internal/lsp/signature_help.go index c514d58075..a978fd862a 100644 --- a/internal/lsp/signature_help.go +++ b/internal/lsp/signature_help.go @@ -14,19 +14,10 @@ import ( ) func (s *Server) signatureHelp(ctx context.Context, params *protocol.SignatureHelpParams) (*protocol.SignatureHelp, error) { - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { return nil, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) - if err != nil { - return nil, err - } - if fh.Identity().Kind != source.Go { - return nil, nil - } info, activeParameter, err := source.SignatureHelp(ctx, snapshot, fh, params.Position) if err != nil { log.Print(ctx, "no signature help", tag.Of("At", params.Position), tag.Of("Failure", err)) diff --git a/internal/lsp/symbols.go b/internal/lsp/symbols.go index b0d93718eb..b9f0b75de3 100644 --- a/internal/lsp/symbols.go +++ b/internal/lsp/symbols.go @@ -18,26 +18,13 @@ func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSy ctx, done := trace.StartSpan(ctx, "lsp.Server.documentSymbol") defer done() - uri := params.TextDocument.URI.SpanURI() - view, err := s.session.ViewOf(uri) - if err != nil { - return nil, err + snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.Go) + if !ok { + return []protocol.DocumentSymbol{}, err } - snapshot := view.Snapshot() - fh, err := snapshot.GetFile(uri) + symbols, err := source.DocumentSymbols(ctx, snapshot, fh) if err != nil { - return nil, err - } - var symbols []protocol.DocumentSymbol - switch fh.Identity().Kind { - case source.Go: - symbols, err = source.DocumentSymbols(ctx, snapshot, fh) - case source.Mod: - return []protocol.DocumentSymbol{}, nil - } - - if err != nil { - log.Error(ctx, "DocumentSymbols failed", err, telemetry.URI.Of(uri)) + log.Error(ctx, "DocumentSymbols failed", err, telemetry.URI.Of(fh.Identity().URI)) return []protocol.DocumentSymbol{}, nil } return symbols, nil diff --git a/internal/lsp/text_synchronization.go b/internal/lsp/text_synchronization.go index e4db204ddc..cb05419c97 100644 --- a/internal/lsp/text_synchronization.go +++ b/internal/lsp/text_synchronization.go @@ -17,9 +17,14 @@ import ( ) func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error { + uri := params.TextDocument.URI.SpanURI() + if !uri.IsFile() { + return nil + } + _, err := s.didModifyFiles(ctx, []source.FileModification{ { - URI: params.TextDocument.URI.SpanURI(), + URI: uri, Action: source.Open, Version: params.TextDocument.Version, Text: []byte(params.TextDocument.Text), @@ -31,6 +36,10 @@ func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocume func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error { uri := params.TextDocument.URI.SpanURI() + if !uri.IsFile() { + return nil + } + text, err := s.changedText(ctx, uri, params.ContentChanges) if err != nil { return err @@ -65,8 +74,12 @@ func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDo func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.DidChangeWatchedFilesParams) error { var modifications []source.FileModification for _, change := range params.Changes { + uri := change.URI.SpanURI() + if !uri.IsFile() { + continue + } modifications = append(modifications, source.FileModification{ - URI: change.URI.SpanURI(), + URI: uri, Action: changeTypeToFileAction(change.Type), OnDisk: true, }) @@ -76,8 +89,13 @@ func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.Did } func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) error { + uri := params.TextDocument.URI.SpanURI() + if !uri.IsFile() { + return nil + } + c := source.FileModification{ - URI: params.TextDocument.URI.SpanURI(), + URI: uri, Action: source.Save, Version: params.TextDocument.Version, } @@ -89,9 +107,14 @@ func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocume } func (s *Server) didClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error { + uri := params.TextDocument.URI.SpanURI() + if !uri.IsFile() { + return nil + } + _, err := s.didModifyFiles(ctx, []source.FileModification{ { - URI: params.TextDocument.URI.SpanURI(), + URI: uri, Action: source.Close, Version: -1, Text: nil, diff --git a/internal/span/uri.go b/internal/span/uri.go index a794a2d06b..f8487b9e9b 100644 --- a/internal/span/uri.go +++ b/internal/span/uri.go @@ -20,6 +20,10 @@ const fileScheme = "file" // URI represents the full URI for a file. type URI string +func (uri URI) IsFile() bool { + return strings.HasPrefix(string(uri), "file://") +} + // Filename returns the file path for the given URI. // It is an error to call this on a URI that is not a valid filename. func (uri URI) Filename() string {