gopls/internal/golang: Web, an abstraction of server.web This change consolidates the two func types, PosURL and PkgURL, into an interface, Web, that aligns with the server.web implementation. Also, strength-reduce PkgURL to require only a viewID, not a view (as we did for freesymbolsURL in CL 591157). Change-Id: Ic48e0d5808257934c56b31126fd4880ee88c7a33 Reviewed-on: https://go-review.googlesource.com/c/tools/+/591318 Commit-Queue: Alan Donovan <adonovan@google.com> Reviewed-by: Robert Findley <rfindley@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Alan Donovan <adonovan@google.com>
diff --git a/gopls/internal/golang/assembly.go b/gopls/internal/golang/assembly.go index cbb9512..ca9f61c 100644 --- a/gopls/internal/golang/assembly.go +++ b/gopls/internal/golang/assembly.go
@@ -30,7 +30,7 @@ // TODO(adonovan): // - display a "Compiling..." message as a cold build can be slow. // - cross-link jumps and block labels, like github.com/aclements/objbrowse. -func AssemblyHTML(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, symbol string, posURL PosURLFunc) ([]byte, error) { +func AssemblyHTML(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, symbol string, web Web) ([]byte, error) { // Compile the package with -S, and capture its stderr stream. inv, cleanupInvocation, err := snapshot.GoCommandInvocation(false, &gocommand.Invocation{ Verb: "build", @@ -145,7 +145,7 @@ if file, linenum, ok := cutLast(parts[2], ":"); ok && !strings.HasPrefix(file, "<") { if linenum, err := strconv.Atoi(linenum); err == nil { text := fmt.Sprintf("L%04d", linenum) - link = sourceLink(text, posURL(file, linenum, 1)) + link = sourceLink(text, web.OpenURL(file, linenum, 1)) } } fmt.Fprintf(&buf, "%s\t%s\t%s", escape(parts[1]), link, escape(parts[3]))
diff --git a/gopls/internal/golang/freesymbols.go b/gopls/internal/golang/freesymbols.go index 4333a85..0bf0d9c 100644 --- a/gopls/internal/golang/freesymbols.go +++ b/gopls/internal/golang/freesymbols.go
@@ -27,7 +27,7 @@ // FreeSymbolsHTML returns an HTML document containing the report of // free symbols referenced by the selection. -func FreeSymbolsHTML(pkg *cache.Package, pgf *parsego.File, start, end token.Pos, posURL PosURLFunc, pkgURL PkgURLFunc) []byte { +func FreeSymbolsHTML(viewID string, pkg *cache.Package, pgf *parsego.File, start, end token.Pos, web Web) []byte { // Compute free references. refs := freeRefs(pkg.Types(), pkg.TypesInfo(), pgf.File, start, end) @@ -210,7 +210,7 @@ fmt.Fprintf(&buf, "<ul>\n") for _, imp := range model.Imported { fmt.Fprintf(&buf, "<li>import \"<a href='%s'>%s</a>\" // for %s</li>\n", - pkgURL(imp.Path, ""), + web.PkgURL(viewID, imp.Path, ""), html.EscapeString(string(imp.Path)), strings.Join(imp.Symbols, ", ")) } @@ -236,7 +236,7 @@ objHTML := func(obj types.Object) string { text := obj.Name() if posn := safetoken.StartPosition(pkg.FileSet(), obj.Pos()); posn.IsValid() { - return sourceLink(text, posURL(posn.Filename, posn.Line, posn.Column)) + return sourceLink(text, web.OpenURL(posn.Filename, posn.Line, posn.Column)) } return text }
diff --git a/gopls/internal/golang/pkgdoc.go b/gopls/internal/golang/pkgdoc.go index c605d29..94e00be 100644 --- a/gopls/internal/golang/pkgdoc.go +++ b/gopls/internal/golang/pkgdoc.go
@@ -53,24 +53,21 @@ "golang.org/x/tools/internal/typesinternal" ) -// TODO(adonovan): factor these two functions into an interface. -type ( - // A PkgURLFunc forms URLs of package or symbol documentation. - PkgURLFunc = func(path PackagePath, fragment string) protocol.URI +// Web is an abstraction of gopls' web server. +type Web interface { + // PkgURL forms URLs of package or symbol documentation. + PkgURL(viewID string, path PackagePath, fragment string) protocol.URI - // A PosURLFunc forms URLs that cause the editor to navigate to a position. - PosURLFunc = func(filename string, line, col8 int) protocol.URI -) + // OpenURL forms URLs that cause the editor to open a file at a specific position. + OpenURL(filename string, line, col8 int) protocol.URI +} // PackageDocHTML formats the package documentation page. // // The posURL function returns a URL that when visited, has the side // effect of causing gopls to direct the client editor to navigate to // the specified file/line/column position, in UTF-8 coordinates. -// -// The pkgURL function returns a URL for the documentation of the -// specified package and symbol. -func PackageDocHTML(pkg *cache.Package, posURL PosURLFunc, pkgURL PkgURLFunc) ([]byte, error) { +func PackageDocHTML(viewID string, pkg *cache.Package, web Web) ([]byte, error) { // We can't use doc.NewFromFiles (even with doc.PreserveAST // mode) as it calls ast.NewPackage which assumes that each // ast.File has an ast.Scope and resolves identifiers to @@ -143,7 +140,7 @@ if link.Recv != "" { fragment = link.Recv + "." + link.Name } - return pkgURL(path, fragment) + return web.PkgURL(viewID, path, fragment) } parser := docpkg.Parser() parser.LookupPackage = func(name string) (importPath string, ok bool) { @@ -334,7 +331,7 @@ objHTML := func(obj types.Object) string { text := obj.Name() if posn := safetoken.StartPosition(pkg.FileSet(), obj.Pos()); posn.IsValid() { - return sourceLink(text, posURL(posn.Filename, posn.Line, posn.Column)) + return sourceLink(text, web.OpenURL(posn.Filename, posn.Line, posn.Column)) } return text } @@ -350,7 +347,7 @@ // imported package name? if pkgname, ok := obj.(*types.PkgName); ok { // TODO(adonovan): do this for Defs of PkgName too. - return pkgURL(PackagePath(pkgname.Imported().Path()), "") + return web.PkgURL(viewID, PackagePath(pkgname.Imported().Path()), "") } // package-level symbol? @@ -358,7 +355,7 @@ if obj.Pkg() == pkg.Types() { return "#" + obj.Name() // intra-package ref } else { - return pkgURL(PackagePath(obj.Pkg().Path()), obj.Name()) + return web.PkgURL(viewID, PackagePath(obj.Pkg().Path()), obj.Name()) } } @@ -369,7 +366,7 @@ _, named := typesinternal.ReceiverNamed(sig.Recv()) if named != nil { fragment := named.Obj().Name() + "." + fn.Name() - return pkgURL(PackagePath(fn.Pkg().Path()), fragment) + return web.PkgURL(viewID, PackagePath(fn.Pkg().Path()), fragment) } } return "" @@ -671,7 +668,7 @@ fmt.Fprintf(&buf, "<h2 id='hdr-SourceFiles'>Source files</h2>\n") for _, filename := range docpkg.Filenames { fmt.Fprintf(&buf, "<div class='comment'>%s</div>\n", - sourceLink(filepath.Base(filename), posURL(filename, 1, 1))) + sourceLink(filepath.Base(filename), web.OpenURL(filename, 1, 1))) } fmt.Fprintf(&buf, "</main>\n")
diff --git a/gopls/internal/server/command.go b/gopls/internal/server/command.go index 201a96d..75f5134 100644 --- a/gopls/internal/server/command.go +++ b/gopls/internal/server/command.go
@@ -571,7 +571,7 @@ } // Direct the client to open the /pkg page. - url := web.pkgURL(deps.snapshot.View(), pkgpath, fragment) + url := web.PkgURL(deps.snapshot.View().ID(), pkgpath, fragment) openClientBrowser(ctx, c.s.client, url) return nil
diff --git a/gopls/internal/server/server.go b/gopls/internal/server/server.go index 58747bb..a414942 100644 --- a/gopls/internal/server/server.go +++ b/gopls/internal/server/server.go
@@ -347,10 +347,7 @@ http.Error(w, err.Error(), http.StatusInternalServerError) return } - pkgURL := func(path golang.PackagePath, fragment string) protocol.URI { - return web.pkgURL(view, path, fragment) - } - content, err := golang.PackageDocHTML(pkgs[0], web.openURL, pkgURL) + content, err := golang.PackageDocHTML(view.ID(), pkgs[0], web) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -405,10 +402,7 @@ } // Produce report. - pkgURL := func(path golang.PackagePath, fragment string) protocol.URI { - return web.pkgURL(view, path, fragment) - } - html := golang.FreeSymbolsHTML(pkg, pgf, start, end, web.openURL, pkgURL) + html := golang.FreeSymbolsHTML(view.ID(), pkg, pgf, start, end, web) w.Write(html) }) @@ -453,7 +447,7 @@ pkg := pkgs[0] // Produce report. - html, err := golang.AssemblyHTML(ctx, snapshot, pkg, symbol, web.openURL) + html, err := golang.AssemblyHTML(ctx, snapshot, pkg, symbol, web) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -469,26 +463,26 @@ //go:embed assets/* var assets embed.FS -// openURL returns an /open URL that, when visited, causes the client +// OpenURL returns an /open URL that, when visited, causes the client // editor to open the specified file/line/column (in 1-based UTF-8 // coordinates). // // (Rendering may generate hundreds of positions across files of many // packages, so don't convert to LSP coordinates yet: wait until the // URL is opened.) -func (w *web) openURL(filename string, line, col8 int) protocol.URI { +func (w *web) OpenURL(filename string, line, col8 int) protocol.URI { return w.url( "open", fmt.Sprintf("file=%s&line=%d&col=%d", url.QueryEscape(filename), line, col8), "") } -// pkgURL returns a /pkg URL for the documentation of the specified package. +// PkgURL returns a /pkg URL for the documentation of the specified package. // The optional fragment must be of the form "Println" or "Buffer.WriteString". -func (w *web) pkgURL(v *cache.View, path golang.PackagePath, fragment string) protocol.URI { +func (w *web) PkgURL(viewID string, path golang.PackagePath, fragment string) protocol.URI { return w.url( "pkg/"+string(path), - "view="+url.QueryEscape(v.ID()), + "view="+url.QueryEscape(viewID), fragment) }