1
0
mirror of https://github.com/golang/go synced 2024-09-30 14:18:32 -06:00

internal/span,lsp: disambiguate URIs, DocumentURIs, and paths

Create a real type for protocol.DocumentURIs. Remove span.NewURI in
favor of path/URI-specific constructors. Remove span.Parse's ability to
parse URI-based spans, which appears to be totally unused.

As a consequence, we no longer mangle non-file URIs to start with
file://, and crash all over the place when one is opened.

Updates golang/go#33699.

Change-Id: Ic7347c9768e38002b4ad9c84471329d0af7d2e05
Reviewed-on: https://go-review.googlesource.com/c/tools/+/219482
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Heschi Kreinick 2020-02-12 16:36:46 -05:00
parent 548b770e2d
commit f7b8cc7bd0
60 changed files with 218 additions and 191 deletions

View File

@ -68,7 +68,7 @@ func main() {
log.Printf("new %d, hist:%s", len(newMsgs), seen.Histogram) log.Printf("new %d, hist:%s", len(newMsgs), seen.Histogram)
ok := make(map[string]int) ok := make(map[string]int)
f := func(x []*parse.Logmsg, label string, diags map[string][]p.Diagnostic) { f := func(x []*parse.Logmsg, label string, diags map[p.DocumentURI][]p.Diagnostic) {
counts := make(map[parse.MsgType]int) counts := make(map[parse.MsgType]int)
for _, l := range x { for _, l := range x {
if l.Method == "window/logMessage" { if l.Method == "window/logMessage" {
@ -102,9 +102,9 @@ func main() {
} }
log.Printf("%s: %s", label, msg) log.Printf("%s: %s", label, msg)
} }
mdiags := make(map[string][]p.Diagnostic) mdiags := make(map[p.DocumentURI][]p.Diagnostic)
f(msgs, "old", mdiags) f(msgs, "old", mdiags)
vdiags := make(map[string][]p.Diagnostic) vdiags := make(map[p.DocumentURI][]p.Diagnostic)
f(newMsgs, "new", vdiags) f(newMsgs, "new", vdiags)
buf := []string{} buf := []string{}
for k := range ok { for k := range ok {

View File

@ -177,7 +177,7 @@ func toSourceErrorKind(kind packages.ErrorKind) source.ErrorKind {
func typeErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, pos token.Pos) (span.Span, error) { func typeErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, pos token.Pos) (span.Span, error) {
posn := fset.Position(pos) posn := fset.Position(pos)
ph, _, err := source.FindFileInPackage(pkg, span.FileURI(posn.Filename)) ph, _, err := source.FindFileInPackage(pkg, span.URIFromPath(posn.Filename))
if err != nil { if err != nil {
return span.Span{}, err return span.Span{}, err
} }
@ -213,7 +213,7 @@ func typeErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, pos toke
} }
func scannerErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, posn token.Position) (span.Span, error) { func scannerErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, posn token.Position) (span.Span, error) {
ph, _, err := source.FindFileInPackage(pkg, span.FileURI(posn.Filename)) ph, _, err := source.FindFileInPackage(pkg, span.URIFromPath(posn.Filename))
if err != nil { if err != nil {
return span.Span{}, err return span.Span{}, err
} }

View File

@ -147,12 +147,12 @@ func (s *snapshot) setMetadata(ctx context.Context, pkgPath packagePath, pkg *pa
} }
for _, filename := range pkg.CompiledGoFiles { for _, filename := range pkg.CompiledGoFiles {
uri := span.FileURI(filename) uri := span.URIFromPath(filename)
m.compiledGoFiles = append(m.compiledGoFiles, uri) m.compiledGoFiles = append(m.compiledGoFiles, uri)
s.addID(uri, m.id) s.addID(uri, m.id)
} }
for _, filename := range pkg.GoFiles { for _, filename := range pkg.GoFiles {
uri := span.FileURI(filename) uri := span.URIFromPath(filename)
m.goFiles = append(m.goFiles, uri) m.goFiles = append(m.goFiles, uri)
s.addID(uri, m.id) s.addID(uri, m.id)
} }

View File

@ -236,7 +236,7 @@ func (v *view) buildBuiltinPackage(ctx context.Context, goFiles []string) error
if len(goFiles) != 1 { if len(goFiles) != 1 {
return errors.Errorf("only expected 1 file, got %v", len(goFiles)) return errors.Errorf("only expected 1 file, got %v", len(goFiles))
} }
uri := span.FileURI(goFiles[0]) uri := span.URIFromPath(goFiles[0])
v.addIgnoredFile(uri) // to avoid showing diagnostics for builtin.go v.addIgnoredFile(uri) // to avoid showing diagnostics for builtin.go
// Get the FileHandle through the cache to avoid adding it to the snapshot // Get the FileHandle through the cache to avoid adding it to the snapshot
@ -585,7 +585,7 @@ func (v *view) setBuildInformation(ctx context.Context, folder span.URI, env []s
if modFile == os.DevNull { if modFile == os.DevNull {
return nil return nil
} }
v.realMod = span.FileURI(modFile) v.realMod = span.URIFromPath(modFile)
// Now that we have set all required fields, // Now that we have set all required fields,
// check if the view has a valid build configuration. // check if the view has a valid build configuration.
@ -618,7 +618,7 @@ func (v *view) setBuildInformation(ctx context.Context, folder span.URI, env []s
if _, err := io.Copy(tempModFile, origFile); err != nil { if _, err := io.Copy(tempModFile, origFile); err != nil {
return err return err
} }
v.tempMod = span.FileURI(tempModFile.Name()) v.tempMod = span.URIFromPath(tempModFile.Name())
// Copy go.sum file as well (if there is one). // Copy go.sum file as well (if there is one).
sumFile := filepath.Join(filepath.Dir(modFile), "go.sum") sumFile := filepath.Join(filepath.Dir(modFile), "go.sum")

View File

@ -10,7 +10,6 @@ import (
"golang.org/x/tools/internal/lsp" "golang.org/x/tools/internal/lsp"
"golang.org/x/tools/internal/lsp/cache" "golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/span"
errors "golang.org/x/xerrors" errors "golang.org/x/xerrors"
) )
@ -36,7 +35,7 @@ func TestCapabilities(t *testing.T) {
defer c.terminate(ctx) defer c.terminate(ctx)
params := &protocol.ParamInitialize{} params := &protocol.ParamInitialize{}
params.RootURI = string(span.FileURI(c.Client.app.wd)) params.RootURI = protocol.URIFromPath(c.Client.app.wd)
params.Capabilities.Workspace.Configuration = true params.Capabilities.Workspace.Configuration = true
// Send an initialize request to the server. // Send an initialize request to the server.
@ -55,7 +54,7 @@ func TestCapabilities(t *testing.T) {
} }
// Open the file on the server side. // Open the file on the server side.
uri := protocol.NewURI(span.FileURI(tmpFile)) uri := protocol.URIFromPath(tmpFile)
if err := c.Server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{ if err := c.Server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{
TextDocument: protocol.TextDocumentItem{ TextDocument: protocol.TextDocumentItem{
URI: uri, URI: uri,

View File

@ -48,7 +48,7 @@ func (c *check) Run(ctx context.Context, args ...string) error {
} }
defer conn.terminate(ctx) defer conn.terminate(ctx)
for _, arg := range args { for _, arg := range args {
uri := span.FileURI(arg) uri := span.URIFromPath(arg)
uris = append(uris, uri) uris = append(uris, uri)
file := conn.AddFile(ctx, uri) file := conn.AddFile(ctx, uri)
if file.err != nil { if file.err != nil {

View File

@ -237,7 +237,7 @@ func (app *Application) connectRemote(ctx context.Context, remote string) (*conn
func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error { func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error {
params := &protocol.ParamInitialize{} params := &protocol.ParamInitialize{}
params.RootURI = string(span.FileURI(c.Client.app.wd)) params.RootURI = protocol.URIFromPath(c.Client.app.wd)
params.Capabilities.Workspace.Configuration = true params.Capabilities.Workspace.Configuration = true
// Make sure to respect configured options when sending initialize request. // Make sure to respect configured options when sending initialize request.
@ -373,8 +373,7 @@ func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishD
c.filesMu.Lock() c.filesMu.Lock()
defer c.filesMu.Unlock() defer c.filesMu.Unlock()
uri := span.NewURI(p.URI) file := c.getFile(ctx, p.URI.SpanURI())
file := c.getFile(ctx, uri)
file.diagnostics = p.Diagnostics file.diagnostics = p.Diagnostics
return nil return nil
} }
@ -424,7 +423,7 @@ func (c *connection) AddFile(ctx context.Context, uri span.URI) *cmdFile {
file.added = true file.added = true
p := &protocol.DidOpenTextDocumentParams{ p := &protocol.DidOpenTextDocumentParams{
TextDocument: protocol.TextDocumentItem{ TextDocument: protocol.TextDocumentItem{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
LanguageID: source.DetectLanguage("", file.uri.Filename()).String(), LanguageID: source.DetectLanguage("", file.uri.Filename()).String(),
Version: 1, Version: 1,
Text: string(file.mapper.Content), Text: string(file.mapper.Content),

View File

@ -109,7 +109,7 @@ func (d *definition) Run(ctx context.Context, args ...string) error {
if hover == nil { if hover == nil {
return errors.Errorf("%v: not an identifier", from) return errors.Errorf("%v: not an identifier", from)
} }
file = conn.AddFile(ctx, span.NewURI(locs[0].URI)) file = conn.AddFile(ctx, locs[0].URI.SpanURI())
if file.err != nil { if file.err != nil {
return errors.Errorf("%v: %v", from, file.err) return errors.Errorf("%v: %v", from, file.err)
} }

View File

@ -50,7 +50,7 @@ func (r *foldingRanges) Run(ctx context.Context, args ...string) error {
p := protocol.FoldingRangeParams{ p := protocol.FoldingRangeParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(from.URI()), URI: protocol.URIFromSpanURI(from.URI()),
}, },
} }

View File

@ -72,7 +72,7 @@ func (i *implementation) Run(ctx context.Context, args ...string) error {
var spans []string var spans []string
for _, impl := range implementations { for _, impl := range implementations {
f := conn.AddFile(ctx, span.NewURI(impl.URI)) f := conn.AddFile(ctx, impl.URI.SpanURI())
span, err := f.mapper.Span(impl) span, err := f.mapper.Span(impl)
if err != nil { if err != nil {
return err return err

View File

@ -62,7 +62,7 @@ func (t *imports) Run(ctx context.Context, args ...string) error {
} }
actions, err := conn.CodeAction(ctx, &protocol.CodeActionParams{ actions, err := conn.CodeAction(ctx, &protocol.CodeActionParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
}) })
if err != nil { if err != nil {
@ -74,7 +74,7 @@ func (t *imports) Run(ctx context.Context, args ...string) error {
continue continue
} }
for _, c := range a.Edit.DocumentChanges { for _, c := range a.Edit.DocumentChanges {
if c.TextDocument.URI == string(uri) { if c.TextDocument.URI.SpanURI() == uri {
edits = append(edits, c.Edits...) edits = append(edits, c.Edits...)
} }
} }

View File

@ -59,7 +59,7 @@ func (l *links) Run(ctx context.Context, args ...string) error {
} }
results, err := conn.DocumentLink(ctx, &protocol.DocumentLinkParams{ results, err := conn.DocumentLink(ctx, &protocol.DocumentLinkParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
}) })
if err != nil { if err != nil {

View File

@ -73,7 +73,7 @@ func (r *references) Run(ctx context.Context, args ...string) error {
} }
var spans []string var spans []string
for _, l := range locations { for _, l := range locations {
f := conn.AddFile(ctx, span.NewURI(l.URI)) f := conn.AddFile(ctx, l.URI.SpanURI())
// convert location to span for user-friendly 1-indexed line // convert location to span for user-friendly 1-indexed line
// and column numbers // and column numbers
span, err := f.mapper.Span(l) span, err := f.mapper.Span(l)

View File

@ -81,15 +81,15 @@ func (r *rename) Run(ctx context.Context, args ...string) error {
var orderedURIs []string var orderedURIs []string
edits := map[span.URI][]protocol.TextEdit{} edits := map[span.URI][]protocol.TextEdit{}
for _, c := range edit.DocumentChanges { for _, c := range edit.DocumentChanges {
uri := span.NewURI(c.TextDocument.URI) uri := c.TextDocument.URI.SpanURI()
edits[uri] = append(edits[uri], c.Edits...) edits[uri] = append(edits[uri], c.Edits...)
orderedURIs = append(orderedURIs, c.TextDocument.URI) orderedURIs = append(orderedURIs, string(uri))
} }
sort.Strings(orderedURIs) sort.Strings(orderedURIs)
changeCount := len(orderedURIs) changeCount := len(orderedURIs)
for _, u := range orderedURIs { for _, u := range orderedURIs {
uri := span.NewURI(u) uri := span.URIFromURI(u)
cmdFile := conn.AddFile(ctx, uri) cmdFile := conn.AddFile(ctx, uri)
filename := cmdFile.uri.Filename() filename := cmdFile.uri.Filename()

View File

@ -59,7 +59,7 @@ func (r *signature) Run(ctx context.Context, args ...string) error {
tdpp := protocol.TextDocumentPositionParams{ tdpp := protocol.TextDocumentPositionParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(from.URI()), URI: protocol.URIFromSpanURI(from.URI()),
}, },
Position: loc.Range.Start, Position: loc.Range.Start,
} }

View File

@ -70,7 +70,7 @@ func (s *suggestedfix) Run(ctx context.Context, args ...string) error {
p := protocol.CodeActionParams{ p := protocol.CodeActionParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
Context: protocol.CodeActionContext{ Context: protocol.CodeActionContext{
Only: []protocol.CodeActionKind{protocol.QuickFix}, Only: []protocol.CodeActionKind{protocol.QuickFix},
@ -87,7 +87,7 @@ func (s *suggestedfix) Run(ctx context.Context, args ...string) error {
continue continue
} }
for _, c := range a.Edit.DocumentChanges { for _, c := range a.Edit.DocumentChanges {
if c.TextDocument.URI == string(uri) { if c.TextDocument.URI.SpanURI() == uri {
edits = append(edits, c.Edits...) edits = append(edits, c.Edits...)
} }
} }

View File

@ -44,7 +44,7 @@ func (r *symbols) Run(ctx context.Context, args ...string) error {
from := span.Parse(args[0]) from := span.Parse(args[0])
p := protocol.DocumentSymbolParams{ p := protocol.DocumentSymbolParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: string(from.URI()), URI: protocol.URIFromSpanURI(from.URI()),
}, },
} }

View File

@ -15,13 +15,12 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/lsp/telemetry"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/log" "golang.org/x/tools/internal/telemetry/log"
errors "golang.org/x/xerrors" errors "golang.org/x/xerrors"
) )
func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) { func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -257,7 +256,7 @@ func documentChanges(fh source.FileHandle, edits []protocol.TextEdit) []protocol
TextDocument: protocol.VersionedTextDocumentIdentifier{ TextDocument: protocol.VersionedTextDocumentIdentifier{
Version: fh.Identity().Version, Version: fh.Identity().Version,
TextDocumentIdentifier: protocol.TextDocumentIdentifier{ TextDocumentIdentifier: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(fh.Identity().URI), URI: protocol.URIFromSpanURI(fh.Identity().URI),
}, },
}, },
Edits: edits, Edits: edits,

View File

@ -16,7 +16,7 @@ func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCom
return nil, errors.Errorf("expected one file URI for call to `go mod tidy`, got %v", params.Arguments) 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. // Confirm that this action is being taken on a go.mod file.
uri := span.NewURI(params.Arguments[0].(string)) uri := span.URIFromURI(params.Arguments[0].(string))
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -37,7 +37,7 @@ func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCom
if len(params.Arguments) < 2 { 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) return nil, errors.Errorf("expected one file URI and one dependency for call to `go get`, got %v", params.Arguments)
} }
uri := span.NewURI(params.Arguments[0].(string)) uri := span.URIFromURI(params.Arguments[0].(string))
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -11,13 +11,12 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/log" "golang.org/x/tools/internal/telemetry/log"
"golang.org/x/tools/internal/telemetry/tag" "golang.org/x/tools/internal/telemetry/tag"
) )
func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) { func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -137,7 +137,7 @@ func (r *runner) callCompletion(t *testing.T, src span.Span, options func(*sourc
list, err := r.server.Completion(r.ctx, &protocol.CompletionParams{ list, err := r.server.Completion(r.ctx, &protocol.CompletionParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{ TextDocumentPositionParams: protocol.TextDocumentPositionParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(src.URI()), URI: protocol.URIFromSpanURI(src.URI()),
}, },
Position: protocol.Position{ Position: protocol.Position{
Line: float64(src.Start().Line() - 1), Line: float64(src.Start().Line() - 1),

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
) )
func (s *Server) definition(ctx context.Context, params *protocol.DefinitionParams) ([]protocol.Location, error) { func (s *Server) definition(ctx context.Context, params *protocol.DefinitionParams) ([]protocol.Location, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -36,14 +35,14 @@ func (s *Server) definition(ctx context.Context, params *protocol.DefinitionPara
} }
return []protocol.Location{ return []protocol.Location{
{ {
URI: protocol.NewURI(ident.Declaration.URI()), URI: protocol.URIFromSpanURI(ident.Declaration.URI()),
Range: decRange, Range: decRange,
}, },
}, nil }, nil
} }
func (s *Server) typeDefinition(ctx context.Context, params *protocol.TypeDefinitionParams) ([]protocol.Location, error) { func (s *Server) typeDefinition(ctx context.Context, params *protocol.TypeDefinitionParams) ([]protocol.Location, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -66,7 +65,7 @@ func (s *Server) typeDefinition(ctx context.Context, params *protocol.TypeDefini
} }
return []protocol.Location{ return []protocol.Location{
{ {
URI: protocol.NewURI(ident.Type.URI()), URI: protocol.URIFromSpanURI(ident.Type.URI()),
Range: identRange, Range: identRange,
}, },
}, nil }, nil

View File

@ -178,7 +178,7 @@ func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, r
if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{ if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
Diagnostics: toProtocolDiagnostics(diagnostics), Diagnostics: toProtocolDiagnostics(diagnostics),
URI: protocol.NewURI(key.id.URI), URI: protocol.URIFromSpanURI(key.id.URI),
Version: key.id.Version, Version: key.id.Version,
}); err != nil { }); err != nil {
if ctx.Err() == nil { if ctx.Err() == nil {
@ -212,7 +212,7 @@ func toProtocolDiagnostics(diagnostics []source.Diagnostic) []protocol.Diagnosti
for _, rel := range diag.Related { for _, rel := range diag.Related {
related = append(related, protocol.DiagnosticRelatedInformation{ related = append(related, protocol.DiagnosticRelatedInformation{
Location: protocol.Location{ Location: protocol.Location{
URI: protocol.NewURI(rel.URI), URI: protocol.URIFromSpanURI(rel.URI),
Range: rel.Range, Range: rel.Range,
}, },
Message: rel.Message, Message: rel.Message,

View File

@ -222,7 +222,7 @@ func DiffTest(t *testing.T, compute diff.ComputeEdits) {
for _, test := range TestCases { for _, test := range TestCases {
t.Run(test.Name, func(t *testing.T) { t.Run(test.Name, func(t *testing.T) {
t.Helper() t.Helper()
edits := compute(span.FileURI("/"+test.Name), test.In, test.Out) edits := compute(span.URIFromPath("/"+test.Name), test.In, test.Out)
got := diff.ApplyEdits(test.In, edits) got := diff.ApplyEdits(test.In, edits)
unified := fmt.Sprint(diff.ToUnified(FileA, FileB, test.In, edits)) unified := fmt.Sprint(diff.ToUnified(FileA, FileB, test.In, edits))
if got != test.Out { if got != test.Out {

View File

@ -101,16 +101,16 @@ func (w *Workspace) URI(path string) protocol.DocumentURI {
// URIToPath converts a uri to a workspace-relative path (or an absolute path, // URIToPath converts a uri to a workspace-relative path (or an absolute path,
// if the uri is outside of the workspace). // if the uri is outside of the workspace).
func (w *Workspace) URIToPath(uri protocol.DocumentURI) string { func (w *Workspace) URIToPath(uri protocol.DocumentURI) string {
root := w.RootURI() + "/" root := w.RootURI().SpanURI().Filename()
if strings.HasPrefix(uri, root) { path := uri.SpanURI().Filename()
return strings.TrimPrefix(uri, root) if rel, err := filepath.Rel(root, path); err == nil && !strings.HasPrefix(rel, "..") {
return filepath.ToSlash(rel)
} }
filename := span.NewURI(string(uri)).Filename() return filepath.ToSlash(path)
return filepath.ToSlash(filename)
} }
func toURI(fp string) protocol.DocumentURI { func toURI(fp string) protocol.DocumentURI {
return protocol.DocumentURI(span.FileURI(fp)) return protocol.DocumentURI(span.URIFromPath(fp))
} }
// ReadFile reads a text file specified by a workspace-relative path. // ReadFile reads a text file specified by a workspace-relative path.

View File

@ -5,11 +5,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
) )
func (s *Server) foldingRange(ctx context.Context, params *protocol.FoldingRangeParams) ([]protocol.FoldingRange, error) { func (s *Server) foldingRange(ctx context.Context, params *protocol.FoldingRangeParams) ([]protocol.FoldingRange, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
) )
func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) { func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -42,8 +42,8 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitializ
if len(s.pendingFolders) == 0 { if len(s.pendingFolders) == 0 {
if params.RootURI != "" { if params.RootURI != "" {
s.pendingFolders = []protocol.WorkspaceFolder{{ s.pendingFolders = []protocol.WorkspaceFolder{{
URI: params.RootURI, URI: string(params.RootURI),
Name: path.Base(params.RootURI), Name: path.Base(params.RootURI.SpanURI().Filename()),
}} }}
} else { } else {
// No folders and no root--we are in single file mode. // No folders and no root--we are in single file mode.
@ -165,8 +165,8 @@ func (s *Server) addFolders(ctx context.Context, folders []protocol.WorkspaceFol
viewErrors := make(map[span.URI]error) viewErrors := make(map[span.URI]error)
for _, folder := range folders { for _, folder := range folders {
uri := span.NewURI(folder.URI) uri := span.URIFromURI(folder.URI)
_, snapshot, err := s.addView(ctx, folder.Name, span.NewURI(folder.URI)) _, snapshot, err := s.addView(ctx, folder.Name, uri)
if err != nil { if err != nil {
viewErrors[uri] = err viewErrors[uri] = err
continue continue
@ -192,10 +192,10 @@ func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI,
v := protocol.ParamConfiguration{ v := protocol.ParamConfiguration{
ConfigurationParams: protocol.ConfigurationParams{ ConfigurationParams: protocol.ConfigurationParams{
Items: []protocol.ConfigurationItem{{ Items: []protocol.ConfigurationItem{{
ScopeURI: protocol.NewURI(folder), ScopeURI: string(folder),
Section: "gopls", Section: "gopls",
}, { }, {
ScopeURI: protocol.NewURI(folder), ScopeURI: string(folder),
Section: fmt.Sprintf("gopls-%s", name), Section: fmt.Sprintf("gopls-%s", name),
}}, }},
}, },

View File

@ -10,12 +10,11 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/lsp/telemetry"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/log" "golang.org/x/tools/internal/telemetry/log"
) )
func (s *Server) documentHighlight(ctx context.Context, params *protocol.DocumentHighlightParams) ([]protocol.DocumentHighlight, error) { func (s *Server) documentHighlight(ctx context.Context, params *protocol.DocumentHighlightParams) ([]protocol.DocumentHighlight, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
) )
func (s *Server) hover(ctx context.Context, params *protocol.HoverParams) (*protocol.Hover, error) { func (s *Server) hover(ctx context.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
) )
func (s *Server) implementation(ctx context.Context, params *protocol.ImplementationParams) ([]protocol.Location, error) { func (s *Server) implementation(ctx context.Context, params *protocol.ImplementationParams) ([]protocol.Location, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -21,7 +21,7 @@ import (
) )
func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) { func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -54,7 +54,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
options := tests.DefaultOptions() options := tests.DefaultOptions()
session.SetOptions(options) session.SetOptions(options)
options.Env = datum.Config.Env options.Env = datum.Config.Env
v, _, err := session.NewView(ctx, datum.Config.Dir, span.FileURI(datum.Config.Dir), options) v, _, err := session.NewView(ctx, datum.Config.Dir, span.URIFromPath(datum.Config.Dir), options)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -74,7 +74,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
continue continue
} }
modifications = append(modifications, source.FileModification{ modifications = append(modifications, source.FileModification{
URI: span.FileURI(filename), URI: span.URIFromPath(filename),
Action: source.Open, Action: source.Open,
Version: -1, Version: -1,
Text: content, Text: content,
@ -158,7 +158,7 @@ func (r *runner) FoldingRanges(t *testing.T, spn span.Span) {
} }
ranges, err := r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{ ranges, err := r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
}) })
if err != nil { if err != nil {
@ -176,7 +176,7 @@ func (r *runner) FoldingRanges(t *testing.T, spn span.Span) {
} }
ranges, err = r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{ ranges, err = r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
}) })
if err != nil { if err != nil {
@ -310,7 +310,7 @@ func (r *runner) Format(t *testing.T, spn span.Span) {
edits, err := r.server.Formatting(r.ctx, &protocol.DocumentFormattingParams{ edits, err := r.server.Formatting(r.ctx, &protocol.DocumentFormattingParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
}) })
if err != nil { if err != nil {
@ -338,7 +338,7 @@ func (r *runner) Import(t *testing.T, spn span.Span) {
filename := uri.Filename() filename := uri.Filename()
actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{ actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
}) })
if err != nil { if err != nil {
@ -402,7 +402,7 @@ func (r *runner) SuggestedFix(t *testing.T, spn span.Span) {
} }
actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{ actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
Context: protocol.CodeActionContext{ Context: protocol.CodeActionContext{
Only: []protocol.CodeActionKind{protocol.QuickFix}, Only: []protocol.CodeActionKind{protocol.QuickFix},
@ -482,7 +482,7 @@ func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) {
} }
if !d.OnlyHover { if !d.OnlyHover {
didSomething = true didSomething = true
locURI := span.NewURI(locs[0].URI) locURI := locs[0].URI.SpanURI()
lm, err := r.data.Mapper(locURI) lm, err := r.data.Mapper(locURI)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -525,7 +525,7 @@ func (r *runner) Implementation(t *testing.T, spn span.Span, impls []span.Span)
var results []span.Span var results []span.Span
for i := range locs { for i := range locs {
locURI := span.NewURI(locs[i].URI) locURI := locs[i].URI.SpanURI()
lm, err := r.data.Mapper(locURI) lm, err := r.data.Mapper(locURI)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -663,7 +663,7 @@ func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
wedit, err := r.server.Rename(r.ctx, &protocol.RenameParams{ wedit, err := r.server.Rename(r.ctx, &protocol.RenameParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
Position: loc.Range.Start, Position: loc.Range.Start,
NewName: newText, NewName: newText,
@ -692,7 +692,7 @@ func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
if i != 0 { if i != 0 {
got += "\n" got += "\n"
} }
uri := span.NewURI(orderedURIs[i]) uri := span.URIFromURI(orderedURIs[i])
if len(res) > 1 { if len(res) > 1 {
got += filepath.Base(uri.Filename()) + ":\n" got += filepath.Base(uri.Filename()) + ":\n"
} }
@ -753,7 +753,7 @@ func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.Prepare
func applyWorkspaceEdits(r *runner, wedit protocol.WorkspaceEdit) (map[span.URI]string, error) { func applyWorkspaceEdits(r *runner, wedit protocol.WorkspaceEdit) (map[span.URI]string, error) {
res := map[span.URI]string{} res := map[span.URI]string{}
for _, docEdits := range wedit.DocumentChanges { for _, docEdits := range wedit.DocumentChanges {
uri := span.NewURI(docEdits.TextDocument.URI) uri := docEdits.TextDocument.URI.SpanURI()
m, err := r.data.Mapper(uri) m, err := r.data.Mapper(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -786,7 +786,7 @@ func applyEdits(contents string, edits []diff.TextEdit) string {
func (r *runner) Symbols(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) { func (r *runner) Symbols(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) {
params := &protocol.DocumentSymbolParams{ params := &protocol.DocumentSymbolParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: string(uri), URI: protocol.URIFromSpanURI(uri),
}, },
} }
symbols, err := r.server.DocumentSymbol(r.ctx, params) symbols, err := r.server.DocumentSymbol(r.ctx, params)
@ -881,7 +881,7 @@ func (r *runner) SignatureHelp(t *testing.T, spn span.Span, want *protocol.Signa
} }
tdpp := protocol.TextDocumentPositionParams{ tdpp := protocol.TextDocumentPositionParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(spn.URI()), URI: protocol.URIFromSpanURI(spn.URI()),
}, },
Position: loc.Range.Start, Position: loc.Range.Start,
} }
@ -917,7 +917,7 @@ func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {
} }
got, err := r.server.DocumentLink(r.ctx, &protocol.DocumentLinkParams{ got, err := r.server.DocumentLink(r.ctx, &protocol.DocumentLinkParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
}, },
}) })
if err != nil { if err != nil {
@ -955,7 +955,7 @@ func TestBytesOffset(t *testing.T) {
fset := token.NewFileSet() fset := token.NewFileSet()
f := fset.AddFile(fname, -1, len(test.text)) f := fset.AddFile(fname, -1, len(test.text))
f.SetLinesForContent([]byte(test.text)) f.SetLinesForContent([]byte(test.text))
uri := span.FileURI(fname) uri := span.URIFromPath(fname)
converter := span.NewContentConverter(fname, []byte(test.text)) converter := span.NewContentConverter(fname, []byte(test.text))
mapper := &protocol.ColumnMapper{ mapper := &protocol.ColumnMapper{
URI: uri, URI: uri,

View File

@ -105,7 +105,7 @@ func SuggestedFixes(ctx context.Context, snapshot source.Snapshot, realfh source
TextDocument: protocol.VersionedTextDocumentIdentifier{ TextDocument: protocol.VersionedTextDocumentIdentifier{
Version: fh.Identity().Version, Version: fh.Identity().Version,
TextDocumentIdentifier: protocol.TextDocumentIdentifier{ TextDocumentIdentifier: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(fh.Identity().URI), URI: protocol.URIFromSpanURI(fh.Identity().URI),
}, },
}, },
Edits: edits, Edits: edits,
@ -188,7 +188,7 @@ func SuggestedGoFixes(ctx context.Context, snapshot source.Snapshot, gofh source
TextDocument: protocol.VersionedTextDocumentIdentifier{ TextDocument: protocol.VersionedTextDocumentIdentifier{
Version: realfh.Identity().Version, Version: realfh.Identity().Version,
TextDocumentIdentifier: protocol.TextDocumentIdentifier{ TextDocumentIdentifier: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(realfh.Identity().URI), URI: protocol.URIFromSpanURI(realfh.Identity().URI),
}, },
}, },
Edits: edits, Edits: edits,

View File

@ -41,7 +41,7 @@ func TestModfileRemainsUnchanged(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_, snapshot, err := session.NewView(ctx, "diagnostics_test", span.FileURI(folder), options) _, snapshot, err := session.NewView(ctx, "diagnostics_test", span.URIFromPath(folder), options)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -19,8 +19,16 @@ type ColumnMapper struct {
Content []byte Content []byte
} }
func NewURI(uri span.URI) string { func URIFromSpanURI(uri span.URI) DocumentURI {
return string(uri) return DocumentURI(uri)
}
func URIFromPath(path string) DocumentURI {
return URIFromSpanURI(span.URIFromPath(path))
}
func (u DocumentURI) SpanURI() span.URI {
return span.URIFromURI(string(u))
} }
func (m *ColumnMapper) Location(s span.Span) (Location, error) { func (m *ColumnMapper) Location(s span.Span) (Location, error) {
@ -28,7 +36,7 @@ func (m *ColumnMapper) Location(s span.Span) (Location, error) {
if err != nil { if err != nil {
return Location{}, err return Location{}, err
} }
return Location{URI: NewURI(s.URI()), Range: rng}, nil return Location{URI: URIFromSpanURI(s.URI()), Range: rng}, nil
} }
func (m *ColumnMapper) Range(s span.Span) (Range, error) { func (m *ColumnMapper) Range(s span.Span) (Range, error) {

View File

@ -3,7 +3,7 @@ package protocol
// Package protocol contains data types and code for LSP jsonrpcs // Package protocol contains data types and code for LSP jsonrpcs
// generated automatically from vscode-languageserver-node // generated automatically from vscode-languageserver-node
// commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba // commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba
// last fetched Thu Jan 23 2020 11:10:31 GMT-0500 (Eastern Standard Time) // last fetched Wed Feb 12 2020 17:16:47 GMT-0500 (Eastern Standard Time)
// Code generated (see typescript/README.md) DO NOT EDIT. // Code generated (see typescript/README.md) DO NOT EDIT.

View File

@ -1,7 +1,7 @@
// Package protocol contains data types and code for LSP jsonrpcs // Package protocol contains data types and code for LSP jsonrpcs
// generated automatically from vscode-languageserver-node // generated automatically from vscode-languageserver-node
// commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba // commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba
// last fetched Thu Jan 23 2020 11:10:31 GMT-0500 (Eastern Standard Time) // last fetched Wed Feb 12 2020 17:16:47 GMT-0500 (Eastern Standard Time)
package protocol package protocol
// Code generated (see typescript/README.md) DO NOT EDIT. // Code generated (see typescript/README.md) DO NOT EDIT.
@ -1532,7 +1532,7 @@ type DocumentSymbolParams struct {
/** /**
* A tagging type for string properties that are actually URIs. * A tagging type for string properties that are actually URIs.
*/ */
type DocumentURI = string type DocumentURI string
/** /**
* The client capabilities of a [ExecuteCommandRequest](#ExecuteCommandRequest). * The client capabilities of a [ExecuteCommandRequest](#ExecuteCommandRequest).

View File

@ -3,7 +3,7 @@ package protocol
// Package protocol contains data types and code for LSP jsonrpcs // Package protocol contains data types and code for LSP jsonrpcs
// generated automatically from vscode-languageserver-node // generated automatically from vscode-languageserver-node
// commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba // commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba
// last fetched Thu Jan 23 2020 11:10:31 GMT-0500 (Eastern Standard Time) // last fetched Wed Feb 12 2020 17:16:47 GMT-0500 (Eastern Standard Time)
// Code generated (see typescript/README.md) DO NOT EDIT. // Code generated (see typescript/README.md) DO NOT EDIT.

View File

@ -601,7 +601,8 @@ function goTypeAlias(d: Data, nm: string) {
} }
typesOut.push(getComments(d.me)) typesOut.push(getComments(d.me))
// d.alias doesn't seem to have comments // d.alias doesn't seem to have comments
typesOut.push(`type ${goName(nm)} = ${goType(d.alias, nm)}\n`) let aliasStr = goName(nm) == "DocumentURI" ? " " : " = "
typesOut.push(`type ${goName(nm)}${aliasStr}${goType(d.alias, nm)}\n`)
} }
// return a go type and maybe an assocated javascript tag // return a go type and maybe an assocated javascript tag

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
) )
func (s *Server) references(ctx context.Context, params *protocol.ReferenceParams) ([]protocol.Location, error) { func (s *Server) references(ctx context.Context, params *protocol.ReferenceParams) ([]protocol.Location, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -41,7 +40,7 @@ func (s *Server) references(ctx context.Context, params *protocol.ReferenceParam
} }
locations = append(locations, protocol.Location{ locations = append(locations, protocol.Location{
URI: protocol.NewURI(ref.URI()), URI: protocol.URIFromSpanURI(ref.URI()),
Range: refRange, Range: refRange,
}) })
} }

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
) )
func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) { func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -46,7 +45,7 @@ func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*pr
} }
func (s *Server) prepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.Range, error) { func (s *Server) prepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.Range, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -70,7 +70,7 @@ func (s *Server) cancelRequest(ctx context.Context, params *protocol.CancelParam
} }
func (s *Server) codeLens(ctx context.Context, params *protocol.CodeLensParams) ([]protocol.CodeLens, error) { func (s *Server) codeLens(ctx context.Context, params *protocol.CodeLensParams) ([]protocol.CodeLens, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -95,7 +95,7 @@ func (s *Server) nonstandardRequest(ctx context.Context, method string, params i
paramMap := params.(map[string]interface{}) paramMap := params.(map[string]interface{})
if method == "gopls/diagnoseFiles" { if method == "gopls/diagnoseFiles" {
for _, file := range paramMap["files"].([]interface{}) { for _, file := range paramMap["files"].([]interface{}) {
uri := span.NewURI(file.(string)) uri := span.URIFromURI(file.(string))
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -105,7 +105,7 @@ func (s *Server) nonstandardRequest(ctx context.Context, method string, params i
return nil, err return nil, err
} }
if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{ if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
URI: protocol.NewURI(uri), URI: protocol.URIFromSpanURI(uri),
Diagnostics: toProtocolDiagnostics(diagnostics), Diagnostics: toProtocolDiagnostics(diagnostics),
Version: fileID.Version, Version: fileID.Version,
}); err != nil { }); err != nil {

View File

@ -9,13 +9,12 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/log" "golang.org/x/tools/internal/telemetry/log"
"golang.org/x/tools/internal/telemetry/tag" "golang.org/x/tools/internal/telemetry/tag"
) )
func (s *Server) signatureHelp(ctx context.Context, params *protocol.SignatureHelpParams) (*protocol.SignatureHelp, error) { func (s *Server) signatureHelp(ctx context.Context, params *protocol.SignatureHelpParams) (*protocol.SignatureHelp, error) {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -179,7 +179,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
if !pos.IsValid() { if !pos.IsValid() {
return item, nil return item, nil
} }
uri := span.FileURI(pos.Filename) uri := span.URIFromPath(pos.Filename)
// Find the source file of the candidate, starting from a package // Find the source file of the candidate, starting from a package
// that should have it in its dependencies. // that should have it in its dependencies.
@ -213,7 +213,7 @@ func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
return nil, nil return nil, nil
} }
uri := span.FileURI(c.filename) uri := span.URIFromPath(c.filename)
var ph ParseGoHandle var ph ParseGoHandle
for _, h := range c.pkg.CompiledGoFiles() { for _, h := range c.pkg.CompiledGoFiles() {
if h.File().Identity().URI == uri { if h.File().Identity().URI == uri {

View File

@ -39,7 +39,7 @@ func Implementation(ctx context.Context, s Snapshot, f FileHandle, pp protocol.P
return nil, err return nil, err
} }
locations = append(locations, protocol.Location{ locations = append(locations, protocol.Location{
URI: protocol.NewURI(rng.URI()), URI: protocol.URIFromSpanURI(rng.URI()),
Range: pr, Range: pr,
}) })
} }

View File

@ -51,7 +51,7 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
session := cache.NewSession() session := cache.NewSession()
options := tests.DefaultOptions() options := tests.DefaultOptions()
options.Env = datum.Config.Env options.Env = datum.Config.Env
view, _, err := session.NewView(ctx, "source_test", span.FileURI(datum.Config.Dir), options) view, _, err := session.NewView(ctx, "source_test", span.URIFromPath(datum.Config.Dir), options)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -67,7 +67,7 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
continue continue
} }
modifications = append(modifications, source.FileModification{ modifications = append(modifications, source.FileModification{
URI: span.FileURI(filename), URI: span.URIFromPath(filename),
Action: source.Open, Action: source.Open,
Version: -1, Version: -1,
Text: content, Text: content,
@ -547,7 +547,7 @@ func (r *runner) Implementation(t *testing.T, spn span.Span, impls []span.Span)
} }
var results []span.Span var results []span.Span
for i := range locs { for i := range locs {
locURI := span.NewURI(locs[i].URI) locURI := locs[i].URI.SpanURI()
lm, err := r.data.Mapper(locURI) lm, err := r.data.Mapper(locURI)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -201,7 +201,7 @@ func nameToMappedRange(v View, pkg Package, pos token.Pos, name string) (mappedR
func posToMappedRange(v View, pkg Package, pos, end token.Pos) (mappedRange, error) { func posToMappedRange(v View, pkg Package, pos, end token.Pos) (mappedRange, error) {
logicalFilename := v.Session().Cache().FileSet().File(pos).Position(pos).Filename logicalFilename := v.Session().Cache().FileSet().File(pos).Position(pos).Filename
m, err := findMapperInPackage(v, pkg, span.FileURI(logicalFilename)) m, err := findMapperInPackage(v, pkg, span.URIFromPath(logicalFilename))
if err != nil { if err != nil {
return mappedRange{}, err return mappedRange{}, err
} }
@ -631,7 +631,7 @@ func findPosInPackage(v View, searchpkg Package, pos token.Pos) (*ast.File, Pack
if tok == nil { if tok == nil {
return nil, nil, errors.Errorf("no file for pos in package %s", searchpkg.ID()) return nil, nil, errors.Errorf("no file for pos in package %s", searchpkg.ID())
} }
uri := span.FileURI(tok.Name()) uri := span.URIFromPath(tok.Name())
var ( var (
ph ParseGoHandle ph ParseGoHandle

View File

@ -53,7 +53,7 @@ func WorkspaceSymbols(ctx context.Context, views []View, query string) ([]protoc
Name: si.name, Name: si.name,
Kind: si.kind, Kind: si.kind,
Location: protocol.Location{ Location: protocol.Location{
URI: protocol.NewURI(fh.File().Identity().URI), URI: protocol.URIFromSpanURI(fh.File().Identity().URI),
Range: rng, Range: rng,
}, },
}) })

View File

@ -10,7 +10,6 @@ import (
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/lsp/telemetry"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/log" "golang.org/x/tools/internal/telemetry/log"
"golang.org/x/tools/internal/telemetry/trace" "golang.org/x/tools/internal/telemetry/trace"
) )
@ -19,7 +18,7 @@ func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSy
ctx, done := trace.StartSpan(ctx, "lsp.Server.documentSymbol") ctx, done := trace.StartSpan(ctx, "lsp.Server.documentSymbol")
defer done() defer done()
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri) view, err := s.session.ViewOf(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -466,7 +466,7 @@ func Run(t *testing.T, tests Tests, data *Data) {
t.Helper() t.Helper()
dirs := make(map[string]struct{}) dirs := make(map[string]struct{})
for _, si := range expectedSymbols { for _, si := range expectedSymbols {
d := filepath.Dir(si.Location.URI) d := filepath.Dir(si.Location.URI.SpanURI().Filename())
if _, ok := dirs[d]; !ok { if _, ok := dirs[d]; !ok {
dirs[d] = struct{}{} dirs[d] = struct{}{}
} }
@ -1077,7 +1077,7 @@ func (data *Data) collectSymbols(name string, spn span.Span, kind string, parent
Name: sym.Name, Name: sym.Name,
Kind: sym.Kind, Kind: sym.Kind,
Location: protocol.Location{ Location: protocol.Location{
URI: protocol.NewURI(spn.URI()), URI: protocol.URIFromSpanURI(spn.URI()),
Range: sym.SelectionRange, Range: sym.SelectionRange,
}, },
} }

View File

@ -109,7 +109,7 @@ func summarizeSymbols(t *testing.T, i int, want, got []protocol.DocumentSymbol,
func FilterWorkspaceSymbols(got []protocol.SymbolInformation, dirs map[string]struct{}) []protocol.SymbolInformation { func FilterWorkspaceSymbols(got []protocol.SymbolInformation, dirs map[string]struct{}) []protocol.SymbolInformation {
var result []protocol.SymbolInformation var result []protocol.SymbolInformation
for _, si := range got { for _, si := range got {
if _, ok := dirs[filepath.Dir(si.Location.URI)]; ok { if _, ok := dirs[filepath.Dir(si.Location.URI.SpanURI().Filename())]; ok {
result = append(result, si) result = append(result, si)
} }
} }

View File

@ -19,7 +19,7 @@ import (
func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error { func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error {
_, err := s.didModifyFiles(ctx, []source.FileModification{ _, err := s.didModifyFiles(ctx, []source.FileModification{
{ {
URI: span.NewURI(params.TextDocument.URI), URI: params.TextDocument.URI.SpanURI(),
Action: source.Open, Action: source.Open,
Version: params.TextDocument.Version, Version: params.TextDocument.Version,
Text: []byte(params.TextDocument.Text), Text: []byte(params.TextDocument.Text),
@ -30,7 +30,7 @@ func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocume
} }
func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error { func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error {
uri := span.NewURI(params.TextDocument.URI) uri := params.TextDocument.URI.SpanURI()
text, err := s.changedText(ctx, uri, params.ContentChanges) text, err := s.changedText(ctx, uri, params.ContentChanges)
if err != nil { if err != nil {
return err return err
@ -66,7 +66,7 @@ func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.Did
var modifications []source.FileModification var modifications []source.FileModification
for _, change := range params.Changes { for _, change := range params.Changes {
modifications = append(modifications, source.FileModification{ modifications = append(modifications, source.FileModification{
URI: span.NewURI(change.URI), URI: change.URI.SpanURI(),
Action: changeTypeToFileAction(change.Type), Action: changeTypeToFileAction(change.Type),
OnDisk: true, OnDisk: true,
}) })
@ -77,7 +77,7 @@ func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.Did
func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) error { func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) error {
c := source.FileModification{ c := source.FileModification{
URI: span.NewURI(params.TextDocument.URI), URI: params.TextDocument.URI.SpanURI(),
Action: source.Save, Action: source.Save,
Version: params.TextDocument.Version, Version: params.TextDocument.Version,
} }
@ -91,7 +91,7 @@ func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocume
func (s *Server) didClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error { func (s *Server) didClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error {
_, err := s.didModifyFiles(ctx, []source.FileModification{ _, err := s.didModifyFiles(ctx, []source.FileModification{
{ {
URI: span.NewURI(params.TextDocument.URI), URI: params.TextDocument.URI.SpanURI(),
Action: source.Close, Action: source.Close,
Version: -1, Version: -1,
Text: nil, Text: nil,

View File

@ -11,7 +11,7 @@ import (
) )
// Parse returns the location represented by the input. // Parse returns the location represented by the input.
// All inputs are valid locations, as they can always be a pure filename. // Only file paths are accepted, not URIs.
// The returned span will be normalized, and thus if printed may produce a // The returned span will be normalized, and thus if printed may produce a
// different string. // different string.
func Parse(input string) Span { func Parse(input string) Span {
@ -32,12 +32,12 @@ func Parse(input string) Span {
} }
switch { switch {
case suf.sep == ":": case suf.sep == ":":
return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), Point{}) return New(URIFromPath(suf.remains), NewPoint(suf.num, hold, offset), Point{})
case suf.sep == "-": case suf.sep == "-":
// we have a span, fall out of the case to continue // we have a span, fall out of the case to continue
default: default:
// separator not valid, rewind to either the : or the start // separator not valid, rewind to either the : or the start
return New(NewURI(valid), NewPoint(hold, 0, offset), Point{}) return New(URIFromPath(valid), NewPoint(hold, 0, offset), Point{})
} }
// only the span form can get here // only the span form can get here
// at this point we still don't know what the numbers we have mean // at this point we still don't know what the numbers we have mean
@ -53,20 +53,20 @@ func Parse(input string) Span {
} }
if suf.sep != ":" { if suf.sep != ":" {
// turns out we don't have a span after all, rewind // turns out we don't have a span after all, rewind
return New(NewURI(valid), end, Point{}) return New(URIFromPath(valid), end, Point{})
} }
valid = suf.remains valid = suf.remains
hold = suf.num hold = suf.num
suf = rstripSuffix(suf.remains) suf = rstripSuffix(suf.remains)
if suf.sep != ":" { if suf.sep != ":" {
// line#offset only // line#offset only
return New(NewURI(valid), NewPoint(hold, 0, offset), end) return New(URIFromPath(valid), NewPoint(hold, 0, offset), end)
} }
// we have a column, so if end only had one number, it is also the column // we have a column, so if end only had one number, it is also the column
if !hadCol { if !hadCol {
end = NewPoint(suf.num, end.v.Line, end.v.Offset) end = NewPoint(suf.num, end.v.Line, end.v.Offset)
} }
return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), end) return New(URIFromPath(suf.remains), NewPoint(suf.num, hold, offset), end)
} }
type suffix struct { type suffix struct {

View File

@ -14,8 +14,7 @@ import (
) )
var ( var (
formats = []string{"%v", "%#v", "%+v"} tests = [][]string{
tests = [][]string{
{"C:/file_a", "C:/file_a", "file:///C:/file_a:1:1#0"}, {"C:/file_a", "C:/file_a", "file:///C:/file_a:1:1#0"},
{"C:/file_b:1:2", "C:/file_b:#1", "file:///C:/file_b:1:2#1"}, {"C:/file_b:1:2", "C:/file_b:#1", "file:///C:/file_b:1:2#1"},
{"C:/file_c:1000", "C:/file_c:#9990", "file:///C:/file_c:1000:1#9990"}, {"C:/file_c:1000", "C:/file_c:#9990", "file:///C:/file_c:1000:1#9990"},
@ -30,7 +29,7 @@ var (
func TestFormat(t *testing.T) { func TestFormat(t *testing.T) {
converter := lines(10) converter := lines(10)
for _, test := range tests { for _, test := range tests {
for ti, text := range test { for ti, text := range test[:2] {
spn := span.Parse(text) spn := span.Parse(text)
if ti <= 1 { if ti <= 1 {
// we can check %v produces the same as the input // we can check %v produces the same as the input

View File

@ -75,7 +75,7 @@ func (r Range) Span() (Span, error) {
if err != nil { if err != nil {
return Span{}, err return Span{}, err
} }
s.v.URI = FileURI(startFilename) s.v.URI = URIFromPath(startFilename)
if r.End.IsValid() { if r.End.IsValid() {
var endFilename string var endFilename string
endFilename, s.v.End.Line, s.v.End.Column, err = position(f, r.End) endFilename, s.v.End.Line, s.v.End.Column, err = position(f, r.End)

View File

@ -32,10 +32,10 @@ package test`)},
} }
var tokenTests = []span.Span{ var tokenTests = []span.Span{
span.New(span.FileURI("/a.go"), span.NewPoint(1, 1, 0), span.Point{}), span.New(span.URIFromPath("/a.go"), span.NewPoint(1, 1, 0), span.Point{}),
span.New(span.FileURI("/a.go"), span.NewPoint(3, 7, 20), span.NewPoint(3, 7, 20)), span.New(span.URIFromPath("/a.go"), span.NewPoint(3, 7, 20), span.NewPoint(3, 7, 20)),
span.New(span.FileURI("/b.go"), span.NewPoint(4, 9, 15), span.NewPoint(4, 13, 19)), span.New(span.URIFromPath("/b.go"), span.NewPoint(4, 9, 15), span.NewPoint(4, 13, 19)),
span.New(span.FileURI("/c.go"), span.NewPoint(4, 1, 26), span.Point{}), span.New(span.URIFromPath("/c.go"), span.NewPoint(4, 1, 26), span.Point{}),
} }
func TestToken(t *testing.T) { func TestToken(t *testing.T) {
@ -44,7 +44,7 @@ func TestToken(t *testing.T) {
for _, f := range testdata { for _, f := range testdata {
file := fset.AddFile(f.uri, -1, len(f.content)) file := fset.AddFile(f.uri, -1, len(f.content))
file.SetLinesForContent(f.content) file.SetLinesForContent(f.content)
files[span.FileURI(f.uri)] = file files[span.URIFromPath(f.uri)] = file
} }
for _, test := range tokenTests { for _, test := range tokenTests {
f := files[test.URI()] f := files[test.URI()]

View File

@ -49,28 +49,26 @@ func filename(uri URI) (string, error) {
return u.Path, nil return u.Path, nil
} }
// NewURI returns a span URI for the string. func URIFromURI(s string) URI {
// It will attempt to detect if the string is a file path or uri. if !strings.HasPrefix(s, "file:///") {
func NewURI(s string) URI {
// If a path has a scheme, it is already a URI.
// We only handle the file:// scheme.
if i := len(fileScheme + "://"); strings.HasPrefix(s, "file:///") {
// Handle microsoft/vscode#75027 by making it a special case.
// On Windows, VS Code sends file URIs that look like file:///C%3A/x/y/z.
// Replace the %3A so that the URI looks like: file:///C:/x/y/z.
if strings.ToLower(s[i+2:i+5]) == "%3a" {
s = s[:i+2] + ":" + s[i+5:]
}
// File URIs from Windows may have lowercase drive letters.
// Since drive letters are guaranteed to be case insensitive,
// we change them to uppercase to remain consistent.
// For example, file:///c:/x/y/z becomes file:///C:/x/y/z.
if isWindowsDriveURIPath(s[i:]) {
s = s[:i+1] + strings.ToUpper(string(s[i+1])) + s[i+2:]
}
return URI(s) return URI(s)
} }
return FileURI(s) // Handle Windows-specific glitches. We can't parse the URI -- it may not be valid.
path := s[len("file://"):]
// Handle microsoft/vscode#75027 by making it a special case.
// On Windows, VS Code sends file URIs that look like file:///C%3A/x/y/z.
// Replace the %3A so that the URI looks like: file:///C:/x/y/z.
if strings.ToLower(path[2:5]) == "%3a" {
path = path[:2] + ":" + path[5:]
}
// File URIs from Windows may have lowercase drive letters.
// Since drive letters are guaranteed to be case insensitive,
// we change them to uppercase to remain consistent.
// For example, file:///c:/x/y/z becomes file:///C:/x/y/z.
if isWindowsDriveURIPath(path) {
path = path[:1] + strings.ToUpper(string(path[1])) + path[2:]
}
return URI("file://" + path)
} }
func CompareURI(a, b URI) int { func CompareURI(a, b URI) int {
@ -111,9 +109,9 @@ func equalURI(a, b URI) bool {
return os.SameFile(infoa, infob) return os.SameFile(infoa, infob)
} }
// FileURI returns a span URI for the supplied file path. // URIFromPath returns a span URI for the supplied file path.
// It will always have the file scheme. // It will always have the file scheme.
func FileURI(path string) URI { func URIFromPath(path string) URI {
if path == "" { if path == "" {
return "" return ""
} }

View File

@ -16,7 +16,7 @@ import (
// include Windows-style URIs and filepaths, but we avoid having OS-specific // include Windows-style URIs and filepaths, but we avoid having OS-specific
// tests by using only forward slashes, assuming that the standard library // tests by using only forward slashes, assuming that the standard library
// functions filepath.ToSlash and filepath.FromSlash do not need testing. // functions filepath.ToSlash and filepath.FromSlash do not need testing.
func TestURI(t *testing.T) { func TestURIFromPath(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
path, wantFile string path, wantFile string
wantURI span.URI wantURI span.URI
@ -56,25 +56,42 @@ func TestURI(t *testing.T) {
wantFile: `C:/Go/src/bob george/george/george.go`, wantFile: `C:/Go/src/bob george/george/george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
}, },
{
path: `file:///c:/Go/src/bob%20george/george/george.go`,
wantFile: `C:/Go/src/bob george/george/george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
},
{
path: `file:///C%3A/Go/src/bob%20george/george/george.go`,
wantFile: `C:/Go/src/bob george/george/george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
},
{
path: `file:///path/to/%25p%25ercent%25/per%25cent.go`,
wantFile: `/path/to/%p%ercent%/per%cent.go`,
wantURI: span.URI(`file:///path/to/%25p%25ercent%25/per%25cent.go`),
},
} { } {
got := span.NewURI(test.path) got := span.URIFromPath(test.path)
if got != test.wantURI { if got != test.wantURI {
t.Errorf("NewURI(%q): got %q, expected %q", test.path, got, test.wantURI) t.Errorf("URIFromPath(%q): got %q, expected %q", test.path, got, test.wantURI)
}
gotFilename := got.Filename()
if gotFilename != test.wantFile {
t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile)
}
}
}
func TestURIFromURI(t *testing.T) {
for _, test := range []struct {
inputURI, wantFile string
wantURI span.URI
}{
{
inputURI: `file:///c:/Go/src/bob%20george/george/george.go`,
wantFile: `C:/Go/src/bob george/george/george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
},
{
inputURI: `file:///C%3A/Go/src/bob%20george/george/george.go`,
wantFile: `C:/Go/src/bob george/george/george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
},
{
inputURI: `file:///path/to/%25p%25ercent%25/per%25cent.go`,
wantFile: `/path/to/%p%ercent%/per%cent.go`,
wantURI: span.URI(`file:///path/to/%25p%25ercent%25/per%25cent.go`),
},
} {
got := span.URIFromURI(test.inputURI)
if got != test.wantURI {
t.Errorf("NewURI(%q): got %q, expected %q", test.inputURI, got, test.wantURI)
} }
gotFilename := got.Filename() gotFilename := got.Filename()
if gotFilename != test.wantFile { if gotFilename != test.wantFile {

View File

@ -16,7 +16,7 @@ import (
// include Windows-style URIs and filepaths, but we avoid having OS-specific // include Windows-style URIs and filepaths, but we avoid having OS-specific
// tests by using only forward slashes, assuming that the standard library // tests by using only forward slashes, assuming that the standard library
// functions filepath.ToSlash and filepath.FromSlash do not need testing. // functions filepath.ToSlash and filepath.FromSlash do not need testing.
func TestURI(t *testing.T) { func TestURIFromPath(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
path, wantFile string path, wantFile string
wantURI span.URI wantURI span.URI
@ -56,28 +56,46 @@ func TestURI(t *testing.T) {
wantFile: `C:\Go\src\bob george\george\george.go`, wantFile: `C:\Go\src\bob george\george\george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
}, },
} {
got := span.URIFromPath(test.path)
if got != test.wantURI {
t.Errorf("URIFromPath(%q): got %q, expected %q", test.path, got, test.wantURI)
}
gotFilename := got.Filename()
if gotFilename != test.wantFile {
t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile)
}
}
}
func TestURIFromURI(t *testing.T) {
for _, test := range []struct {
inputURI, wantFile string
wantURI span.URI
}{
{ {
path: `file:///c:/Go/src/bob%20george/george/george.go`, inputURI: `file:///c:/Go/src/bob%20george/george/george.go`,
wantFile: `C:\Go\src\bob george\george\george.go`, wantFile: `C:\Go\src\bob george\george\george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
}, },
{ {
path: `file:///C%3A/Go/src/bob%20george/george/george.go`, inputURI: `file:///C%3A/Go/src/bob%20george/george/george.go`,
wantFile: `C:\Go\src\bob george\george\george.go`, wantFile: `C:\Go\src\bob george\george\george.go`,
wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"), wantURI: span.URI("file:///C:/Go/src/bob%20george/george/george.go"),
}, },
{ {
path: `file:///c:/path/to/%25p%25ercent%25/per%25cent.go`, inputURI: `file:///c:/path/to/%25p%25ercent%25/per%25cent.go`,
wantFile: `C:\path\to\%p%ercent%\per%cent.go`, wantFile: `C:\path\to\%p%ercent%\per%cent.go`,
wantURI: span.URI(`file:///C:/path/to/%25p%25ercent%25/per%25cent.go`), wantURI: span.URI(`file:///C:/path/to/%25p%25ercent%25/per%25cent.go`),
}, },
} { } {
got := span.NewURI(test.path) got := span.URIFromURI(test.inputURI)
if got != test.wantURI { if got != test.wantURI {
t.Errorf("ToURI: got %s, expected %s", got, test.wantURI) t.Errorf("NewURI(%q): got %q, expected %q", test.inputURI, got, test.wantURI)
} }
if got.Filename() != test.wantFile { gotFilename := got.Filename()
t.Errorf("Filename: got %s, expected %s", got.Filename(), test.wantFile) if gotFilename != test.wantFile {
t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile)
} }
} }
} }