зеркало из https://github.com/golang/tools.git
gopls/internal/golang: factor the 3 web reports
This change factors the common elements of the three reports: - the common CSS and JS, previously constants, are now assets; only the ad hoc styles particular to each page remain in the HTML. - The disconnect banner element is now created on load, in common.js, so no <div> HTML is required. - objHTML, sourceLink are factored out. Also: - use the same font-families as pkg.go.dev. - use addEventListener instead of clobbering window.onload. Change-Id: Ic21cc46fc8d92a94b78aa1faf5b2f3012f539e57 Reviewed-on: https://go-review.googlesource.com/c/tools/+/591355 Auto-Submit: 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>
This commit is contained in:
Родитель
f41a407b04
Коммит
413a491271
|
@ -50,7 +50,6 @@ func AssemblyHTML(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Pack
|
|||
escape := html.EscapeString
|
||||
|
||||
// Produce the report.
|
||||
// TODO(adonovan): factor with RenderPkgDoc, FreeSymbolsHTML
|
||||
title := fmt.Sprintf("%s assembly for %s",
|
||||
escape(snapshot.View().GOARCH()),
|
||||
escape(symbol))
|
||||
|
@ -59,31 +58,11 @@ func AssemblyHTML(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Pack
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>` + pkgDocStyle + `</style>
|
||||
<title>` + escape(title) + `</title>
|
||||
<script type='text/javascript'>
|
||||
// httpGET requests a URL for its effects only.
|
||||
function httpGET(url) {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
return false; // disable usual <a href=...> behavior
|
||||
}
|
||||
|
||||
// Start a GET /hang request. If it ever completes, the server
|
||||
// has disconnected. Show a banner in that case.
|
||||
{
|
||||
var x = new XMLHttpRequest();
|
||||
x.open("GET", "/hang", true);
|
||||
x.onloadend = () => {
|
||||
document.getElementById("disconnected").style.display = 'block';
|
||||
};
|
||||
x.send();
|
||||
};
|
||||
</script>
|
||||
<link rel="stylesheet" href="/assets/common.css">
|
||||
<script src="/assets/common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id='disconnected'>Gopls server has terminated. Page is inactive.</div>
|
||||
<h1>` + title + `</h1>
|
||||
<p>
|
||||
<a href='https://go.dev/doc/asm'>A Quick Guide to Go's Assembler</a>
|
||||
|
@ -101,18 +80,6 @@ function httpGET(url) {
|
|||
<pre>
|
||||
`)
|
||||
|
||||
// sourceLink returns HTML for a link to open a file in the client editor.
|
||||
// TODO(adonovan): factor with two other copies.
|
||||
sourceLink := func(text, url string) string {
|
||||
// The /open URL returns nothing but has the side effect
|
||||
// of causing the LSP client to open the requested file.
|
||||
// So we use onclick to prevent the browser from navigating.
|
||||
// We keep the href attribute as it causes the <a> to render
|
||||
// as a link: blue, underlined, with URL hover information.
|
||||
return fmt.Sprintf(`<a href="%[1]s" onclick='return httpGET("%[1]s")'>%[2]s</a>`,
|
||||
escape(url), text)
|
||||
}
|
||||
|
||||
// insnRx matches an assembly instruction line.
|
||||
// Submatch groups are: (offset-hex-dec, file-line-column, instruction).
|
||||
insnRx := regexp.MustCompile(`^(\s+0x[0-9a-f ]+)\(([^)]*)\)\s+(.*)$`)
|
||||
|
@ -145,7 +112,7 @@ function httpGET(url) {
|
|||
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, web.OpenURL(file, linenum, 1))
|
||||
link = sourceLink(text, web.SrcURL(file, linenum, 1))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(&buf, "%s\t%s\t%s", escape(parts[1]), link, escape(parts[3]))
|
||||
|
|
|
@ -161,40 +161,11 @@ func FreeSymbolsHTML(viewID string, pkg *cache.Package, pgf *parsego.File, start
|
|||
.col-local { color: #0cb7c9 }
|
||||
li { font-family: monospace; }
|
||||
p { max-width: 6in; }
|
||||
#disconnected {
|
||||
position: fixed;
|
||||
top: 1em;
|
||||
left: 1em;
|
||||
display: none; /* initially */
|
||||
background-color: white;
|
||||
border: thick solid red;
|
||||
padding: 2em;
|
||||
}
|
||||
</style>
|
||||
<!-- TODO(adonovan): factor with RenderPackageDoc -->
|
||||
<script type='text/javascript'>
|
||||
// httpGET requests a URL for its effects only.
|
||||
function httpGET(url) {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
return false; // disable usual <a href=...> behavior
|
||||
}
|
||||
|
||||
// Start a GET /hang request. If it ever completes, the server
|
||||
// has disconnected. Show a banner in that case.
|
||||
{
|
||||
var x = new XMLHttpRequest();
|
||||
x.open("GET", "/hang", true);
|
||||
x.onloadend = () => {
|
||||
document.getElementById("disconnected").style.display = 'block';
|
||||
};
|
||||
x.send();
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/common.js"></script>
|
||||
<link rel="stylesheet" href="/assets/common.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id='disconnected'>Gopls server has terminated. Page is inactive.</div>
|
||||
<h1>Free symbols</h1>
|
||||
<p>
|
||||
The selected code contains references to these free* symbols:
|
||||
|
@ -219,28 +190,6 @@ function httpGET(url) {
|
|||
}
|
||||
buf.WriteString("</ul>\n")
|
||||
|
||||
// sourceLink returns HTML for a link to open a file in the client editor.
|
||||
// TODO(adonovan): factor with RenderPackageDoc.
|
||||
sourceLink := func(text, url string) string {
|
||||
// The /open URL returns nothing but has the side effect
|
||||
// of causing the LSP client to open the requested file.
|
||||
// So we use onclick to prevent the browser from navigating.
|
||||
// We keep the href attribute as it causes the <a> to render
|
||||
// as a link: blue, underlined, with URL hover information.
|
||||
return fmt.Sprintf(`<a href="%[1]s" onclick='return httpGET("%[1]s")'>%[2]s</a>`,
|
||||
html.EscapeString(url), text)
|
||||
}
|
||||
|
||||
// objHTML returns HTML for obj.Name(), possibly as a link.
|
||||
// TODO(adonovan): factor with RenderPackageDoc.
|
||||
objHTML := func(obj types.Object) string {
|
||||
text := obj.Name()
|
||||
if posn := safetoken.StartPosition(pkg.FileSet(), obj.Pos()); posn.IsValid() {
|
||||
return sourceLink(text, web.OpenURL(posn.Filename, posn.Line, posn.Column))
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
// -- package and local symbols --
|
||||
|
||||
showSymbols := func(scope, title string, symbols []Symbol) {
|
||||
|
@ -253,7 +202,7 @@ function httpGET(url) {
|
|||
if i > 0 {
|
||||
buf.WriteByte('.')
|
||||
}
|
||||
buf.WriteString(objHTML(obj))
|
||||
buf.WriteString(objHTML(pkg.FileSet(), web, obj))
|
||||
}
|
||||
fmt.Fprintf(&buf, " %s</li>\n", html.EscapeString(sym.Type))
|
||||
}
|
||||
|
@ -452,3 +401,26 @@ func freeRefs(pkg *types.Package, info *types.Info, file *ast.File, start, end t
|
|||
ast.Inspect(path[0], visit)
|
||||
return free
|
||||
}
|
||||
|
||||
// objHTML returns HTML for obj.Name(), possibly marked up as a link
|
||||
// to the web server that, when visited, opens the declaration in the
|
||||
// client editor.
|
||||
func objHTML(fset *token.FileSet, web Web, obj types.Object) string {
|
||||
text := obj.Name()
|
||||
if posn := safetoken.StartPosition(fset, obj.Pos()); posn.IsValid() {
|
||||
url := web.SrcURL(posn.Filename, posn.Line, posn.Column)
|
||||
return sourceLink(text, url)
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
// sourceLink returns HTML for a link to open a file in the client editor.
|
||||
func sourceLink(text, url string) string {
|
||||
// The /src URL returns nothing but has the side effect
|
||||
// of causing the LSP client to open the requested file.
|
||||
// So we use onclick to prevent the browser from navigating.
|
||||
// We keep the href attribute as it causes the <a> to render
|
||||
// as a link: blue, underlined, with URL hover information.
|
||||
return fmt.Sprintf(`<a href="%[1]s" onclick='return httpGET("%[1]s")'>%[2]s</a>`,
|
||||
html.EscapeString(url), text)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package golang
|
|||
// - list promoted methods---we have type information!
|
||||
// - gather Example tests, following go/doc and pkgsite.
|
||||
// - add option for doc.AllDecls: show non-exported symbols too.
|
||||
// - abbreviate long signatures by replacing parameters 4 onwards with "...".
|
||||
// - style the <li> bullets in the index as invisible.
|
||||
// - add push notifications such as didChange -> reload.
|
||||
// - there appears to be a maximum file size beyond which the
|
||||
|
@ -25,9 +24,9 @@ package golang
|
|||
// - modify JS httpGET function to give a transient visual indication
|
||||
// when clicking a source link that the editor is being navigated
|
||||
// (in case it doesn't raise itself, like VS Code).
|
||||
// - move this into a new package, golang/pkgdoc, and then
|
||||
// - move this into a new package, golang/web, and then
|
||||
// split out the various helpers without fear of polluting
|
||||
// the golang package namespace.
|
||||
// the golang package namespace?
|
||||
// - show "Deprecated" chip when appropriate.
|
||||
|
||||
import (
|
||||
|
@ -58,8 +57,8 @@ type Web interface {
|
|||
// PkgURL forms URLs of package or symbol documentation.
|
||||
PkgURL(viewID string, path PackagePath, fragment string) 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
|
||||
// SrcURL forms URLs that cause the editor to open a file at a specific position.
|
||||
SrcURL(filename string, line, col8 int) protocol.URI
|
||||
}
|
||||
|
||||
// PackageDocHTML formats the package documentation page.
|
||||
|
@ -199,39 +198,40 @@ func PackageDocHTML(viewID string, pkg *cache.Package, web Web) ([]byte, error)
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>` + pkgDocStyle + `</style>
|
||||
<title>` + title + `</title>
|
||||
<script type='text/javascript'>
|
||||
// httpGET requests a URL for its effects only.
|
||||
function httpGET(url) {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
return false; // disable usual <a href=...> behavior
|
||||
<link rel="stylesheet" href="/assets/common.css">
|
||||
<script src="/assets/common.js"></script>
|
||||
<style>
|
||||
.lit { color: darkgreen; }
|
||||
|
||||
header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
#pkgsite { height: 1.5em; }
|
||||
|
||||
#hdr-Selector {
|
||||
margin-right: 0.3em;
|
||||
float: right;
|
||||
min-width: 25em;
|
||||
padding: 0.3em;
|
||||
}
|
||||
</style>
|
||||
<script type='text/javascript'>
|
||||
window.addEventListener('load', function() {
|
||||
// Hook up the navigation selector.
|
||||
document.getElementById('hdr-Selector').onchange = (e) => {
|
||||
window.location.href = e.target.value;
|
||||
};
|
||||
};
|
||||
|
||||
// Start a GET /hang request. If it ever completes, the server
|
||||
// has disconnected. Show a banner in that case.
|
||||
{
|
||||
var x = new XMLHttpRequest();
|
||||
x.open("GET", "/hang", true);
|
||||
x.onloadend = () => {
|
||||
document.getElementById("disconnected").style.display = 'block';
|
||||
};
|
||||
x.send();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div id='disconnected'>Gopls server has terminated. Page is inactive.</div>
|
||||
<select id='hdr-Selector'>
|
||||
<optgroup label="Documentation">
|
||||
<option label="Overview" value="#hdr-Overview"/>
|
||||
|
@ -316,26 +316,6 @@ window.onload = () => {
|
|||
|
||||
// -- main element --
|
||||
|
||||
// sourceLink returns HTML for a link to open a file in the client editor.
|
||||
sourceLink := func(text, url string) string {
|
||||
// The /open URL returns nothing but has the side effect
|
||||
// of causing the LSP client to open the requested file.
|
||||
// So we use onclick to prevent the browser from navigating.
|
||||
// We keep the href attribute as it causes the <a> to render
|
||||
// as a link: blue, underlined, with URL hover information.
|
||||
return fmt.Sprintf(`<a href="%[1]s" onclick='return httpGET("%[1]s")'>%[2]s</a>`,
|
||||
escape(url), escape(text))
|
||||
}
|
||||
|
||||
// objHTML returns HTML for obj.Name(), possibly as a link.
|
||||
objHTML := func(obj types.Object) string {
|
||||
text := obj.Name()
|
||||
if posn := safetoken.StartPosition(pkg.FileSet(), obj.Pos()); posn.IsValid() {
|
||||
return sourceLink(text, web.OpenURL(posn.Filename, posn.Line, posn.Column))
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
// nodeHTML returns HTML markup for a syntax tree.
|
||||
// It replaces referring identifiers with links,
|
||||
// and adds style spans for strings and comments.
|
||||
|
@ -613,7 +593,7 @@ window.onload = () => {
|
|||
for _, docfn := range funcs {
|
||||
obj := scope.Lookup(docfn.Name).(*types.Func)
|
||||
fmt.Fprintf(&buf, "<h3 id='%s'>func %s</h3>\n",
|
||||
docfn.Name, objHTML(obj))
|
||||
docfn.Name, objHTML(pkg.FileSet(), web, obj))
|
||||
|
||||
// decl: func F(params) results
|
||||
fmt.Fprintf(&buf, "<pre class='code'>%s</pre>\n",
|
||||
|
@ -631,7 +611,8 @@ window.onload = () => {
|
|||
tname := scope.Lookup(doctype.Name).(*types.TypeName)
|
||||
|
||||
// title and source link
|
||||
fmt.Fprintf(&buf, "<h3 id='%s'>type %s</a></h3>\n", doctype.Name, objHTML(tname))
|
||||
fmt.Fprintf(&buf, "<h3 id='%s'>type %s</a></h3>\n",
|
||||
doctype.Name, objHTML(pkg.FileSet(), web, tname))
|
||||
|
||||
// declaration
|
||||
// TODO(adonovan): excise non-exported struct fields somehow.
|
||||
|
@ -652,7 +633,7 @@ window.onload = () => {
|
|||
method, _, _ := types.LookupFieldOrMethod(tname.Type(), true, tname.Pkg(), docmethod.Name)
|
||||
fmt.Fprintf(&buf, "<h4 id='%s.%s'>func (%s) %s</h4>\n",
|
||||
doctype.Name, docmethod.Name,
|
||||
doctype.Name, objHTML(method))
|
||||
doctype.Name, objHTML(pkg.FileSet(), web, method))
|
||||
|
||||
// decl: func (x T) M(params) results
|
||||
fmt.Fprintf(&buf, "<pre class='code'>%s</pre>\n",
|
||||
|
@ -668,7 +649,7 @@ window.onload = () => {
|
|||
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), web.OpenURL(filename, 1, 1)))
|
||||
sourceLink(filepath.Base(filename), web.SrcURL(filename, 1, 1)))
|
||||
}
|
||||
|
||||
fmt.Fprintf(&buf, "</main>\n")
|
||||
|
@ -693,135 +674,3 @@ func typesSeqToSlice[T any](seq typesSeq[T]) []T {
|
|||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
// (partly taken from pkgsite's typography.css)
|
||||
const pkgDocStyle = `
|
||||
body {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.375rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
line-height: 1.25em;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: 500;
|
||||
line-height: 1.3em;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
max-width: 60rem;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
code,
|
||||
pre,
|
||||
textarea.code {
|
||||
font-family: Consolas, 'Liberation Mono', Menlo, monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
pre,
|
||||
textarea.code {
|
||||
background-color: #eee;
|
||||
border: 3px;
|
||||
border-radius: 3px
|
||||
color: black;
|
||||
overflow-x: auto;
|
||||
padding: 0.625rem;
|
||||
tab-size: 4;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
a,
|
||||
a:link,
|
||||
a:visited {
|
||||
color: rgb(0, 125, 156);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: rgb(0, 125, 156);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover > * {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.lit { color: darkgreen; }
|
||||
|
||||
#pkgsite { height: 1.5em; }
|
||||
|
||||
header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
#hdr-Selector {
|
||||
margin-right: 0.3em;
|
||||
float: right;
|
||||
min-width: 25em;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
#disconnected {
|
||||
position: fixed;
|
||||
top: 1em;
|
||||
left: 1em;
|
||||
display: none; /* initially */
|
||||
background-color: white;
|
||||
border: thick solid red;
|
||||
padding: 2em;
|
||||
}
|
||||
`
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/* Copyright 2024 The Go Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* inspired by pkg.go.dev's typography.css */
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
|
||||
font-size: 1rem;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.375rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
line-height: 1.25em;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: 500;
|
||||
line-height: 1.3em;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
max-width: 60rem;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
code,
|
||||
pre,
|
||||
textarea.code {
|
||||
font-family: Consolas, 'Liberation Mono', Menlo, monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
pre,
|
||||
textarea.code {
|
||||
background-color: #eee;
|
||||
border: 3px;
|
||||
border-radius: 3px
|
||||
color: black;
|
||||
overflow-x: auto;
|
||||
padding: 0.625rem;
|
||||
tab-size: 4;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
a,
|
||||
a:link,
|
||||
a:visited {
|
||||
color: rgb(0, 125, 156);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: rgb(0, 125, 156);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover > * {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#disconnected {
|
||||
position: fixed;
|
||||
top: 1em;
|
||||
left: 1em;
|
||||
display: none; /* initially */
|
||||
background-color: white;
|
||||
border: thick solid red;
|
||||
padding: 2em;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// httpGET requests a URL for its effects only.
|
||||
// (It is needed for /open URLs; see objHTML.)
|
||||
function httpGET(url) {
|
||||
var x = new XMLHttpRequest();
|
||||
x.open("GET", url, true);
|
||||
x.send();
|
||||
return false; // disable usual <a href=...> behavior
|
||||
}
|
||||
|
||||
// disconnect banner
|
||||
window.addEventListener('load', function() {
|
||||
// Create a hidden <div id='disconnected'> element.
|
||||
var banner = document.createElement("div");
|
||||
banner.id = "disconnected";
|
||||
banner.innerText = "Gopls server has terminated. Page is inactive.";
|
||||
document.body.appendChild(banner);
|
||||
|
||||
// Start a GET /hang request. If it ever completes, the server
|
||||
// has disconnected. Reveal the banner in that case.
|
||||
var x = new XMLHttpRequest();
|
||||
x.open("GET", "/hang", true);
|
||||
x.onloadend = () => { banner.style.display = "block"; };
|
||||
x.send();
|
||||
});
|
|
@ -286,9 +286,9 @@ func (s *server) initWeb() (*web, error) {
|
|||
mux: webMux,
|
||||
}
|
||||
|
||||
// The /open handler allows the browser to request that the
|
||||
// LSP client editor open a file; see web.urlToOpen.
|
||||
webMux.HandleFunc("/open", func(w http.ResponseWriter, req *http.Request) {
|
||||
// The /src handler allows the browser to request that the
|
||||
// LSP client editor open a file; see web.SrcURL.
|
||||
webMux.HandleFunc("/src", func(w http.ResponseWriter, req *http.Request) {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
@ -463,16 +463,16 @@ func (s *server) initWeb() (*web, error) {
|
|||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
|
||||
// OpenURL returns an /open URL that, when visited, causes the client
|
||||
// SrcURL returns a /src 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) SrcURL(filename string, line, col8 int) protocol.URI {
|
||||
return w.url(
|
||||
"open",
|
||||
"src",
|
||||
fmt.Sprintf("file=%s&line=%d&col=%d", url.QueryEscape(filename), line, col8),
|
||||
"")
|
||||
}
|
||||
|
|
|
@ -61,14 +61,14 @@ func (G[T]) F(int, int, int, int, int, int, int, ...int) {}
|
|||
// (We don't have a DOM or JS interpreter so we have
|
||||
// to know something of the document internals here.)
|
||||
rx := regexp.MustCompile(`<h3 id='NewFunc'.*httpGET\("(.*)"\)`)
|
||||
openURL := html.UnescapeString(string(rx.FindSubmatch(doc2)[1]))
|
||||
srcURL := html.UnescapeString(string(rx.FindSubmatch(doc2)[1]))
|
||||
|
||||
// Fetch the document. Its result isn't important,
|
||||
// but it must have the side effect of another showDocument
|
||||
// downcall, this time for a "file:" URL, causing the
|
||||
// client editor to navigate to the source file.
|
||||
t.Log("extracted /open URL", openURL)
|
||||
get(t, openURL)
|
||||
t.Log("extracted /src URL", srcURL)
|
||||
get(t, srcURL)
|
||||
|
||||
// Check that that shown location is that of NewFunc.
|
||||
shownSource := shownDocument(t, env, "file:")
|
||||
|
|
Загрузка…
Ссылка в новой задаче