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)
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)
for _, l := range x {
if l.Method == "window/logMessage" {
@ -102,9 +102,9 @@ func main() {
}
log.Printf("%s: %s", label, msg)
}
mdiags := make(map[string][]p.Diagnostic)
mdiags := make(map[p.DocumentURI][]p.Diagnostic)
f(msgs, "old", mdiags)
vdiags := make(map[string][]p.Diagnostic)
vdiags := make(map[p.DocumentURI][]p.Diagnostic)
f(newMsgs, "new", vdiags)
buf := []string{}
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) {
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 {
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) {
ph, _, err := source.FindFileInPackage(pkg, span.FileURI(posn.Filename))
ph, _, err := source.FindFileInPackage(pkg, span.URIFromPath(posn.Filename))
if err != nil {
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 {
uri := span.FileURI(filename)
uri := span.URIFromPath(filename)
m.compiledGoFiles = append(m.compiledGoFiles, uri)
s.addID(uri, m.id)
}
for _, filename := range pkg.GoFiles {
uri := span.FileURI(filename)
uri := span.URIFromPath(filename)
m.goFiles = append(m.goFiles, uri)
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 {
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
// 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 {
return nil
}
v.realMod = span.FileURI(modFile)
v.realMod = span.URIFromPath(modFile)
// Now that we have set all required fields,
// 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 {
return err
}
v.tempMod = span.FileURI(tempModFile.Name())
v.tempMod = span.URIFromPath(tempModFile.Name())
// Copy go.sum file as well (if there is one).
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/cache"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/span"
errors "golang.org/x/xerrors"
)
@ -36,7 +35,7 @@ func TestCapabilities(t *testing.T) {
defer c.terminate(ctx)
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
// Send an initialize request to the server.
@ -55,7 +54,7 @@ func TestCapabilities(t *testing.T) {
}
// 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{
TextDocument: protocol.TextDocumentItem{
URI: uri,

View File

@ -48,7 +48,7 @@ func (c *check) Run(ctx context.Context, args ...string) error {
}
defer conn.terminate(ctx)
for _, arg := range args {
uri := span.FileURI(arg)
uri := span.URIFromPath(arg)
uris = append(uris, uri)
file := conn.AddFile(ctx, uri)
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 {
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
// 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()
defer c.filesMu.Unlock()
uri := span.NewURI(p.URI)
file := c.getFile(ctx, uri)
file := c.getFile(ctx, p.URI.SpanURI())
file.diagnostics = p.Diagnostics
return nil
}
@ -424,7 +423,7 @@ func (c *connection) AddFile(ctx context.Context, uri span.URI) *cmdFile {
file.added = true
p := &protocol.DidOpenTextDocumentParams{
TextDocument: protocol.TextDocumentItem{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
LanguageID: source.DetectLanguage("", file.uri.Filename()).String(),
Version: 1,
Text: string(file.mapper.Content),

View File

@ -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, span.NewURI(locs[0].URI))
file = conn.AddFile(ctx, locs[0].URI.SpanURI())
if file.err != nil {
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{
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
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)
if err != nil {
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
})
if err != nil {
@ -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 == string(uri) {
if c.TextDocument.URI.SpanURI() == uri {
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
})
if err != nil {

View File

@ -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, span.NewURI(l.URI))
f := conn.AddFile(ctx, l.URI.SpanURI())
// convert location to span for user-friendly 1-indexed line
// and column numbers
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
edits := map[span.URI][]protocol.TextEdit{}
for _, c := range edit.DocumentChanges {
uri := span.NewURI(c.TextDocument.URI)
uri := c.TextDocument.URI.SpanURI()
edits[uri] = append(edits[uri], c.Edits...)
orderedURIs = append(orderedURIs, c.TextDocument.URI)
orderedURIs = append(orderedURIs, string(uri))
}
sort.Strings(orderedURIs)
changeCount := len(orderedURIs)
for _, u := range orderedURIs {
uri := span.NewURI(u)
uri := span.URIFromURI(u)
cmdFile := conn.AddFile(ctx, uri)
filename := cmdFile.uri.Filename()

View File

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

View File

@ -70,7 +70,7 @@ func (s *suggestedfix) Run(ctx context.Context, args ...string) error {
p := protocol.CodeActionParams{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
Context: protocol.CodeActionContext{
Only: []protocol.CodeActionKind{protocol.QuickFix},
@ -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 == string(uri) {
if c.TextDocument.URI.SpanURI() == uri {
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])
p := protocol.DocumentSymbolParams{
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/source"
"golang.org/x/tools/internal/lsp/telemetry"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/log"
errors "golang.org/x/xerrors"
)
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)
if err != nil {
return nil, err
@ -257,7 +256,7 @@ func documentChanges(fh source.FileHandle, edits []protocol.TextEdit) []protocol
TextDocument: protocol.VersionedTextDocumentIdentifier{
Version: fh.Identity().Version,
TextDocumentIdentifier: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(fh.Identity().URI),
URI: protocol.URIFromSpanURI(fh.Identity().URI),
},
},
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)
}
// 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)
if err != nil {
return nil, err
@ -37,7 +37,7 @@ func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCom
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.NewURI(params.Arguments[0].(string))
uri := span.URIFromURI(params.Arguments[0].(string))
view, err := s.session.ViewOf(uri)
if err != nil {
return nil, err

View File

@ -11,13 +11,12 @@ import (
"golang.org/x/tools/internal/lsp/protocol"
"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/tag"
)
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)
if err != nil {
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{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(src.URI()),
URI: protocol.URIFromSpanURI(src.URI()),
},
Position: protocol.Position{
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/source"
"golang.org/x/tools/internal/span"
)
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)
if err != nil {
return nil, err
@ -36,14 +35,14 @@ func (s *Server) definition(ctx context.Context, params *protocol.DefinitionPara
}
return []protocol.Location{
{
URI: protocol.NewURI(ident.Declaration.URI()),
URI: protocol.URIFromSpanURI(ident.Declaration.URI()),
Range: decRange,
},
}, nil
}
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)
if err != nil {
return nil, err
@ -66,7 +65,7 @@ func (s *Server) typeDefinition(ctx context.Context, params *protocol.TypeDefini
}
return []protocol.Location{
{
URI: protocol.NewURI(ident.Type.URI()),
URI: protocol.URIFromSpanURI(ident.Type.URI()),
Range: identRange,
},
}, 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{
Diagnostics: toProtocolDiagnostics(diagnostics),
URI: protocol.NewURI(key.id.URI),
URI: protocol.URIFromSpanURI(key.id.URI),
Version: key.id.Version,
}); err != nil {
if ctx.Err() == nil {
@ -212,7 +212,7 @@ func toProtocolDiagnostics(diagnostics []source.Diagnostic) []protocol.Diagnosti
for _, rel := range diag.Related {
related = append(related, protocol.DiagnosticRelatedInformation{
Location: protocol.Location{
URI: protocol.NewURI(rel.URI),
URI: protocol.URIFromSpanURI(rel.URI),
Range: rel.Range,
},
Message: rel.Message,

View File

@ -222,7 +222,7 @@ func DiffTest(t *testing.T, compute diff.ComputeEdits) {
for _, test := range TestCases {
t.Run(test.Name, func(t *testing.T) {
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)
unified := fmt.Sprint(diff.ToUnified(FileA, FileB, test.In, edits))
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,
// if the uri is outside of the workspace).
func (w *Workspace) URIToPath(uri protocol.DocumentURI) string {
root := w.RootURI() + "/"
if strings.HasPrefix(uri, root) {
return strings.TrimPrefix(uri, root)
root := w.RootURI().SpanURI().Filename()
path := uri.SpanURI().Filename()
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(filename)
return filepath.ToSlash(path)
}
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.

View File

@ -5,11 +5,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol"
"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) {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri)
if err != nil {
return nil, err

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol"
"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) {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri)
if err != nil {
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 params.RootURI != "" {
s.pendingFolders = []protocol.WorkspaceFolder{{
URI: params.RootURI,
Name: path.Base(params.RootURI),
URI: string(params.RootURI),
Name: path.Base(params.RootURI.SpanURI().Filename()),
}}
} else {
// 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)
for _, folder := range folders {
uri := span.NewURI(folder.URI)
_, snapshot, err := s.addView(ctx, folder.Name, span.NewURI(folder.URI))
uri := span.URIFromURI(folder.URI)
_, snapshot, err := s.addView(ctx, folder.Name, uri)
if err != nil {
viewErrors[uri] = err
continue
@ -192,10 +192,10 @@ func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI,
v := protocol.ParamConfiguration{
ConfigurationParams: protocol.ConfigurationParams{
Items: []protocol.ConfigurationItem{{
ScopeURI: protocol.NewURI(folder),
ScopeURI: string(folder),
Section: "gopls",
}, {
ScopeURI: protocol.NewURI(folder),
ScopeURI: string(folder),
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/source"
"golang.org/x/tools/internal/lsp/telemetry"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/telemetry/log"
)
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)
if err != nil {
return nil, err

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol"
"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) {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri)
if err != nil {
return nil, err

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol"
"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) {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri)
if err != nil {
return nil, err

View File

@ -21,7 +21,7 @@ import (
)
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)
if err != nil {
return nil, err

View File

@ -54,7 +54,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
options := tests.DefaultOptions()
session.SetOptions(options)
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 {
t.Fatal(err)
}
@ -74,7 +74,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
continue
}
modifications = append(modifications, source.FileModification{
URI: span.FileURI(filename),
URI: span.URIFromPath(filename),
Action: source.Open,
Version: -1,
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
})
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
})
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
})
if err != nil {
@ -338,7 +338,7 @@ func (r *runner) Import(t *testing.T, spn span.Span) {
filename := uri.Filename()
actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
})
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
Context: protocol.CodeActionContext{
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 {
didSomething = true
locURI := span.NewURI(locs[0].URI)
locURI := locs[0].URI.SpanURI()
lm, err := r.data.Mapper(locURI)
if err != nil {
t.Fatal(err)
@ -525,7 +525,7 @@ func (r *runner) Implementation(t *testing.T, spn span.Span, impls []span.Span)
var results []span.Span
for i := range locs {
locURI := span.NewURI(locs[i].URI)
locURI := locs[i].URI.SpanURI()
lm, err := r.data.Mapper(locURI)
if err != nil {
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
Position: loc.Range.Start,
NewName: newText,
@ -692,7 +692,7 @@ func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
if i != 0 {
got += "\n"
}
uri := span.NewURI(orderedURIs[i])
uri := span.URIFromURI(orderedURIs[i])
if len(res) > 1 {
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) {
res := map[span.URI]string{}
for _, docEdits := range wedit.DocumentChanges {
uri := span.NewURI(docEdits.TextDocument.URI)
uri := docEdits.TextDocument.URI.SpanURI()
m, err := r.data.Mapper(uri)
if err != nil {
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) {
params := &protocol.DocumentSymbolParams{
TextDocument: protocol.TextDocumentIdentifier{
URI: string(uri),
URI: protocol.URIFromSpanURI(uri),
},
}
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(spn.URI()),
URI: protocol.URIFromSpanURI(spn.URI()),
},
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{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
},
})
if err != nil {
@ -955,7 +955,7 @@ func TestBytesOffset(t *testing.T) {
fset := token.NewFileSet()
f := fset.AddFile(fname, -1, len(test.text))
f.SetLinesForContent([]byte(test.text))
uri := span.FileURI(fname)
uri := span.URIFromPath(fname)
converter := span.NewContentConverter(fname, []byte(test.text))
mapper := &protocol.ColumnMapper{
URI: uri,

View File

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

View File

@ -41,7 +41,7 @@ func TestModfileRemainsUnchanged(t *testing.T) {
if err != nil {
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 {
t.Fatal(err)
}

View File

@ -19,8 +19,16 @@ type ColumnMapper struct {
Content []byte
}
func NewURI(uri span.URI) string {
return string(uri)
func URIFromSpanURI(uri span.URI) DocumentURI {
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) {
@ -28,7 +36,7 @@ func (m *ColumnMapper) Location(s span.Span) (Location, error) {
if err != nil {
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) {

View File

@ -3,7 +3,7 @@ package protocol
// Package protocol contains data types and code for LSP jsonrpcs
// generated automatically from vscode-languageserver-node
// 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.

View File

@ -1,7 +1,7 @@
// Package protocol contains data types and code for LSP jsonrpcs
// generated automatically from vscode-languageserver-node
// 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
// 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.
*/
type DocumentURI = string
type DocumentURI string
/**
* 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
// generated automatically from vscode-languageserver-node
// 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.

View File

@ -601,7 +601,8 @@ function goTypeAlias(d: Data, nm: string) {
}
typesOut.push(getComments(d.me))
// 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

View File

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

View File

@ -9,11 +9,10 @@ import (
"golang.org/x/tools/internal/lsp/protocol"
"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) {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri)
if err != nil {
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) {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri)
if err != nil {
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) {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
view, err := s.session.ViewOf(uri)
if err != nil {
return nil, err
@ -95,7 +95,7 @@ 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.NewURI(file.(string))
uri := span.URIFromURI(file.(string))
view, err := s.session.ViewOf(uri)
if err != nil {
return nil, err
@ -105,7 +105,7 @@ func (s *Server) nonstandardRequest(ctx context.Context, method string, params i
return nil, err
}
if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
URI: protocol.NewURI(uri),
URI: protocol.URIFromSpanURI(uri),
Diagnostics: toProtocolDiagnostics(diagnostics),
Version: fileID.Version,
}); err != nil {

View File

@ -9,13 +9,12 @@ import (
"golang.org/x/tools/internal/lsp/protocol"
"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/tag"
)
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)
if err != nil {
return nil, err

View File

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

View File

@ -51,7 +51,7 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
session := cache.NewSession()
options := tests.DefaultOptions()
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 {
t.Fatal(err)
}
@ -67,7 +67,7 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
continue
}
modifications = append(modifications, source.FileModification{
URI: span.FileURI(filename),
URI: span.URIFromPath(filename),
Action: source.Open,
Version: -1,
Text: content,
@ -547,7 +547,7 @@ func (r *runner) Implementation(t *testing.T, spn span.Span, impls []span.Span)
}
var results []span.Span
for i := range locs {
locURI := span.NewURI(locs[i].URI)
locURI := locs[i].URI.SpanURI()
lm, err := r.data.Mapper(locURI)
if err != nil {
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) {
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 {
return mappedRange{}, err
}
@ -631,7 +631,7 @@ func findPosInPackage(v View, searchpkg Package, pos token.Pos) (*ast.File, Pack
if tok == nil {
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 (
ph ParseGoHandle

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@ import (
func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error {
_, err := s.didModifyFiles(ctx, []source.FileModification{
{
URI: span.NewURI(params.TextDocument.URI),
URI: params.TextDocument.URI.SpanURI(),
Action: source.Open,
Version: params.TextDocument.Version,
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 {
uri := span.NewURI(params.TextDocument.URI)
uri := params.TextDocument.URI.SpanURI()
text, err := s.changedText(ctx, uri, params.ContentChanges)
if err != nil {
return err
@ -66,7 +66,7 @@ func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.Did
var modifications []source.FileModification
for _, change := range params.Changes {
modifications = append(modifications, source.FileModification{
URI: span.NewURI(change.URI),
URI: change.URI.SpanURI(),
Action: changeTypeToFileAction(change.Type),
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 {
c := source.FileModification{
URI: span.NewURI(params.TextDocument.URI),
URI: params.TextDocument.URI.SpanURI(),
Action: source.Save,
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 {
_, err := s.didModifyFiles(ctx, []source.FileModification{
{
URI: span.NewURI(params.TextDocument.URI),
URI: params.TextDocument.URI.SpanURI(),
Action: source.Close,
Version: -1,
Text: nil,

View File

@ -11,7 +11,7 @@ import (
)
// 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
// different string.
func Parse(input string) Span {
@ -32,12 +32,12 @@ func Parse(input string) Span {
}
switch {
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 == "-":
// we have a span, fall out of the case to continue
default:
// 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
// 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 != ":" {
// 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
hold = suf.num
suf = rstripSuffix(suf.remains)
if suf.sep != ":" {
// 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
if !hadCol {
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 {

View File

@ -14,7 +14,6 @@ import (
)
var (
formats = []string{"%v", "%#v", "%+v"}
tests = [][]string{
{"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"},
@ -30,7 +29,7 @@ var (
func TestFormat(t *testing.T) {
converter := lines(10)
for _, test := range tests {
for ti, text := range test {
for ti, text := range test[:2] {
spn := span.Parse(text)
if ti <= 1 {
// 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 {
return Span{}, err
}
s.v.URI = FileURI(startFilename)
s.v.URI = URIFromPath(startFilename)
if r.End.IsValid() {
var endFilename string
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{
span.New(span.FileURI("/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.FileURI("/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("/a.go"), span.NewPoint(1, 1, 0), span.Point{}),
span.New(span.URIFromPath("/a.go"), span.NewPoint(3, 7, 20), span.NewPoint(3, 7, 20)),
span.New(span.URIFromPath("/b.go"), span.NewPoint(4, 9, 15), span.NewPoint(4, 13, 19)),
span.New(span.URIFromPath("/c.go"), span.NewPoint(4, 1, 26), span.Point{}),
}
func TestToken(t *testing.T) {
@ -44,7 +44,7 @@ func TestToken(t *testing.T) {
for _, f := range testdata {
file := fset.AddFile(f.uri, -1, len(f.content))
file.SetLinesForContent(f.content)
files[span.FileURI(f.uri)] = file
files[span.URIFromPath(f.uri)] = file
}
for _, test := range tokenTests {
f := files[test.URI()]

View File

@ -49,28 +49,26 @@ func filename(uri URI) (string, error) {
return u.Path, nil
}
// NewURI returns a span URI for the string.
// It will attempt to detect if the string is a file path or uri.
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:///") {
func URIFromURI(s string) URI {
if !strings.HasPrefix(s, "file:///") {
return URI(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(s[i+2:i+5]) == "%3a" {
s = s[:i+2] + ":" + s[i+5:]
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(s[i:]) {
s = s[:i+1] + strings.ToUpper(string(s[i+1])) + s[i+2:]
if isWindowsDriveURIPath(path) {
path = path[:1] + strings.ToUpper(string(path[1])) + path[2:]
}
return URI(s)
}
return FileURI(s)
return URI("file://" + path)
}
func CompareURI(a, b URI) int {
@ -111,9 +109,9 @@ func equalURI(a, b URI) bool {
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.
func FileURI(path string) URI {
func URIFromPath(path string) URI {
if path == "" {
return ""
}

View File

@ -16,7 +16,7 @@ import (
// include Windows-style URIs and filepaths, but we avoid having OS-specific
// tests by using only forward slashes, assuming that the standard library
// functions filepath.ToSlash and filepath.FromSlash do not need testing.
func TestURI(t *testing.T) {
func TestURIFromPath(t *testing.T) {
for _, test := range []struct {
path, wantFile string
wantURI span.URI
@ -56,25 +56,42 @@ func TestURI(t *testing.T) {
wantFile: `C:/Go/src/bob george/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 {
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()
if gotFilename != test.wantFile {

View File

@ -16,7 +16,7 @@ import (
// include Windows-style URIs and filepaths, but we avoid having OS-specific
// tests by using only forward slashes, assuming that the standard library
// functions filepath.ToSlash and filepath.FromSlash do not need testing.
func TestURI(t *testing.T) {
func TestURIFromPath(t *testing.T) {
for _, test := range []struct {
path, wantFile string
wantURI span.URI
@ -56,28 +56,46 @@ func TestURI(t *testing.T) {
wantFile: `C:\Go\src\bob george\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`,
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`,
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`,
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 {
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 {
t.Errorf("Filename: got %s, expected %s", got.Filename(), test.wantFile)
gotFilename := got.Filename()
if gotFilename != test.wantFile {
t.Errorf("Filename(%q): got %q, expected %q", got, gotFilename, test.wantFile)
}
}
}