internal/godoc: clean up use of templates
- convert from text/template to html/template
- use proper template set
- always pass *godoc.Page to templates, with custom value in .Data
- move stateful site template functions to methods on *godoc.Page
- unexport Presentation.ServeFile: ServeHTTP is good enough
- reorder api.DB.Func args to match source order (pkg first)
- rename lib/godoc/godoc.html to lib/godoc/site.html
(lib/godoc itself must stay lib/godoc because of links to other content it holds).
Change-Id: I873f17db20107fdab11d276932e6d847a6081015
Reviewed-on: https://go-review.googlesource.com/c/website/+/317655
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/_content/doc/articles/race_detector.html b/_content/doc/articles/race_detector.html
index 09188c1..01278a2 100644
--- a/_content/doc/articles/race_detector.html
+++ b/_content/doc/articles/race_detector.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Data Race Detector",
- "Template": true
+ "Title": "Data Race Detector"
}-->
<h2 id="Introduction">Introduction</h2>
diff --git a/_content/doc/code.html b/_content/doc/code.html
index 99a1729..1f020c9 100644
--- a/_content/doc/code.html
+++ b/_content/doc/code.html
@@ -183,7 +183,7 @@
<pre>
# Windows users should consult https://github.com/golang/go/wiki/SettingGOPATH
# for setting %PATH%.
-$ <b>export PATH=$PATH:$(dirname $(go list -f '{{"{{"}}.Target{{"}}"}}' .))</b>
+$ <b>export PATH=$PATH:$(dirname $(go list -f '{{"{{.Target}}"}}' .))</b>
$ <b>hello</b>
Hello, world.
$
diff --git a/_content/doc/diagnostics.html b/_content/doc/diagnostics.html
index 438cdce..c97140a 100644
--- a/_content/doc/diagnostics.html
+++ b/_content/doc/diagnostics.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Diagnostics",
- "Template": true
+ "Title": "Diagnostics"
}-->
<!--
diff --git a/_content/doc/editors.html b/_content/doc/editors.html
index e0d0c53..0ba8836 100644
--- a/_content/doc/editors.html
+++ b/_content/doc/editors.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Editor plugins and IDEs",
- "Template": true
+ "Title": "Editor plugins and IDEs"
}-->
<h2 id="introduction">Introduction</h2>
diff --git a/_content/doc/effective_go.html b/_content/doc/effective_go.html
index 3db4d1b..f2f056d 100644
--- a/_content/doc/effective_go.html
+++ b/_content/doc/effective_go.html
@@ -3638,13 +3638,13 @@
form value.
Within the template text (<code>templateStr</code>),
double-brace-delimited pieces denote template actions.
-The piece from <code>{{html "{{if .}}"}}</code>
-to <code>{{html "{{end}}"}}</code> executes only if the value of the current data item, called <code>.</code> (dot),
+The piece from <code>{{"{{if .}}"}}</code>
+to <code>{{"{{end}}"}}</code> executes only if the value of the current data item, called <code>.</code> (dot),
is non-empty.
That is, when the string is empty, this piece of the template is suppressed.
</p>
<p>
-The two snippets <code>{{html "{{.}}"}}</code> say to show the data presented to
+The two snippets <code>{{"{{.}}"}}</code> say to show the data presented to
the template—the query string—on the web page.
The HTML template package automatically provides appropriate escaping so the
text is safe to display.
diff --git a/_content/doc/go1.1.html b/_content/doc/go1.1.html
index a1130c0..edda047 100644
--- a/_content/doc/go1.1.html
+++ b/_content/doc/go1.1.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.1 Release Notes",
- "Template": true
+ "Title": "Go 1.1 Release Notes"
}-->
<h2 id="introduction">Introduction to Go 1.1</h2>
diff --git a/_content/doc/go1.10.html b/_content/doc/go1.10.html
index 0445026..5201e4a 100644
--- a/_content/doc/go1.10.html
+++ b/_content/doc/go1.10.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.10 Release Notes",
- "Template": true
+ "Title": "Go 1.10 Release Notes"
}-->
<!--
diff --git a/_content/doc/go1.11.html b/_content/doc/go1.11.html
index fad1e0d..b513890 100644
--- a/_content/doc/go1.11.html
+++ b/_content/doc/go1.11.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.11 Release Notes",
- "Template": true
+ "Title": "Go 1.11 Release Notes"
}-->
<!--
@@ -907,11 +906,11 @@
Modifying template variables via assignments is now permitted via the <code>=</code> token:
</p>
<pre>
- {{"{{"}} $v := "init" {{"}}"}}
- {{"{{"}} if true {{"}}"}}
- {{"{{"}} $v = "changed" {{"}}"}}
- {{"{{"}} end {{"}}"}}
- v: {{"{{"}} $v {{"}}"}} {{"{{"}}/* "changed" */{{"}}"}}</pre>
+ {{ $v := "init" }}
+ {{ if true }}
+ {{ $v = "changed" }}
+ {{ end }}
+ v: {{ $v }} {{/* "changed" */}}</pre>
<p><!-- CL 95215 -->
In previous versions untyped <code>nil</code> values passed to
diff --git a/_content/doc/go1.12.html b/_content/doc/go1.12.html
index c3181e0..21d77f1 100644
--- a/_content/doc/go1.12.html
+++ b/_content/doc/go1.12.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.12 Release Notes",
- "Template": true
+ "Title": "Go 1.12 Release Notes"
}-->
<!--
diff --git a/_content/doc/go1.13.html b/_content/doc/go1.13.html
index 6bbc84e..af1d8bb 100644
--- a/_content/doc/go1.13.html
+++ b/_content/doc/go1.13.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.13 Release Notes",
- "Template": true
+ "Title": "Go 1.13 Release Notes"
}-->
<!--
diff --git a/_content/doc/go1.2.html b/_content/doc/go1.2.html
index acc4436..aa05934 100644
--- a/_content/doc/go1.2.html
+++ b/_content/doc/go1.2.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.2 Release Notes",
- "Template": true
+ "Title": "Go 1.2 Release Notes"
}-->
<h2 id="introduction">Introduction to Go 1.2</h2>
@@ -554,7 +553,7 @@
</p>
<pre>
-{{"{{"}}if eq .A 1 2 3 {{"}}"}} equal {{"{{"}}else{{"}}"}} not equal {{"{{"}}end{{"}}"}}
+{{if eq .A 1 2 3}} equal {{else}} not equal {{end}}
</pre>
<p>
@@ -567,7 +566,7 @@
</p>
<pre>
-{{"{{"}}if eq .A 1{{"}}"}} X {{"{{"}}else{{"}}"}} {{"{{"}}if eq .A 2{{"}}"}} Y {{"{{"}}end{{"}}"}} {{"{{"}}end{{"}}"}}
+{{if eq .A 1}} X {{else}} {{if eq .A 2}} Y {{end}} {{end}}
</pre>
<p>
@@ -575,7 +574,7 @@
</p>
<pre>
-{{"{{"}}if eq .A 1{{"}}"}} X {{"{{"}}else if eq .A 2{{"}}"}} Y {{"{{"}}end{{"}}"}}
+{{if eq .A 1}} X {{else if eq .A 2}} Y {{end}}
</pre>
<p>
diff --git a/_content/doc/go1.3.html b/_content/doc/go1.3.html
index 57d1d7f..8edb6ee 100644
--- a/_content/doc/go1.3.html
+++ b/_content/doc/go1.3.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.3 Release Notes",
- "Template": true
+ "Title": "Go 1.3 Release Notes"
}-->
<h2 id="introduction">Introduction to Go 1.3</h2>
diff --git a/_content/doc/go1.4.html b/_content/doc/go1.4.html
index 0233ad4..1c306f6 100644
--- a/_content/doc/go1.4.html
+++ b/_content/doc/go1.4.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.4 Release Notes",
- "Template": true
+ "Title": "Go 1.4 Release Notes"
}-->
<h2 id="introduction">Introduction to Go 1.4</h2>
diff --git a/_content/doc/go1.5.html b/_content/doc/go1.5.html
index d9529f2..bd7517c 100644
--- a/_content/doc/go1.5.html
+++ b/_content/doc/go1.5.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.5 Release Notes",
- "Template": true
+ "Title": "Go 1.5 Release Notes"
}-->
diff --git a/_content/doc/go1.6.html b/_content/doc/go1.6.html
index 2f7093d..edf89d2 100644
--- a/_content/doc/go1.6.html
+++ b/_content/doc/go1.6.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.6 Release Notes",
- "Template": true
+ "Title": "Go 1.6 Release Notes"
}-->
<!--
@@ -443,9 +442,9 @@
</p>
<pre>
-{{"{{"}}23 -}}
+{{23 -}}
<
-{{"{{"}}- 45}}
+{{- 45}}
</pre>
<p>
@@ -453,7 +452,7 @@
</p>
<p>
-Second, the new <a href="/pkg/text/template/#hdr-Actions"><code>{{"{{"}}block}}</code> action</a>,
+Second, the new <a href="/pkg/text/template/#hdr-Actions"><code>{{block}}</code> action</a>,
combined with allowing redefinition of named templates,
provides a simple way to define pieces of a template that
can be replaced in different instantiations.
diff --git a/_content/doc/go1.7.html b/_content/doc/go1.7.html
index 2138871..79236d6 100644
--- a/_content/doc/go1.7.html
+++ b/_content/doc/go1.7.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.7 Release Notes",
- "Template": true
+ "Title": "Go 1.7 Release Notes"
}-->
<!--
diff --git a/_content/doc/go1.8.html b/_content/doc/go1.8.html
index adb8991..56290f0 100644
--- a/_content/doc/go1.8.html
+++ b/_content/doc/go1.8.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.8 Release Notes",
- "Template": true
+ "Title": "Go 1.8 Release Notes"
}-->
<!--
diff --git a/_content/doc/go1.9.html b/_content/doc/go1.9.html
index ddd310f..374ac35 100644
--- a/_content/doc/go1.9.html
+++ b/_content/doc/go1.9.html
@@ -1,6 +1,5 @@
<!--{
- "Title": "Go 1.9 Release Notes",
- "Template": true
+ "Title": "Go 1.9 Release Notes"
}-->
<!--
diff --git a/_content/lib/godoc/codewalk.html b/_content/lib/godoc/codewalk.html
index 0f3d22a..89360bf 100644
--- a/_content/lib/godoc/codewalk.html
+++ b/_content/lib/godoc/codewalk.html
@@ -4,6 +4,7 @@
license that can be found in the LICENSE file.
-->
+{{with .Data}}
<style type='text/css'>@import "/doc/codewalk/codewalk.css";</style>
<script type="text/javascript" src="/doc/codewalk/codewalk.js"></script>
@@ -17,7 +18,7 @@
</a>
<select id="code-selector">
{{range .File}}
- <option value="/doc/codewalk/?fileprint=/{{urlquery .}}">{{html .}}</option>
+ <option value="/doc/codewalk/?fileprint=/{{.}}">{{.}}</option>
{{end}}
</select>
</div>
@@ -35,15 +36,15 @@
<div id="comment-area">
{{range .Step}}
<div class="comment first last">
- <a class="comment-link" href="/doc/codewalk/?fileprint=/{{urlquery .File}}&lo={{urlquery .Lo}}&hi={{urlquery .Hi}}#mark" target="code-display"></a>
- <div class="comment-title">{{html .Title}}</div>
+ <a class="comment-link" href="/doc/codewalk/?fileprint=/{{.File}}&lo={{.Lo}}&hi={{.Hi}}#mark" target="code-display"></a>
+ <div class="comment-title">{{.Title}}</div>
<div class="comment-text">
{{with .Err}}
- ERROR LOADING FILE: {{html .}}<br/><br/>
+ ERROR LOADING FILE: {{.}}<br/><br/>
{{end}}
- {{.XML}}
+ {{.HTML}}
</div>
- <div class="comment-text file-name"><span class="path-file">{{html .}}</span></div>
+ <div class="comment-text file-name"><span class="path-file">{{.}}</span></div>
</div>
{{end}}
</div>
@@ -54,3 +55,4 @@
</div>
</div>
</div>
+{{end}}
diff --git a/_content/lib/godoc/codewalkdir.html b/_content/lib/godoc/codewalkdir.html
index b7674c6..5479429 100644
--- a/_content/lib/godoc/codewalkdir.html
+++ b/_content/lib/godoc/codewalkdir.html
@@ -5,12 +5,11 @@
-->
<table class="layout">
-{{range .}}
+{{range .Data}}
<tr>
- {{$name_html := html .Name}}
- <td><a href="{{$name_html}}">{{$name_html}}</a></td>
+ <td><a href="{{.Name}}">{{.Name}}</a></td>
<td width="25"> </td>
- <td>{{html .Title}}</td>
+ <td>{{.Title}}</td>
</tr>
{{end}}
</table>
diff --git a/_content/lib/godoc/dirlist.html b/_content/lib/godoc/dirlist.html
index 78530e6..6f32403 100644
--- a/_content/lib/godoc/dirlist.html
+++ b/_content/lib/godoc/dirlist.html
@@ -4,6 +4,7 @@
license that can be found in the LICENSE file.
-->
+{{with .Data}}
<p>
<table class="layout">
<tr>
@@ -15,11 +16,12 @@
<td><a href="../">../</a></td>
</tr>
{{range .}}{{if .IsDir}}
- <tr><td align="left"><a href="{{html .Name}}/">{{html .Name}}/</a><td></tr>
+ <tr><td align="left"><a href="{{.Name}}/">{{.Name}}/</a><td></tr>
{{end}}{{end}}
{{range .}}{{if not .IsDir}}
- <tr><td align="left"><a href="{{html .Name}}">{{html .Name}}</a><td align="right">{{html .Size}}</tr>
+ <tr><td align="left"><a href="{{.Name}}">{{.Name}}</a><td align="right">{{.Size}}</tr>
{{end}}{{end}}
</table>
</p>
+{{end}}
diff --git a/_content/lib/godoc/error.html b/_content/lib/godoc/error.html
index 7573aa2..cb5325e 100644
--- a/_content/lib/godoc/error.html
+++ b/_content/lib/godoc/error.html
@@ -4,6 +4,8 @@
license that can be found in the LICENSE file.
-->
+{{with .Data}}
<p>
-<span class="alert" style="font-size:120%">{{html .}}</span>
+<span class="alert" style="font-size:120%">{{.}}</span>
</p>
+{{end}}
diff --git a/_content/lib/godoc/example.html b/_content/lib/godoc/example.html
index bde02c6..aef6edb 100644
--- a/_content/lib/godoc/example.html
+++ b/_content/lib/godoc/example.html
@@ -1,14 +1,15 @@
+{{with .Data}}
<div id="example_{{.Name}}" class="toggle">
<div class="collapsed">
<p class="exampleHeading toggleButton">▹ <span class="text">Example{{example_suffix .Name}}</span></p>
</div>
<div class="expanded">
<p class="exampleHeading toggleButton">▾ <span class="text">Example{{example_suffix .Name}}</span></p>
- {{with .Doc}}<p>{{html .}}</p>{{end}}
+ {{with .Doc}}<p>{{.}}</p>{{end}}
{{$output := .Output}}
{{with .Play}}
<div class="play">
- <div class="input"><textarea class="code" spellcheck="false">{{html .}}</textarea></div>
+ <div class="input"><textarea class="code" spellcheck="false">{{.}}</textarea></div>
<div class="output"><pre>{{html $output}}</pre></div>
<div class="buttons">
<button class="Button Button--primary run" title="Run this code [shift-enter]">Run</button>
@@ -23,8 +24,9 @@
<pre class="code">{{.Code}}</pre>
{{with .Output}}
<p>Output:</p>
- <pre class="output">{{html .}}</pre>
+ <pre class="output">{{.}}</pre>
{{end}}
{{end}}
</div>
</div>
+{{end}}
diff --git a/_content/lib/godoc/godocs.js b/_content/lib/godoc/godocs.js
index 68e2a89..e581cb3 100644
--- a/_content/lib/godoc/godocs.js
+++ b/_content/lib/godoc/godocs.js
@@ -372,7 +372,7 @@
personalizeInstallInstructions();
updateVersionTags();
- // godoc.html defines window.initFuncs in the <head> tag, and root.html and
+ // site.html defines window.initFuncs in the <head> tag, and root.html and
// codewalk.js push their on-page-ready functions to the list.
// We execute those functions here, to avoid loading jQuery until the page
// content is loaded.
diff --git a/_content/lib/godoc/package.html b/_content/lib/godoc/package.html
index 9f0c879..3d6e8ba 100644
--- a/_content/lib/godoc/package.html
+++ b/_content/lib/godoc/package.html
@@ -9,23 +9,24 @@
them to conflict with generated attributes (some of which
correspond to Go identifiers).
-->
-{{with .PDoc}}
- {{if $.IsMain}}
+{{$pkg := .Data}}
+{{with $pkg.PDoc}}
+ {{if $pkg.IsMain}}
{{/* command documentation */}}
- {{comment_html .Doc}}
+ {{$.Comment .Doc}}
{{else}}
{{/* package documentation */}}
<div id="short-nav">
<dl>
- <dd><code>import "{{html .ImportPath}}"</code></dd>
+ <dd><code>import "{{.ImportPath}}"</code></dd>
</dl>
<dl>
<dd><a href="#pkg-overview" class="overviewLink">Overview</a></dd>
<dd><a href="#pkg-index" class="indexLink">Index</a></dd>
- {{if $.Examples}}
+ {{if $pkg.Examples}}
<dd><a href="#pkg-examples" class="examplesLink">Examples</a></dd>
{{end}}
- {{if $.Dirs}}
+ {{if $pkg.Dirs}}
<dd><a href="#pkg-subdirectories">Subdirectories</a></dd>
{{end}}
</dl>
@@ -37,8 +38,8 @@
</div>
<div class="expanded">
<h2 class="toggleButton" title="Click to hide Overview section">Overview ▾</h2>
- {{comment_html .Doc}}
- {{example_html $ ""}}
+ {{$.Comment .Doc}}
+ {{$.Example ""}}
</div>
</div>
@@ -59,33 +60,30 @@
<dd><a href="#pkg-variables">Variables</a></dd>
{{end}}
{{range .Funcs}}
- {{$name_html := html .Name}}
- <dd><a href="#{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ <dd><a href="#{{.Name}}">{{$.NodeTOC .Decl}}</a></dd>
{{end}}
{{range .Types}}
- {{$tname_html := html .Name}}
- <dd><a href="#{{$tname_html}}">type {{$tname_html}}</a></dd>
+ {{$typeName := .Name}}
+ <dd><a href="#{{.Name}}">type {{.Name}}</a></dd>
{{range .Funcs}}
- {{$name_html := html .Name}}
- <dd> <a href="#{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ <dd> <a href="#{{.Name}}">{{$.NodeTOC .Decl}}</a></dd>
{{end}}
{{range .Methods}}
- {{$name_html := html .Name}}
- <dd> <a href="#{{$tname_html}}.{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ <dd> <a href="#{{$typeName}}.{{.Name}}">{{$.NodeTOC .Decl}}</a></dd>
{{end}}
{{end}}
- {{if $.Bugs}}
+ {{if $pkg.Bugs}}
<dd><a href="#pkg-note-BUG">Bugs</a></dd>
{{end}}
</dl>
</div><!-- #manual-nav -->
- {{if $.Examples}}
+ {{if $pkg.Examples}}
<div id="pkg-examples">
<h3>Examples</h3>
<div class="js-expandAll expandAll collapsed">(Expand All)</div>
<dl>
- {{range $.Examples}}
+ {{range $pkg.Examples}}
<dd><a class="exampleLink" href="#example_{{.Name}}">{{example_name .Name}}</a></dd>
{{end}}
</dl>
@@ -97,7 +95,7 @@
<p>
<span style="font-size:90%">
{{range .}}
- <a href="{{.|srcLink|html}}">{{.|filename|html}}</a>
+ <a href="/src/{{.}}">{{basename .}}</a>
{{end}}
</span>
</p>
@@ -108,93 +106,87 @@
{{with .Consts}}
<h2 id="pkg-constants">Constants</h2>
{{range .}}
- {{comment_html .Doc}}
- <pre>{{node_html $ .Decl true}}</pre>
+ {{$.Comment .Doc}}
+ <pre>{{$.Node .Decl}}</pre>
{{end}}
{{end}}
{{with .Vars}}
<h2 id="pkg-variables">Variables</h2>
{{range .}}
- {{comment_html .Doc}}
- <pre>{{node_html $ .Decl true}}</pre>
+ {{$.Comment .Doc}}
+ <pre>{{$.Node .Decl}}</pre>
{{end}}
{{end}}
{{range .Funcs}}
{{/* Name is a string - no need for FSet */}}
- {{$name_html := html .Name}}
- <h2 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a>
- <a class="permalink" href="#{{$name_html}}">¶</a>
- {{$since := since "func" "" .Name $.PDoc.ImportPath}}
+ <h2 id="{{.Name}}">func <a href="{{$.SrcPosLink .Decl}}">{{.Name}}</a>
+ <a class="permalink" href="#{{.Name}}">¶</a>
+ {{$since := $.Since "func" "" .Name}}
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
</h2>
- <pre>{{node_html $ .Decl true}}</pre>
- {{comment_html .Doc}}
- {{example_html $ .Name}}
-
+ <pre>{{$.Node .Decl}}</pre>
+ {{$.Comment .Doc}}
+ {{$.Example .Name}}
{{end}}
{{range .Types}}
- {{$tname := .Name}}
- {{$tname_html := html .Name}}
- <h2 id="{{$tname_html}}">type <a href="{{posLink_url $ .Decl}}">{{$tname_html}}</a>
- <a class="permalink" href="#{{$tname_html}}">¶</a>
- {{$since := since "type" "" .Name $.PDoc.ImportPath}}
+ {{$typeName := .Name}}
+ <h2 id="{{.Name}}">type <a href="{{$.SrcPosLink .Decl}}">{{$typeName}}</a>
+ <a class="permalink" href="#{{.Name}}">¶</a>
+ {{$since := $.Since "type" "" .Name}}
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
</h2>
- {{comment_html .Doc}}
- <pre>{{node_html $ .Decl true}}</pre>
+ {{$.Comment .Doc}}
+ <pre>{{$.Node .Decl}}</pre>
{{range .Consts}}
- {{comment_html .Doc}}
- <pre>{{node_html $ .Decl true}}</pre>
+ {{$.Comment .Doc}}
+ <pre>{{$.Node .Decl}}</pre>
{{end}}
{{range .Vars}}
- {{comment_html .Doc}}
- <pre>{{node_html $ .Decl true}}</pre>
+ {{$.Comment .Doc}}
+ <pre>{{$.Node .Decl}}</pre>
{{end}}
- {{example_html $ $tname}}
+ {{$.Example .Name}}
{{range .Funcs}}
- {{$name_html := html .Name}}
- <h3 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a>
- <a class="permalink" href="#{{$name_html}}">¶</a>
- {{$since := since "func" "" .Name $.PDoc.ImportPath}}
+ <h3 id="{{.Name}}">func <a href="{{$.SrcPosLink .Decl}}">{{.Name}}</a>
+ <a class="permalink" href="#{{.Name}}">¶</a>
+ {{$since := $.Since "func" "" .Name}}
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
</h3>
- <pre>{{node_html $ .Decl true}}</pre>
- {{comment_html .Doc}}
- {{example_html $ .Name}}
+ <pre>{{$.Node .Decl}}</pre>
+ {{$.Comment .Doc}}
+ {{$.Example .Name}}
{{end}}
{{range .Methods}}
- {{$name_html := html .Name}}
- <h3 id="{{$tname_html}}.{{$name_html}}">func ({{html .Recv}}) <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a>
- <a class="permalink" href="#{{$tname_html}}.{{$name_html}}">¶</a>
- {{$since := since "method" .Recv .Name $.PDoc.ImportPath}}
+ <h3 id="{{$typeName}}.{{.Name}}">func ({{html .Recv}}) <a href="{{$.SrcPosLink .Decl}}">{{.Name}}</a>
+ <a class="permalink" href="#{{$typeName}}.{{.Name}}">¶</a>
+ {{$since := $.Since "method" .Recv .Name}}
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
</h3>
- <pre>{{node_html $ .Decl true}}</pre>
- {{comment_html .Doc}}
- {{$name := printf "%s_%s" $tname .Name}}
- {{example_html $ $name}}
+ <pre>{{$.Node .Decl}}</pre>
+ {{$.Comment .Doc}}
+ {{$.Example (printf "%s_%s" $typeName .Name)}}
{{end}}
{{end}}
{{end}}
- {{with $.Bugs}}
+ {{with $pkg.Bugs}}
<h2 id="pkg-note-BUG">Bugs</h2>
<ul style="list-style: none; padding: 0;">
{{range .}}
- <li><a href="{{posLink_url $ .}}" style="float: left;">☞</a> {{comment_html .Body}}</li>
+ <li><a href="{{$.SrcPosLink .}}" style="float: left;">☞</a> {{$.Comment .Body}}</li>
{{end}}
</ul>
{{end}}
{{end}}
-{{with .Dirs}}
+{{with $pkg.Dirs}}
{{/* DirList entries are numbers and strings - no need for FSet */}}
- {{if $.PDoc}}
+ {{if $pkg.PDoc}}
<h2 id="pkg-subdirectories">Subdirectories</h2>
{{end}}
<div class="pkg-dir">
@@ -204,7 +196,7 @@
<th class="pkg-synopsis">Synopsis</th>
</tr>
- {{if not (or (eq $.Dirname "/src/cmd") $.DirFlat)}}
+ {{if not (or (eq $pkg.Dirname "/src/cmd") $pkg.DirFlat)}}
<tr>
<td colspan="2"><a href="..">..</a></td>
</tr>
@@ -212,19 +204,19 @@
{{range .List}}
<tr>
- {{if $.DirFlat}}
+ {{if $pkg.DirFlat}}
{{if .HasPkg}}
<td class="pkg-name">
- <a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
+ <a href="{{.Path}}/{{$.ModeQuery}}">{{.Path}}</a>
</td>
{{end}}
{{else}}
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
- <a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
+ <a href="{{.Path}}/{{$.ModeQuery}}">{{.Name}}</a>
</td>
{{end}}
<td class="pkg-synopsis">
- {{html .Synopsis}}
+ {{.Synopsis}}
</td>
</tr>
{{end}}
diff --git a/_content/lib/godoc/packageroot.html b/_content/lib/godoc/packageroot.html
index 5727926..218c845 100644
--- a/_content/lib/godoc/packageroot.html
+++ b/_content/lib/godoc/packageroot.html
@@ -9,10 +9,11 @@
them to conflict with generated attributes (some of which
correspond to Go identifiers).
-->
+{{$pkg := .Data}}
-{{with .Dirs}}
+{{with $pkg.Dirs}}
{{/* DirList entries are numbers and strings - no need for FSet */}}
- {{if $.PDoc}}
+ {{if $pkg.PDoc}}
<h2 id="pkg-subdirectories">Subdirectories</h2>
{{end}}
<div id="manual-nav">
@@ -40,19 +41,19 @@
{{range .List}}
<tr>
- {{if $.DirFlat}}
+ {{if $pkg.DirFlat}}
{{if .HasPkg}}
<td class="pkg-name">
- <a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Path}}</a>
+ <a href="{{.Path}}/{{$.ModeQuery}}">{{.Path}}</a>
</td>
{{end}}
{{else}}
<td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
- <a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .Name}}</a>
+ <a href="{{.Path}}/{{$.ModeQuery}}">{{.Name}}</a>
</td>
{{end}}
<td class="pkg-synopsis">
- {{html .Synopsis}}
+ {{.Synopsis}}
</td>
</tr>
{{end}}
diff --git a/_content/lib/godoc/godoc.html b/_content/lib/godoc/site.html
similarity index 93%
rename from _content/lib/godoc/godoc.html
rename to _content/lib/godoc/site.html
index f1d14e4..2f3e496 100644
--- a/_content/lib/godoc/godoc.html
+++ b/_content/lib/godoc/site.html
@@ -4,8 +4,8 @@
<meta name="description" content="Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#00ADD8">
-{{with .Tabtitle}}
- <title>{{html .}} - The Go Programming Language</title>
+{{with .TabTitle}}
+ <title>{{.}} - The Go Programming Language</title>
{{else}}
<title>The Go Programming Language</title>
{{end}}
@@ -63,18 +63,18 @@
{{if or .Title .SrcPath}}
<h1>
- {{html .Title}}
- {{html .SrcPath | srcBreadcrumb}}
+ {{.Title}}
+ {{$.SrcBreadcrumb}}
</h1>
{{end}}
{{with .Subtitle}}
- <h2>{{html .}}</h2>
+ <h2>{{.}}</h2>
{{end}}
{{with .SrcPath}}
<h2>
- Documentation: {{html . | srcToPkgLink}}
+ Documentation: {{$.SrcPkgLink}}
</h2>
{{end}}
@@ -82,8 +82,11 @@
Do not delete this <div>. */}}
<div id="nav"></div>
-{{/* Body is HTML-escaped elsewhere */}}
-{{printf "%s" .Body}}
+{{if .Template}}
+{{.Invoke .Template .Data}}
+{{else}}
+{{.Data}}
+{{end}}
</div><!-- .container -->
</main><!-- #page -->
@@ -108,4 +111,3 @@
})();
</script>
{{end}}
-
diff --git a/cmd/golangorg/codewalk.go b/cmd/golangorg/codewalk.go
index b571343..d8d2284 100644
--- a/cmd/golangorg/codewalk.go
+++ b/cmd/golangorg/codewalk.go
@@ -16,10 +16,10 @@
package main
import (
- "bytes"
"encoding/xml"
"errors"
"fmt"
+ "html/template"
"io"
"io/fs"
"log"
@@ -30,14 +30,11 @@
"sort"
"strconv"
"strings"
- "text/template"
"unicode/utf8"
"golang.org/x/website/internal/godoc"
)
-var codewalkHTML, codewalkdirHTML *template.Template
-
// Handler for /doc/codewalk/ and below.
func codewalk(w http.ResponseWriter, r *http.Request) {
relpath := r.URL.Path[len("/doc/codewalk/"):]
@@ -58,7 +55,7 @@
// If file exists, serve using standard file server.
if err == nil {
- pres.ServeFile(w, r)
+ pres.ServeHTTP(w, r)
return
}
@@ -69,7 +66,7 @@
cw, err := loadCodewalk(abspath + ".xml")
if err != nil {
log.Print(err)
- pres.ServeError(w, r, relpath, err)
+ pres.ServeError(w, r, err)
return
}
@@ -78,10 +75,11 @@
return
}
- pres.ServePage(w, godoc.Page{
+ pres.ServePage(w, r, godoc.Page{
Title: "Codewalk: " + cw.Title,
- Tabtitle: cw.Title,
- Body: applyTemplate(codewalkHTML, "codewalk", cw),
+ TabTitle: cw.Title,
+ Template: "codewalk.html",
+ Data: cw,
})
}
@@ -99,14 +97,6 @@
return
}
-func applyTemplate(t *template.Template, name string, data interface{}) []byte {
- var buf bytes.Buffer
- if err := t.Execute(&buf, data); err != nil {
- log.Printf("%s.Execute: %s", name, err)
- }
- return buf.Bytes()
-}
-
// A Codewalk represents a single codewalk read from an XML file.
type Codewalk struct {
Title string `xml:"title,attr"`
@@ -131,6 +121,10 @@
Data []byte
}
+func (c *Codestep) HTML() template.HTML {
+ return template.HTML(c.XML)
+}
+
// String method for printing in template.
// Formats file address nicely.
func (st *Codestep) String() string {
@@ -217,7 +211,7 @@
dir, err := fs.ReadDir(fsys, toFS(abspath))
if err != nil {
log.Print(err)
- pres.ServeError(w, r, relpath, err)
+ pres.ServeError(w, r, err)
return
}
var v []interface{}
@@ -234,9 +228,10 @@
}
}
- pres.ServePage(w, godoc.Page{
- Title: "Codewalks",
- Body: applyTemplate(codewalkdirHTML, "codewalkdir", v),
+ pres.ServePage(w, r, godoc.Page{
+ Title: "Codewalks",
+ Template: "codewalkdir.html",
+ Data: v,
})
}
@@ -251,7 +246,7 @@
data, err := fs.ReadFile(fsys, toFS(abspath))
if err != nil {
log.Print(err)
- pres.ServeError(w, r, f, err)
+ pres.ServeError(w, r, err)
return
}
lo, _ := strconv.Atoi(r.FormValue("lo"))
diff --git a/cmd/golangorg/handlers.go b/cmd/golangorg/handlers.go
index 28a3b80..1ee843d 100644
--- a/cmd/golangorg/handlers.go
+++ b/cmd/golangorg/handlers.go
@@ -11,7 +11,6 @@
"encoding/json"
"go/format"
"io/fs"
- "log"
"net/http"
pathpkg "path"
"strings"
@@ -93,16 +92,6 @@
return mux
}
-func readTemplates(p *godoc.Presentation) {
- var err error
- if codewalkHTML, err = p.ReadTemplate("codewalk.html"); err != nil {
- log.Fatal(err)
- }
- if codewalkdirHTML, err = p.ReadTemplate("codewalkdir.html"); err != nil {
- log.Fatal(err)
- }
-}
-
type fmtResponse struct {
Body string
Error string
diff --git a/cmd/golangorg/local.go b/cmd/golangorg/local.go
index 37353b3..ba00aaa 100644
--- a/cmd/golangorg/local.go
+++ b/cmd/golangorg/local.go
@@ -27,7 +27,7 @@
os.Exit(2)
}
dir := filepath.Join(file, "../../../_content")
- if _, err := os.Stat(filepath.Join(dir, "lib/godoc/godoc.html")); err != nil {
+ if _, err := os.Stat(filepath.Join(dir, "lib/godoc/site.html")); err != nil {
log.Printf("warning: cannot find template dir; using embedded copy")
return
}
diff --git a/cmd/golangorg/main.go b/cmd/golangorg/main.go
index 283f4e0..9c20031 100644
--- a/cmd/golangorg/main.go
+++ b/cmd/golangorg/main.go
@@ -85,7 +85,6 @@
}
pres.GoogleCN = googleCN
- readTemplates(pres)
mux := registerHandlers(pres)
lateSetup(mux)
diff --git a/cmd/golangorg/release_test.go b/cmd/golangorg/release_test.go
index 4b19884..5c6a574 100644
--- a/cmd/golangorg/release_test.go
+++ b/cmd/golangorg/release_test.go
@@ -32,7 +32,6 @@
if err != nil {
t.Fatal(err)
}
- readTemplates(pres)
mux := registerHandlers(pres)
req := httptest.NewRequest(http.MethodGet, "/doc/devel/release", nil)
diff --git a/internal/api/api.go b/internal/api/api.go
index a9669f2..7fcb23d 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -51,7 +51,7 @@
//
// The name is the symbol name ("Server") and the pkg is the package
// ("net/http").
-func (v DB) Func(kind, receiver, name, pkg string) string {
+func (v DB) Func(pkg, kind, receiver, name string) string {
pv := v[pkg]
switch kind {
case "func":
diff --git a/internal/api/api_test.go b/internal/api/api_test.go
index 64c8800..ced9aa4 100644
--- a/internal/api/api_test.go
+++ b/internal/api/api_test.go
@@ -137,8 +137,8 @@
if tc.want != "" && !hasTag("go"+tc.want) {
continue
}
- if got := av.Func(tc.kind, tc.receiver, tc.name, tc.pkg); got != tc.want {
- t.Errorf(`sinceFunc("%s", "%s", "%s", "%s") = "%s"; want "%s"`, tc.kind, tc.receiver, tc.name, tc.pkg, got, tc.want)
+ if got := av.Func(tc.pkg, tc.kind, tc.receiver, tc.name); got != tc.want {
+ t.Errorf(`sinceFunc(%q, %q, %q, %q) = %q; want %q`, tc.pkg, tc.kind, tc.receiver, tc.name, got, tc.want)
}
}
}
diff --git a/internal/godoc/astfuncs.go b/internal/godoc/astfuncs.go
index f6cafd4..e21b52a 100644
--- a/internal/godoc/astfuncs.go
+++ b/internal/godoc/astfuncs.go
@@ -14,6 +14,7 @@
"go/doc"
"go/printer"
"go/token"
+ "html/template"
"io"
"log"
"unicode"
@@ -25,26 +26,36 @@
var slashSlash = []byte("//")
-func (p *Presentation) nodeFunc(info *pkgdoc.Page, node interface{}) string {
- var buf bytes.Buffer
- p.writeNode(&buf, info, info.FSet, node)
- return buf.String()
-}
-
-func (p *Presentation) node_htmlFunc(info *pkgdoc.Page, node interface{}, linkify bool) string {
+// Node formats the given AST node as HTML.
+// Identifiers in the rendered node
+// are turned into links to their documentation.
+func (p *Page) Node(node interface{}) template.HTML {
+ info := p.Data.(*pkgdoc.Page)
var buf1 bytes.Buffer
- p.writeNode(&buf1, info, info.FSet, node)
+ p.pres.writeNode(&buf1, info, info.FSet, node)
var buf2 bytes.Buffer
- var n ast.Node
- if linkify {
- n, _ = node.(ast.Node)
- }
+ n, _ := node.(ast.Node)
buf2.Write(texthtml.Format(buf1.Bytes(), texthtml.Config{
AST: n,
GoComments: true,
}))
- return buf2.String()
+ return template.HTML(buf2.String())
+}
+
+// NodeTOC formats the given AST node as HTML
+// for inclusion in the table of contents.
+func (p *Page) NodeTOC(node interface{}) template.HTML {
+ info := p.Data.(*pkgdoc.Page)
+ var buf1 bytes.Buffer
+ p.pres.writeNode(&buf1, info, info.FSet, node)
+
+ var buf2 bytes.Buffer
+ buf2.Write(texthtml.Format(buf1.Bytes(), texthtml.Config{
+ GoComments: true,
+ }))
+
+ return sanitize(template.HTML(buf2.String()))
}
const TabWidth = 4
@@ -140,18 +151,19 @@
return string(x[:i])
}
-func comment_htmlFunc(comment string) string {
+// Comment formats the given documentation comment as HTML.
+func (p *Page) Comment(comment string) template.HTML {
var buf bytes.Buffer
// TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML.
doc.ToHTML(&buf, comment, nil) // does html-escaping
- return buf.String()
+ return template.HTML(buf.String())
}
-// sanitizeFunc sanitizes the argument src by replacing newlines with
+// sanitize sanitizes the argument src by replacing newlines with
// blanks, removing extra blanks, and by removing trailing whitespace
// and commas before closing parentheses.
-func sanitizeFunc(src string) string {
+func sanitize(src template.HTML) template.HTML {
buf := make([]byte, len(src))
j := 0 // buf index
comma := -1 // comma index if >= 0
@@ -189,5 +201,13 @@
if j > 0 && buf[j-1] == ' ' {
j--
}
- return string(buf[:j])
+ return template.HTML(buf[:j])
+}
+
+// Since reports the Go version that introduced the API feature
+// identified by kind, reeciver, name.
+// The current package is deduced from p.Data, which must be a *pkgdoc.Page.
+func (p *Page) Since(kind, receiver, name string) string {
+ pkg := p.Data.(*pkgdoc.Page).PDoc.ImportPath
+ return p.pres.api.Func(pkg, kind, receiver, name)
}
diff --git a/internal/godoc/examplefuncs.go b/internal/godoc/examplefuncs.go
index 3d10fc1..67099ec 100644
--- a/internal/godoc/examplefuncs.go
+++ b/internal/godoc/examplefuncs.go
@@ -12,6 +12,7 @@
"go/ast"
"go/format"
"go/printer"
+ "html/template"
"log"
"regexp"
"strings"
@@ -20,7 +21,10 @@
"golang.org/x/website/internal/pkgdoc"
)
-func (p *Presentation) example_htmlFunc(info *pkgdoc.Page, funcName string) string {
+// Example renders the examples for the given function name as HTML.
+// The current package is deduced from p.Data, which must be a *pkgdoc.Page.
+func (p *Page) Example(funcName string) template.HTML {
+ info := p.Data.(*pkgdoc.Page)
var buf bytes.Buffer
for _, eg := range info.Examples {
name := pkgdoc.TrimExampleSuffix(eg.Name)
@@ -31,7 +35,7 @@
// print code
cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
- code := p.node_htmlFunc(info, cnode, true)
+ code := string(p.Node(cnode))
out := eg.Output
wholeFile := true
@@ -66,20 +70,23 @@
out = ""
}
- if p.ExampleHTML == nil {
- out = ""
+ t := p.pres.Templates.Lookup("example.html")
+ if t == nil {
return ""
}
- err := p.ExampleHTML.Execute(&buf, struct {
+ newPage := *p
+ newPage.Data = struct {
Name, Doc, Code, Play, Output string
- GoogleCN bool
- }{eg.Name, eg.Doc, code, play, out, info.GoogleCN})
+ }{
+ eg.Name, eg.Doc, code, play, out,
+ }
+ err := t.Execute(&buf, &newPage)
if err != nil {
log.Print(err)
}
}
- return buf.String()
+ return template.HTML(buf.String())
}
// replaceLeadingIndentation replaces oldIndent at the beginning of each line
@@ -190,7 +197,7 @@
// example_nameFunc takes an example function name and returns its display
// name. For example, "Foo_Bar_quux" becomes "Foo.Bar (Quux)".
-func (p *Presentation) example_nameFunc(s string) string {
+func example_nameFunc(s string) string {
name, suffix := pkgdoc.SplitExampleName(s)
// replace _ with . for method names
name = strings.Replace(name, "_", ".", 1)
@@ -203,7 +210,7 @@
// example_suffixFunc takes an example function name and returns its suffix in
// parenthesized form. For example, "Foo_Bar_quux" becomes " (Quux)".
-func (p *Presentation) example_suffixFunc(name string) string {
+func example_suffixFunc(name string) string {
_, suffix := pkgdoc.SplitExampleName(name)
return suffix
}
diff --git a/internal/godoc/godoc.go b/internal/godoc/godoc.go
index 33bd631..7e6f989 100644
--- a/internal/godoc/godoc.go
+++ b/internal/godoc/godoc.go
@@ -13,67 +13,35 @@
"go/ast"
"go/doc"
"go/token"
+ "html"
+ "html/template"
"path"
- "strconv"
"strings"
- "text/template"
"golang.org/x/website/internal/history"
"golang.org/x/website/internal/pkgdoc"
)
func (p *Presentation) initFuncMap() {
- // Template function maps.
- // Convention: template function names ending in "_html" or "_url" produce
- // HTML- or URL-escaped strings; all other function results may
- // require explicit escaping in the template.
-
- p.DocFuncs = template.FuncMap{
+ p.docFuncs = template.FuncMap{
"code": p.code,
"releases": func() []*history.Major { return history.Majors },
}
-
- p.SiteFuncs = template.FuncMap{
- // various helpers
- "filename": filenameFunc,
- "since": p.api.Func,
-
- // formatting of AST nodes
- "node": p.nodeFunc,
- "node_html": p.node_htmlFunc,
- "comment_html": comment_htmlFunc,
- "sanitize": sanitizeFunc,
-
- // support for URL attributes
- "pkgLink": pkgLinkFunc,
- "srcLink": srcLinkFunc,
- "posLink_url": posLink_urlFunc,
- "docLink": docLinkFunc,
- "queryLink": queryLinkFunc,
- "srcBreadcrumb": srcBreadcrumbFunc,
- "srcToPkgLink": srcToPkgLinkFunc,
-
- // formatting of Examples
- "example_html": p.example_htmlFunc,
- "example_name": p.example_nameFunc,
- "example_suffix": p.example_suffixFunc,
-
- // Number operation
- "multiply": multiply,
-
- // formatting of PageInfoMode query string
- "modeQueryString": modeQueryString,
- }
}
-func multiply(a, b int) int { return a * b }
+var siteFuncs = template.FuncMap{
+ // various helpers
+ "basename": path.Base,
-func filenameFunc(name string) string {
- _, localname := path.Split(name)
- return localname
+ // formatting of Examples
+ "example_name": example_nameFunc,
+ "example_suffix": example_suffixFunc,
+
+ // Number operation
+ "multiply": func(a, b int) int { return a * b },
}
-func pkgLinkFunc(path string) string {
+func srcToPkg(path string) string {
// because of the irregular mapping under goroot
// we need to correct certain relative paths
path = strings.TrimPrefix(path, "/")
@@ -82,26 +50,26 @@
return "pkg/" + path
}
-// srcToPkgLinkFunc builds an <a> tag linking to the package
-// documentation of relpath.
-func srcToPkgLinkFunc(relpath string) string {
- relpath = pkgLinkFunc(relpath)
- relpath = path.Dir(relpath)
- if relpath == "pkg" {
+// SrcPkgLink builds an <a> tag linking to the package documentation
+// for p.SrcPath.
+func (p *Page) SrcPkgLink() template.HTML {
+ dir := path.Dir(srcToPkg(p.SrcPath))
+ if dir == "pkg" {
return `<a href="/pkg">Index</a>`
}
- return fmt.Sprintf(`<a href="/%s">%s</a>`, relpath, relpath[len("pkg/"):])
+ dir = html.EscapeString(dir)
+ return template.HTML(fmt.Sprintf(`<a href="/%s">%s</a>`, dir, dir[len("pkg/"):]))
}
-// srcBreadcrumbFun converts each segment of relpath to a HTML <a>.
+// SrcBreadcrumb converts each segment of p.SrcPath to a HTML <a>.
// Each segment links to its corresponding src directories.
-func srcBreadcrumbFunc(relpath string) string {
- segments := strings.Split(relpath, "/")
+func (p *Page) SrcBreadcrumb() template.HTML {
+ segments := strings.Split(p.SrcPath, "/")
var buf bytes.Buffer
var selectedSegment string
var selectedIndex int
- if strings.HasSuffix(relpath, "/") {
+ if strings.HasSuffix(p.SrcPath, "/") {
// relpath is a directory ending with a "/".
// Selected segment is the segment before the last slash.
selectedIndex = len(segments) - 2
@@ -113,18 +81,22 @@
for i := range segments[:selectedIndex] {
buf.WriteString(fmt.Sprintf(`<a href="/%s">%s</a>/`,
- strings.Join(segments[:i+1], "/"),
- segments[i],
+ html.EscapeString(strings.Join(segments[:i+1], "/")),
+ html.EscapeString(segments[i]),
))
}
buf.WriteString(`<span class="text-muted">`)
- buf.WriteString(selectedSegment)
+ buf.WriteString(html.EscapeString(selectedSegment))
buf.WriteString(`</span>`)
- return buf.String()
+ return template.HTML(buf.String())
}
-func posLink_urlFunc(info *pkgdoc.Page, n interface{}) string {
+// SrcPosLink returns a link to the specific source code position containing n,
+// which must be either an ast.Node or a *doc.Note.
+// The current package is deduced from p.Data, which must be a *pkgdoc.Page.
+func (p *Page) SrcPosLink(n interface{}) template.HTML {
+ info := p.Data.(*pkgdoc.Page)
// n must be an ast.Node or a *doc.Note
var pos, end token.Pos
@@ -136,7 +108,7 @@
pos = n.Pos
end = n.End
default:
- panic(fmt.Sprintf("wrong type for posLink_url template formatter: %T", n))
+ panic(fmt.Sprintf("wrong type for SrcPosLink template formatter: %T", n))
}
var relpath string
@@ -156,8 +128,11 @@
return srcPosLinkFunc(relpath, line, low, high)
}
-func srcPosLinkFunc(s string, line, low, high int) string {
- s = srcLinkFunc(s)
+func srcPosLinkFunc(s string, line, low, high int) template.HTML {
+ s = path.Clean("/" + s)
+ if !strings.HasPrefix(s, "/src/") {
+ s = "/src" + s
+ }
var buf bytes.Buffer
template.HTMLEscape(&buf, []byte(s))
// selection ranges are of form "s=low:high"
@@ -175,30 +150,5 @@
if line > 0 {
fmt.Fprintf(&buf, "#L%d", line) // no need for URL escaping
}
- return buf.String()
-}
-
-func srcLinkFunc(s string) string {
- s = path.Clean("/" + s)
- if !strings.HasPrefix(s, "/src/") {
- s = "/src" + s
- }
- return s
-}
-
-// queryLinkFunc returns a URL for a line in a source file with a highlighted
-// query term.
-// s is expected to be a path to a source file.
-// query is expected to be a string that has already been appropriately escaped
-// for use in a URL query.
-func queryLinkFunc(s, query string, line int) string {
- url := path.Clean("/"+s) + "?h=" + query
- if line > 0 {
- url += "#L" + strconv.Itoa(line)
- }
- return url
-}
-
-func docLinkFunc(s string, ident string) string {
- return path.Clean("/pkg/"+s) + "/#" + ident
+ return template.HTML(buf.String())
}
diff --git a/internal/godoc/godoc_test.go b/internal/godoc/godoc_test.go
index 74e472c..eba1bd0 100644
--- a/internal/godoc/godoc_test.go
+++ b/internal/godoc/godoc_test.go
@@ -12,13 +12,14 @@
"fmt"
"go/parser"
"go/token"
+ "html/template"
"strings"
"testing"
"golang.org/x/website/internal/pkgdoc"
)
-func TestPkgLinkFunc(t *testing.T) {
+func TestSrcToPkg(t *testing.T) {
for _, tc := range []struct {
path string
want string
@@ -27,9 +28,11 @@
{"src/fmt", "pkg/fmt"},
{"/fmt", "pkg/fmt"},
{"fmt", "pkg/fmt"},
+ {"src/pkg/fmt", "pkg/fmt"},
+ {"/src/pkg/fmt", "pkg/fmt"},
} {
- if got := pkgLinkFunc(tc.path); got != tc.want {
- t.Errorf("pkgLinkFunc(%v) = %v; want %v", tc.path, got, tc.want)
+ if got := srcToPkg(tc.path); got != tc.want {
+ t.Errorf("srcToPkg(%v) = %v; want %v", tc.path, got, tc.want)
}
}
}
@@ -40,7 +43,7 @@
line int
low int
high int
- want string
+ want template.HTML
}{
{"/src/fmt/print.go", 42, 30, 50, "/src/fmt/print.go?s=30:50#L32"},
{"/src/fmt/print.go", 2, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
@@ -51,64 +54,15 @@
{"fmt/print.go", 0, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
} {
if got := srcPosLinkFunc(tc.src, tc.line, tc.low, tc.high); got != tc.want {
- t.Errorf("srcLinkFunc(%v, %v, %v, %v) = %v; want %v", tc.src, tc.line, tc.low, tc.high, got, tc.want)
+ t.Errorf("srcPosLink(%v, %v, %v, %v) = %v; want %v", tc.src, tc.line, tc.low, tc.high, got, tc.want)
}
}
}
-func TestSrcLinkFunc(t *testing.T) {
+func TestSanitize(t *testing.T) {
for _, tc := range []struct {
- src string
- want string
- }{
- {"/src/fmt/print.go", "/src/fmt/print.go"},
- {"src/fmt/print.go", "/src/fmt/print.go"},
- {"/fmt/print.go", "/src/fmt/print.go"},
- {"fmt/print.go", "/src/fmt/print.go"},
- } {
- if got := srcLinkFunc(tc.src); got != tc.want {
- t.Errorf("srcLinkFunc(%v) = %v; want %v", tc.src, got, tc.want)
- }
- }
-}
-
-func TestQueryLinkFunc(t *testing.T) {
- for _, tc := range []struct {
- src string
- query string
- line int
- want string
- }{
- {"/src/fmt/print.go", "Sprintf", 33, "/src/fmt/print.go?h=Sprintf#L33"},
- {"/src/fmt/print.go", "Sprintf", 0, "/src/fmt/print.go?h=Sprintf"},
- {"src/fmt/print.go", "EOF", 33, "/src/fmt/print.go?h=EOF#L33"},
- {"src/fmt/print.go", "a%3f+%26b", 1, "/src/fmt/print.go?h=a%3f+%26b#L1"},
- } {
- if got := queryLinkFunc(tc.src, tc.query, tc.line); got != tc.want {
- t.Errorf("queryLinkFunc(%v, %v, %v) = %v; want %v", tc.src, tc.query, tc.line, got, tc.want)
- }
- }
-}
-
-func TestDocLinkFunc(t *testing.T) {
- for _, tc := range []struct {
- src string
- ident string
- want string
- }{
- {"fmt", "Sprintf", "/pkg/fmt/#Sprintf"},
- {"fmt", "EOF", "/pkg/fmt/#EOF"},
- } {
- if got := docLinkFunc(tc.src, tc.ident); got != tc.want {
- t.Errorf("docLinkFunc(%v, %v) = %v; want %v", tc.src, tc.ident, got, tc.want)
- }
- }
-}
-
-func TestSanitizeFunc(t *testing.T) {
- for _, tc := range []struct {
- src string
- want string
+ src template.HTML
+ want template.HTML
}{
{},
{"foo", "foo"},
@@ -121,8 +75,8 @@
{"{ a, b}", "{a, b}"},
{"[ a, b]", "[a, b]"},
} {
- if got := sanitizeFunc(tc.src); got != tc.want {
- t.Errorf("sanitizeFunc(%v) = %v; want %v", tc.src, got, tc.want)
+ if got := sanitize(tc.src); got != tc.want {
+ t.Errorf("sanitize(%v) = %v; want %v", tc.src, got, tc.want)
}
}
}
@@ -241,11 +195,15 @@
pi := &pkgdoc.Page{
FSet: fset,
}
+ pg := &Page{
+ pres: p,
+ Data: pi,
+ }
sep := ""
for _, decl := range af.Decls {
buf.WriteString(sep)
sep = "\n"
- buf.WriteString(p.node_htmlFunc(pi, decl, true))
+ buf.WriteString(string(pg.Node(decl)))
}
return buf.String()
}
@@ -279,29 +237,29 @@
func TestSrcBreadcrumbFunc(t *testing.T) {
for _, tc := range []struct {
path string
- want string
+ want template.HTML
}{
{"src/", `<span class="text-muted">src/</span>`},
{"src/fmt/", `<a href="/src">src</a>/<span class="text-muted">fmt/</span>`},
{"src/fmt/print.go", `<a href="/src">src</a>/<a href="/src/fmt">fmt</a>/<span class="text-muted">print.go</span>`},
} {
- if got := srcBreadcrumbFunc(tc.path); got != tc.want {
+ if got := (&Page{SrcPath: tc.path}).SrcBreadcrumb(); got != tc.want {
t.Errorf("srcBreadcrumbFunc(%v) = %v; want %v", tc.path, got, tc.want)
}
}
}
-func TestSrcToPkgLinkFunc(t *testing.T) {
+func TestSrcPkgLink(t *testing.T) {
for _, tc := range []struct {
path string
- want string
+ want template.HTML
}{
{"src/", `<a href="/pkg">Index</a>`},
{"src/fmt/", `<a href="/pkg/fmt">fmt</a>`},
{"pkg/", `<a href="/pkg">Index</a>`},
{"pkg/LICENSE", `<a href="/pkg">Index</a>`},
} {
- if got := srcToPkgLinkFunc(tc.path); got != tc.want {
+ if got := (&Page{SrcPath: tc.path}).SrcPkgLink(); got != tc.want {
t.Errorf("srcToPkgLinkFunc(%v) = %v; want %v", tc.path, got, tc.want)
}
}
diff --git a/internal/godoc/meta.go b/internal/godoc/meta.go
index 0c5809e..27f4def 100644
--- a/internal/godoc/meta.go
+++ b/internal/godoc/meta.go
@@ -17,7 +17,6 @@
)
var (
- doctype = []byte("<!DOCTYPE ")
jsonStart = []byte("<!--{")
jsonEnd = []byte("}-->")
)
diff --git a/internal/godoc/page.go b/internal/godoc/page.go
index 6c06ba5..9426dd7 100644
--- a/internal/godoc/page.go
+++ b/internal/godoc/page.go
@@ -9,50 +9,64 @@
import (
"net/http"
- "os"
- "path/filepath"
"runtime"
)
-// Page describes the contents of the top-level godoc webpage.
+// A Page describes the contents of a webpage to be served.
+//
+// A Page's Methods are for use by the templates rendering the page.
type Page struct {
- Title string
- Tabtitle string
- Subtitle string
- SrcPath string
- Query string
- Body []byte
- GoogleCN bool // page is being served from golang.google.cn
+ Title string // <h1>
+ TabTitle string // prefix in <title>; defaults to Title
+ Subtitle string // subtitle (date for spec, memory model)
+ SrcPath string // path to file in /src for text view
- // filled in by ServePage
- Version string
- GoogleAnalytics string
+ // Template and Data describe the data to be
+ // rendered into the overall site frame template.
+ // If Template is empty, then Data should be a template.HTML
+ // holding raw HTML to render into the site frame.
+ // Otherwise, Template should be the name of a template file
+ // in _content/lib/godoc (for example, "package.html"),
+ // and that template will be executed
+ // (with the *Page as its data argument) to produce HTML.
+ //
+ // The overall site template site.html is also invoked with
+ // the *Page as its data argument. It is what arranges to call Template.
+ Template string // template to apply to data (empty string when Data is raw template.HTML)
+ Data interface{} // data to be rendered into page frame
+
+ // Filled in automatically by ServePage
+ GoogleCN bool // page is being served from golang.google.cn
+ GoogleAnalytics string // Google Analytics tag
+ Version string // current Go version
+
+ pres *Presentation
}
-func (p *Presentation) ServePage(w http.ResponseWriter, page Page) {
- if page.Tabtitle == "" {
- page.Tabtitle = page.Title
+// fullPage returns a copy of page with the “automatic” fields filled in.
+func (p *Presentation) fullPage(r *http.Request, page Page) Page {
+ if page.TabTitle == "" {
+ page.TabTitle = page.Title
}
page.Version = runtime.Version()
+ page.GoogleCN = p.googleCN(r)
page.GoogleAnalytics = p.GoogleAnalytics
- applyTemplateToResponseWriter(w, p.GodocHTML, page)
+ page.pres = p
+ return page
}
-func (p *Presentation) ServeError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
+// ServePage responds to the request with the content described by page.
+func (p *Presentation) ServePage(w http.ResponseWriter, r *http.Request, page Page) {
+ page = p.fullPage(r, page)
+ applyTemplateToResponseWriter(w, p.Templates.Lookup("site.html"), &page)
+}
+
+// ServeError responds to the request with the given error.
+func (p *Presentation) ServeError(w http.ResponseWriter, r *http.Request, err error) {
w.WriteHeader(http.StatusNotFound)
- if perr, ok := err.(*os.PathError); ok {
- rel, err := filepath.Rel(runtime.GOROOT(), perr.Path)
- if err != nil {
- perr.Path = "REDACTED"
- } else {
- perr.Path = filepath.Join("$GOROOT", rel)
- }
- }
- p.ServePage(w, Page{
- Title: "File " + relpath,
- Subtitle: relpath,
- Body: applyTemplate(p.ErrorHTML, "errorHTML", err),
- GoogleCN: p.googleCN(r),
- GoogleAnalytics: p.GoogleAnalytics,
+ p.ServePage(w, r, Page{
+ Title: r.URL.Path,
+ Template: "error.html",
+ Data: err,
})
}
diff --git a/internal/godoc/pres.go b/internal/godoc/pres.go
index b60e9b6..51928c4 100644
--- a/internal/godoc/pres.go
+++ b/internal/godoc/pres.go
@@ -8,15 +8,15 @@
package godoc
import (
+ "html/template"
"io/fs"
"net/http"
- "text/template"
"golang.org/x/website/internal/api"
"golang.org/x/website/internal/pkgdoc"
)
-// Presentation generates output from a file system.
+// Presentation is a website served from a file system.
type Presentation struct {
fs fs.FS
api api.DB
@@ -24,12 +24,7 @@
mux *http.ServeMux
fileServer http.Handler
- DirlistHTML,
- ErrorHTML,
- ExampleHTML,
- GodocHTML,
- PackageHTML,
- PackageRootHTML *template.Template
+ Templates *template.Template
// GoogleCN reports whether this request should be marked GoogleCN.
// If the function is nil, no requests are marked GoogleCN.
@@ -39,8 +34,7 @@
// tracking ID to each page.
GoogleAnalytics string
- DocFuncs template.FuncMap
- SiteFuncs template.FuncMap
+ docFuncs template.FuncMap
}
// NewPresentation returns a new Presentation from a file system.
@@ -61,31 +55,19 @@
}
p.mux.Handle("/cmd/", docs)
p.mux.Handle("/pkg/", docs)
- p.mux.HandleFunc("/", p.ServeFile)
+ p.mux.HandleFunc("/", p.serveFile)
p.initFuncMap()
- if p.DirlistHTML, err = p.ReadTemplate("dirlist.html"); err != nil {
+ t, err := template.New("").Funcs(siteFuncs).ParseFS(fsys, "lib/godoc/*.html")
+ if err != nil {
return nil, err
}
- if p.ErrorHTML, err = p.ReadTemplate("error.html"); err != nil {
- return nil, err
- }
- if p.ExampleHTML, err = p.ReadTemplate("example.html"); err != nil {
- return nil, err
- }
- if p.GodocHTML, err = p.ReadTemplate("godoc.html"); err != nil {
- return nil, err
- }
- if p.PackageHTML, err = p.ReadTemplate("package.html"); err != nil {
- return nil, err
- }
- if p.PackageRootHTML, err = p.ReadTemplate("packageroot.html"); err != nil {
- return nil, err
- }
+ p.Templates = t
return p, nil
}
+// ServeHTTP implements http.Handler, dispatching the request appropriately.
func (p *Presentation) ServeHTTP(w http.ResponseWriter, r *http.Request) {
p.mux.ServeHTTP(w, r)
}
@@ -93,15 +75,3 @@
func (p *Presentation) googleCN(r *http.Request) bool {
return p.GoogleCN != nil && p.GoogleCN(r)
}
-
-func (p *Presentation) ReadTemplate(name string) (*template.Template, error) {
- data, err := fs.ReadFile(p.fs, "lib/godoc/"+name)
- if err != nil {
- return nil, err
- }
- t, err := template.New(name).Funcs(p.SiteFuncs).Parse(string(data))
- if err != nil {
- return nil, err
- }
- return t, nil
-}
diff --git a/internal/godoc/server.go b/internal/godoc/server.go
index c10b189..90b119f 100644
--- a/internal/godoc/server.go
+++ b/internal/godoc/server.go
@@ -12,6 +12,7 @@
"encoding/json"
"fmt"
htmlpkg "html"
+ "html/template"
"io"
"io/fs"
"log"
@@ -20,7 +21,6 @@
"regexp"
"strconv"
"strings"
- "text/template"
"golang.org/x/website/internal/pkgdoc"
"golang.org/x/website/internal/spec"
@@ -47,7 +47,8 @@
}
// TODO(rsc): URL should be clean already.
- relpath := path.Clean(strings.TrimPrefix(r.URL.Path, "/pkg/"))
+ relpath := path.Clean(strings.TrimPrefix(r.URL.Path, "/pkg"))
+ relpath = strings.TrimPrefix(relpath, "/")
abspath := path.Join("/src", relpath)
mode := pkgdoc.ParseMode(r.FormValue("m"))
@@ -60,7 +61,7 @@
info := pkgdoc.Doc(h.d, abspath, relpath, mode, r.FormValue("GOOS"), r.FormValue("GOARCH"))
if info.Err != nil {
log.Print(info.Err)
- h.p.ServeError(w, r, relpath, info.Err)
+ h.p.ServeError(w, r, info.Err)
return
}
@@ -93,23 +94,23 @@
tabtitle = "Commands"
}
- info.GoogleCN = h.p.googleCN(r)
- var body []byte
+ name := "package.html"
if info.Dirname == "/src" {
- body = applyTemplate(h.p.PackageRootHTML, "packageRootHTML", info)
- } else {
- body = applyTemplate(h.p.PackageHTML, "packageHTML", info)
+ name = "packageroot.html"
}
- h.p.ServePage(w, Page{
+ h.p.ServePage(w, r, Page{
Title: title,
- Tabtitle: tabtitle,
+ TabTitle: tabtitle,
Subtitle: subtitle,
- Body: body,
- GoogleCN: info.GoogleCN,
+ Template: name,
+ Data: info,
})
}
-func modeQueryString(m pkgdoc.Mode) string {
+// ModeQuery returns the "?m=..." query for the current page.
+// The page's Data must be a *pkgdoc.Page (to find the mode).
+func (p *Page) ModeQuery() string {
+ m := p.Data.(*pkgdoc.Page).Mode
s := m.String()
if s == "" {
return ""
@@ -117,12 +118,17 @@
return "?m=" + s
}
-func applyTemplate(t *template.Template, name string, data interface{}) []byte {
+// Invoke invokes the template with the given name on
+// a copy of p with .Data set to data, returning the resulting HTML.
+func (p *Page) Invoke(name string, data interface{}) template.HTML {
+ t := p.pres.Templates.Lookup(name)
var buf bytes.Buffer
- if err := t.Execute(&buf, data); err != nil {
- log.Printf("%s.Execute: %s", name, err)
+ p1 := *p
+ p1.Data = data
+ if err := t.Execute(&buf, &p1); err != nil {
+ log.Printf("%s.Execute: %s", t.Name(), err)
}
- return buf.Bytes()
+ return template.HTML(buf.String())
}
type writerCapturesErr struct {
@@ -202,12 +208,12 @@
src, err := fs.ReadFile(p.fs, toFS(abspath))
if err != nil {
log.Printf("ReadFile: %s", err)
- p.ServeError(w, r, relpath, err)
+ p.ServeError(w, r, err)
return
}
if r.FormValue("m") == "text" {
- p.ServeText(w, src)
+ p.serveText(w, src)
return
}
@@ -229,12 +235,11 @@
if strings.HasSuffix(relpath, ".go") {
title = "Source file"
}
- p.ServePage(w, Page{
+ p.ServePage(w, r, Page{
Title: title,
SrcPath: relpath,
- Tabtitle: relpath,
- Body: buf.Bytes(),
- GoogleCN: p.googleCN(r),
+ TabTitle: relpath,
+ Data: template.HTML(buf.String()),
})
}
@@ -245,7 +250,7 @@
list, err := fs.ReadDir(p.fs, toFS(abspath))
if err != nil {
- p.ServeError(w, r, relpath, err)
+ p.ServeError(w, r, err)
return
}
@@ -257,15 +262,17 @@
}
}
- p.ServePage(w, Page{
+ p.ServePage(w, r, Page{
Title: "Directory",
SrcPath: relpath,
- Tabtitle: relpath,
- Body: applyTemplate(p.DirlistHTML, "dirlistHTML", info),
- GoogleCN: p.googleCN(r),
+ TabTitle: relpath,
+ Template: "dirlist.html",
+ Data: info,
})
}
+var doctype = []byte("<!DOCTYPE ")
+
func (p *Presentation) serveHTML(w http.ResponseWriter, r *http.Request, f *file) {
src := f.Body
isMarkdown := strings.HasSuffix(f.FilePath, ".md")
@@ -280,21 +287,21 @@
page := Page{
Title: f.Title,
Subtitle: f.Subtitle,
- GoogleCN: p.googleCN(r),
}
// evaluate as template if indicated
if f.Template {
- tmpl, err := template.New("main").Funcs(p.DocFuncs).Parse(string(src))
+ page = p.fullPage(r, page)
+ tmpl, err := template.New("main").Funcs(p.docFuncs).Parse(string(src))
if err != nil {
log.Printf("parsing template %s: %v", f.Path, err)
- p.ServeError(w, r, f.Path, err)
+ p.ServeError(w, r, err)
return
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, page); err != nil {
log.Printf("executing template %s: %v", f.Path, err)
- p.ServeError(w, r, f.Path, err)
+ p.ServeError(w, r, err)
return
}
src = buf.Bytes()
@@ -306,7 +313,7 @@
html, err := renderMarkdown(src)
if err != nil {
log.Printf("executing markdown %s: %v", f.Path, err)
- p.ServeError(w, r, f.Path, err)
+ p.ServeError(w, r, err)
return
}
src = html
@@ -319,12 +326,8 @@
src = buf.Bytes()
}
- page.Body = src
- p.ServePage(w, page)
-}
-
-func (p *Presentation) ServeFile(w http.ResponseWriter, r *http.Request) {
- p.serveFile(w, r)
+ page.Data = template.HTML(src)
+ p.ServePage(w, r, page)
}
func (p *Presentation) serveFile(w http.ResponseWriter, r *http.Request) {
@@ -361,7 +364,7 @@
return
}
}
- p.ServeError(w, r, relpath, err)
+ p.ServeError(w, r, err)
return
}
@@ -385,7 +388,7 @@
p.fileServer.ServeHTTP(w, r)
}
-func (p *Presentation) ServeText(w http.ResponseWriter, text []byte) {
+func (p *Presentation) serveText(w http.ResponseWriter, text []byte) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Write(text)
}
diff --git a/internal/godoc/server_test.go b/internal/godoc/server_test.go
index 152e934..1829036 100644
--- a/internal/godoc/server_test.go
+++ b/internal/godoc/server_test.go
@@ -14,14 +14,13 @@
"strings"
"testing"
"testing/fstest"
- "text/template"
)
func testServeBody(t *testing.T, p *Presentation, path, body string) {
t.Helper()
r := &http.Request{URL: &url.URL{Path: path}}
rw := httptest.NewRecorder()
- p.ServeFile(rw, r)
+ p.serveFile(rw, r)
if rw.Code != 200 || !strings.Contains(rw.Body.String(), body) {
t.Fatalf("GET %s: expected 200 w/ %q: got %d w/ body:\n%s",
path, body, rw.Code, rw.Body)
@@ -30,11 +29,12 @@
func TestRedirectAndMetadata(t *testing.T) {
fsys := fstest.MapFS{
- "doc/x/index.html": {Data: []byte("Hello, x.")},
+ "doc/x/index.html": {Data: []byte("Hello, x.")},
+ "lib/godoc/site.html": {Data: []byte(`{{.Data}}`)},
}
- p := &Presentation{
- fs: fsys,
- GodocHTML: template.Must(template.New("").Parse(`{{printf "%s" .Body}}`)),
+ p, err := NewPresentation(fsys)
+ if err != nil {
+ t.Fatal(err)
}
// Test that redirect is sent back correctly.
@@ -43,7 +43,7 @@
r := &http.Request{URL: &url.URL{Path: dir + "index.html"}}
rw := httptest.NewRecorder()
- p.ServeFile(rw, r)
+ p.serveFile(rw, r)
loc := rw.Result().Header.Get("Location")
if rw.Code != 301 || loc != dir {
t.Errorf("GET %s: expected 301 -> %q, got %d -> %q", r.URL.Path, dir, rw.Code, loc)
@@ -53,12 +53,13 @@
}
func TestMarkdown(t *testing.T) {
- p := &Presentation{
- fs: fstest.MapFS{
- "doc/test.md": {Data: []byte("**bold**")},
- "doc/test2.md": {Data: []byte(`{{"*template*"}}`)},
- },
- GodocHTML: template.Must(template.New("").Parse(`{{printf "%s" .Body}}`)),
+ p, err := NewPresentation(fstest.MapFS{
+ "doc/test.md": {Data: []byte("**bold**")},
+ "doc/test2.md": {Data: []byte(`{{"*template*"}}`)},
+ "lib/godoc/site.html": {Data: []byte(`{{.Data}}`)},
+ })
+ if err != nil {
+ t.Fatal(err)
}
testServeBody(t, p, "/doc/test", "<strong>bold</strong>")
diff --git a/internal/godoc/template.go b/internal/godoc/template.go
index 138b71f..214a159 100644
--- a/internal/godoc/template.go
+++ b/internal/godoc/template.go
@@ -37,6 +37,7 @@
import (
"bytes"
"fmt"
+ "html/template"
"io/fs"
"log"
"regexp"
@@ -74,7 +75,7 @@
return ""
}
-func (p *Presentation) code(file string, arg ...interface{}) (s string, err error) {
+func (p *Presentation) code(file string, arg ...interface{}) (_ template.HTML, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("%v", r)
@@ -105,7 +106,7 @@
buf.Write(texthtml.Format([]byte(text), texthtml.Config{GoComments: true}))
// Include the command as a comment.
text = fmt.Sprintf("<pre><!--{{%s}}\n-->%s</pre>", command, buf.Bytes())
- return text, nil
+ return template.HTML(text), nil
}
// parseArg returns the integer or string value of the argument and tells which it is.
diff --git a/internal/pkgdoc/doc.go b/internal/pkgdoc/doc.go
index a5b98ac..02e7b5b 100644
--- a/internal/pkgdoc/doc.go
+++ b/internal/pkgdoc/doc.go
@@ -44,9 +44,8 @@
}
type Page struct {
- Dirname string // directory containing the package
- Err error // error or nil
- GoogleCN bool // page is being served from golang.google.cn
+ Dirname string // directory containing the package
+ Err error // error or nil
Mode Mode // display metadata from query string