internal/godoc: remove unused configuration

There is lots of dead flexibility in this code.
Remove it, to make the control flow and data dependencies
easier to understand.

Change-Id: Ie9aa7bc96afc64d2a07677a73f8fb311808ef307
Reviewed-on: https://go-review.googlesource.com/c/website/+/296377
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
This commit is contained in:
Russ Cox 2021-02-24 10:08:10 -05:00
Родитель f46db3cc1a
Коммит b09c5abe08
13 изменённых файлов: 74 добавлений и 305 удалений

Просмотреть файл

@ -28,9 +28,7 @@ window.trackEvent = function(category, action, opt_label, opt_value, opt_noninte
{{end}}
<script src="/lib/godoc/jquery.js" defer></script>
{{if .Playground}}
<script src="/lib/godoc/playground.js" defer></script>
{{end}}
{{with .Version}}<script>var goVersion = {{printf "%q" .}};</script>{{end}}
<script src="/lib/godoc/godocs.js" defer></script>
@ -54,9 +52,7 @@ window.trackEvent = function(category, action, opt_label, opt_value, opt_noninte
<li class="Header-menuItem"><a href="/help/">Help</a></li>
{{if not .GoogleCN}}
<li class="Header-menuItem"><a href="/blog/">Blog</a></li>
{{if .Playground}}
<li class="Header-menuItem"><a href="https://play.golang.org/">Play</a></li>
{{end}}
<li class="Header-menuItem"><a href="https://play.golang.org/">Play</a></li>
{{end}}
</ul>
</nav>

Просмотреть файл

@ -74,10 +74,8 @@
<dd>&nbsp; &nbsp; <a href="#{{$tname_html}}.{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
{{end}}
{{end}}
{{if $.Notes}}
{{range $marker, $item := $.Notes}}
<dd><a href="#pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</a></dd>
{{end}}
{{if $.Bugs}}
<dd><a href="#pkg-note-BUG">Bugs</a></dd>
{{end}}
</dl>
</div><!-- #manual-nav -->
@ -184,15 +182,13 @@
{{end}}
{{end}}
{{with $.Notes}}
{{range $marker, $content := .}}
<h2 id="pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</h2>
<ul style="list-style: none; padding: 0;">
{{range .}}
<li><a href="{{posLink_url $ .}}" style="float: left;">&#x261e;</a> {{comment_html .Body}}</li>
{{end}}
</ul>
{{with $.Bugs}}
<h2 id="pkg-note-BUG">Bugs</h2>
<ul style="list-style: none; padding: 0;">
{{range .}}
<li><a href="{{posLink_url $ .}}" style="float: left;">&#x261e;</a> {{comment_html .Body}}</li>
{{end}}
</ul>
{{end}}
{{end}}

Просмотреть файл

@ -23,9 +23,6 @@
<div id="manual-nav">
<dl>
<dt><a href="#stdlib">Standard library</a></dt>
{{if hasThirdParty .List }}
<dt><a href="#thirdparty">Third party</a></dt>
{{end}}
<dt><a href="#other">Other packages</a></dt>
<dd><a href="#subrepo">Sub-repositories</a></dd>
<dd><a href="#community">Community</a></dd>
@ -71,46 +68,6 @@
</div> <!-- .expanded -->
</div> <!-- #stdlib .toggleVisible -->
{{if hasThirdParty .List }}
<div id="thirdparty" class="toggleVisible">
<div class="collapsed">
<h2 class="toggleButton" title="Click to show Third party section">Third party ▹</h2>
</div>
<div class="expanded">
<h2 class="toggleButton" title="Click to hide Third party section">Third party ▾</h2>
<div class="pkg-dir">
<table>
<tr>
<th class="pkg-name">Name</th>
<th class="pkg-synopsis">Synopsis</th>
</tr>
{{range .List}}
<tr>
{{if eq .RootType "GOPATH"}}
{{if $.DirFlat}}
{{if .HasPkg}}
<td class="pkg-name">
<a href="{{html .Path}}/{{modeQueryString $.Mode | html}}">{{html .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>
</td>
{{end}}
<td class="pkg-synopsis">
{{html .Synopsis}}
</td>
{{end}}
</tr>
{{end}}
</table>
</div> <!-- .pkg-dir -->
</div> <!-- .expanded -->
</div> <!-- #stdlib .toggleVisible -->
{{end}}
<h2 id="other">Other packages</h2>
<h3 id="subrepo">Sub-repositories</h3>
<p>

Просмотреть файл

@ -1,68 +0,0 @@
// Copyright 2009 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.
/*
Godoc extracts and generates documentation for Go programs.
It runs as a web server and presents the documentation as a
web page.
godoc -http=:6060
Usage:
godoc [flag]
The flags are:
-v
verbose mode
-timestamps=true
show timestamps with directory listings
-play=false
enable playground
-links=true
link identifiers to their declarations
-notes="BUG"
regular expression matching note markers to show
(e.g., "BUG|TODO", ".*")
-goroot=$GOROOT
Go root directory
-http=addr
HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
-templates=""
directory containing alternate template files; if set,
the directory may provide alternative template files
for the files in _content/
By default, golangorg looks at the packages it finds via $GOROOT (if set).
This behavior can be altered by providing an alternative $GOROOT with the -goroot
flag.
By default, godoc uses the system's GOOS/GOARCH. You can provide the URL parameters
"GOOS" and "GOARCH" to set the output on the web page for the target system.
The presentation mode of web pages served by godoc can be controlled with the
"m" URL parameter; it accepts a comma-separated list of flag names as value:
all show documentation for all declarations, not just the exported ones
methods show all embedded methods, not just those of unexported anonymous fields
src show the original source code rather than the extracted documentation
flat present flat (not indented) directory listings using full paths
For instance, https://golang.org/pkg/math/big/?m=all shows the documentation
for all (not just the exported) declarations of package big.
Godoc serves files from the file system of the underlying OS.
Godoc documentation is converted to HTML or to text using the go/doc package;
see https://golang.org/pkg/go/doc/#ToHTML for the exact rules.
Godoc also shows example code that is runnable by the testing package;
see https://golang.org/pkg/testing/#hdr-Examples for the conventions.
See "Godoc: documenting Go code" for how to write good comments for godoc:
https://golang.org/doc/articles/godoc_documenting_go_code.html
*/
package main // import "golang.org/x/website/cmd/golangorg"

Просмотреть файл

@ -27,7 +27,6 @@ import (
"log"
"net/http"
"os"
"regexp"
"runtime"
"golang.org/x/website"
@ -35,14 +34,10 @@ import (
)
var (
httpAddr = flag.String("http", "localhost:6060", "HTTP service address")
verbose = flag.Bool("v", false, "verbose mode")
goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings")
templateDir = flag.String("templates", "", "load templates/JS/CSS from disk in this directory (usually /path-to-website/content)")
showPlayground = flag.Bool("play", true, "enable playground")
declLinks = flag.Bool("links", true, "link identifiers to their declarations")
notesRx = flag.String("notes", "BUG", "regular expression matching note markers to show")
httpAddr = flag.String("http", "localhost:6060", "HTTP service address")
verbose = flag.Bool("v", false, "verbose mode")
goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
templateDir = flag.String("templates", "", "load templates/JS/CSS from disk in this directory (usually /path-to-website/content)")
)
func usage() {
@ -93,12 +88,6 @@ func main() {
corpus.InitVersionInfo()
pres = godoc.NewPresentation(corpus)
pres.ShowTimestamps = *showTimestamps
pres.ShowPlayground = *showPlayground
pres.DeclLinks = *declLinks
if *notesRx != "" {
pres.NotesRx = regexp.MustCompile(*notesRx)
}
pres.GoogleCN = googleCN
readTemplates(pres)

Просмотреть файл

@ -36,7 +36,7 @@ func (p *Presentation) node_htmlFunc(info *PageInfo, node interface{}, linkify b
var buf2 bytes.Buffer
var n ast.Node
if linkify && p.DeclLinks {
if linkify {
n, _ = node.(ast.Node)
}
buf2.Write(texthtml.Format(buf1.Bytes(), texthtml.Config{
@ -46,6 +46,8 @@ func (p *Presentation) node_htmlFunc(info *PageInfo, node interface{}, linkify b
return buf2.String()
}
const TabWidth = 4
// writeNode writes the AST node x to w.
//
// The provided fset must be non-nil. The pageInfo is optional. If
@ -82,7 +84,7 @@ func (p *Presentation) writeNode(w io.Writer, pageInfo *PageInfo, fset *token.Fi
}
mode := printer.TabIndent | printer.UseSpaces
err := (&printer.Config{Mode: mode, Tabwidth: p.TabWidth}).Fprint(TabSpacer(out, p.TabWidth), fset, x)
err := (&printer.Config{Mode: mode, Tabwidth: TabWidth}).Fprint(TabSpacer(out, TabWidth), fset, x)
if err != nil {
log.Print(err)
}

Просмотреть файл

@ -335,12 +335,6 @@ type DirList struct {
List []DirEntry
}
// hasThirdParty checks whether a list of directory entries has packages outside
// the standard library or not.
func hasThirdParty(list []DirEntry) bool {
return false
}
// listing creates a (linear) directory listing from a directory tree.
// If skipRoot is set, the root directory itself is excluded from the list.
// If filter is set, only the directory entries whose paths match the filter

Просмотреть файл

@ -40,7 +40,7 @@ func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string
// remove surrounding braces
code = code[1 : n-1]
// unindent
code = replaceLeadingIndentation(code, strings.Repeat(" ", p.TabWidth), "")
code = replaceLeadingIndentation(code, strings.Repeat(" ", TabWidth), "")
// remove output comment
if loc := exampleOutputRx.FindStringIndex(code); loc != nil {
code = strings.TrimSpace(code[:loc[0]])
@ -50,7 +50,7 @@ func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string
// Write out the playground code in standard Go style
// (use tabs, no comment highlight, etc).
play := ""
if eg.Play != nil && p.ShowPlayground {
if eg.Play != nil {
var buf bytes.Buffer
eg.Play.Comments = filterOutBuildAnnotations(eg.Play.Comments)
if err := format.Node(&buf, info.FSet, eg.Play); err != nil {

Просмотреть файл

@ -62,7 +62,7 @@ func (p *Presentation) initFuncMap() {
// support for URL attributes
"pkgLink": pkgLinkFunc,
"srcLink": srcLinkFunc,
"posLink_url": newPosLink_urlFunc(srcPosLinkFunc),
"posLink_url": posLink_urlFunc,
"docLink": docLinkFunc,
"queryLink": queryLinkFunc,
"srcBreadcrumb": srcBreadcrumbFunc,
@ -73,26 +73,11 @@ func (p *Presentation) initFuncMap() {
"example_name": p.example_nameFunc,
"example_suffix": p.example_suffixFunc,
// formatting of Notes
"noteTitle": noteTitle,
// Number operation
"multiply": multiply,
// formatting of PageInfoMode query string
"modeQueryString": modeQueryString,
// check whether to display third party section or not
"hasThirdParty": hasThirdParty,
}
if p.URLForSrc != nil {
p.funcMap["srcLink"] = p.URLForSrc
}
if p.URLForSrcPos != nil {
p.funcMap["posLink_url"] = newPosLink_urlFunc(p.URLForSrcPos)
}
if p.URLForSrcQuery != nil {
p.funcMap["queryLink"] = p.URLForSrcQuery
}
}
@ -111,13 +96,13 @@ type PageInfo struct {
Mode PageInfoMode // display metadata from query string
// package info
FSet *token.FileSet // nil if no package documentation
PDoc *doc.Package // nil if no package documentation
Examples []*doc.Example // nil if no example code
Notes map[string][]*doc.Note // nil if no package Notes
PAst map[string]*ast.File // nil if no AST with package exports
IsMain bool // true for package main
IsFiltered bool // true if results were filtered
FSet *token.FileSet // nil if no package documentation
PDoc *doc.Package // nil if no package documentation
Examples []*doc.Example // nil if no example code
Bugs []*doc.Note // nil if no BUG comments
PAst map[string]*ast.File // nil if no AST with package exports
IsMain bool // true for package main
IsFiltered bool // true if results were filtered
// directory info
Dirs *DirList // nil if no directory information
@ -180,38 +165,36 @@ func srcBreadcrumbFunc(relpath string) string {
return buf.String()
}
func newPosLink_urlFunc(srcPosLinkFunc func(s string, line, low, high int) string) func(info *PageInfo, n interface{}) string {
func posLink_urlFunc(info *PageInfo, n interface{}) string {
// n must be an ast.Node or a *doc.Note
return func(info *PageInfo, n interface{}) string {
var pos, end token.Pos
var pos, end token.Pos
switch n := n.(type) {
case ast.Node:
pos = n.Pos()
end = n.End()
case *doc.Note:
pos = n.Pos
end = n.End
default:
panic(fmt.Sprintf("wrong type for posLink_url template formatter: %T", n))
}
var relpath string
var line int
var low, high int // selection offset range
if pos.IsValid() {
p := info.FSet.Position(pos)
relpath = p.Filename
line = p.Line
low = p.Offset
}
if end.IsValid() {
high = info.FSet.Position(end).Offset
}
return srcPosLinkFunc(relpath, line, low, high)
switch n := n.(type) {
case ast.Node:
pos = n.Pos()
end = n.End()
case *doc.Note:
pos = n.Pos
end = n.End
default:
panic(fmt.Sprintf("wrong type for posLink_url template formatter: %T", n))
}
var relpath string
var line int
var low, high int // selection offset range
if pos.IsValid() {
p := info.FSet.Position(pos)
relpath = p.Filename
line = p.Line
low = p.Offset
}
if end.IsValid() {
high = info.FSet.Position(end).Offset
}
return srcPosLinkFunc(relpath, line, low, high)
}
func srcPosLinkFunc(s string, line, low, high int) string {
@ -260,7 +243,3 @@ func queryLinkFunc(s, query string, line int) string {
func docLinkFunc(s string, ident string) string {
return pathpkg.Clean("/pkg/"+s) + "/#" + ident
}
func noteTitle(note string) string {
return strings.Title(strings.ToLower(note))
}

Просмотреть файл

@ -145,16 +145,16 @@ type T struct {
}
`))
want := `type T struct {
<span id="T.NoDoc"></span>NoDoc <a href="/pkg/builtin/#string">string</a>
<span id="T.NoDoc"></span> NoDoc <a href="/pkg/builtin/#string">string</a>
<span id="T.Doc"></span><span class="comment">// Doc has a comment.</span>
Doc <a href="/pkg/builtin/#string">string</a>
<span id="T.Doc"></span> <span class="comment">// Doc has a comment.</span>
Doc <a href="/pkg/builtin/#string">string</a>
<span id="T.Opt"></span><span class="comment">// Opt, if non-nil, is an option.</span>
Opt *<a href="/pkg/builtin/#int">int</a>
<span id="T.Opt"></span> <span class="comment">// Opt, if non-nil, is an option.</span>
Opt *<a href="/pkg/builtin/#int">int</a>
<span id="T.Опция"></span><span class="comment">// Опция - другое поле.</span>
Опция <a href="/pkg/builtin/#bool">bool</a>
<span id="T.Опция"></span> <span class="comment">// Опция - другое поле.</span>
Опция <a href="/pkg/builtin/#bool">bool</a>
}`
if got != want {
t.Errorf("got: %s\n\nwant: %s\n", got, want)
@ -176,12 +176,12 @@ const (
NoVal
)`))
want := `const (
<span id="NoDoc">NoDoc</span> <a href="/pkg/builtin/#string">string</a> = &#34;NoDoc&#34;
<span id="NoDoc">NoDoc</span> <a href="/pkg/builtin/#string">string</a> = &#34;NoDoc&#34;
<span class="comment">// Doc has a comment</span>
<span id="Doc">Doc</span> = &#34;Doc&#34;
<span class="comment">// Doc has a comment</span>
<span id="Doc">Doc</span> = &#34;Doc&#34;
<span id="NoVal">NoVal</span>
<span id="NoVal">NoVal</span>
)`
if got != want {
t.Errorf("got: %s\n\nwant: %s\n", got, want)
@ -198,7 +198,7 @@ type T struct {
var S T = T{X: 12}`))
want := `type T struct {
<span id="T.X"></span>X <a href="/pkg/builtin/#int">int</a>
<span id="T.X"></span> X <a href="/pkg/builtin/#int">int</a>
}
var <span id="S">S</span> <a href="#T">T</a> = <a href="#T">T</a>{<a href="#T.X">X</a>: 12}`
if got != want {
@ -229,9 +229,7 @@ func (h Header) Get(key string) string`))
}
func linkifySource(t *testing.T, src []byte) string {
p := &Presentation{
DeclLinks: true,
}
p := &Presentation{}
fset := token.NewFileSet()
af, err := parser.ParseFile(fset, "foo.go", src, parser.ParseComments)
if err != nil {

Просмотреть файл

@ -25,7 +25,6 @@ type Page struct {
GoogleCN bool // page is being served from golang.google.cn
// filled in by ServePage
Playground bool
Version string
GoogleAnalytics string
}
@ -34,7 +33,6 @@ func (p *Presentation) ServePage(w http.ResponseWriter, page Page) {
if page.Tabtitle == "" {
page.Tabtitle = page.Title
}
page.Playground = p.ShowPlayground
page.Version = runtime.Version()
page.GoogleAnalytics = p.GoogleAnalytics
applyTemplateToResponseWriter(w, p.GodocHTML, page)

Просмотреть файл

@ -9,7 +9,6 @@ package godoc
import (
"net/http"
"regexp"
"sync"
"text/template"
)
@ -30,44 +29,6 @@ type Presentation struct {
PackageHTML,
PackageRootHTML *template.Template
// TabWidth optionally specifies the tab width.
TabWidth int
ShowTimestamps bool
ShowPlayground bool
DeclLinks bool
// NotesRx optionally specifies a regexp to match
// notes to render in the output.
NotesRx *regexp.Regexp
// AdjustPageInfoMode optionally specifies a function to
// modify the PageInfoMode of a request. The default chosen
// value is provided.
AdjustPageInfoMode func(req *http.Request, mode PageInfoMode) PageInfoMode
// URLForSrc optionally specifies a function that takes a source file and
// returns a URL for it.
// The source file argument has the form /src/<path>/<filename>.
URLForSrc func(src string) string
// URLForSrcPos optionally specifies a function to create a URL given a
// source file, a line from the source file (1-based), and low & high offset
// positions (0-based, bytes from beginning of file). Ideally, the returned
// URL will be for the specified line of the file, while the high & low
// positions will be used to highlight a section of the file.
// The source file argument has the form /src/<path>/<filename>.
URLForSrcPos func(src string, line, low, high int) string
// URLForSrcQuery optionally specifies a function to create a URL given a
// source file, a query string, and a line from the source file (1-based).
// The source file argument has the form /src/<path>/<filename>.
// The query argument will be escaped for the purposes of embedding in a URL
// query parameter.
// Ideally, the returned URL will be for the specified line of the file with
// the query string highlighted.
URLForSrcQuery func(src, query string, line int) string
// GoogleCN reports whether this request should be marked GoogleCN.
// If the function is nil, no requests are marked GoogleCN.
GoogleCN func(*http.Request) bool
@ -90,9 +51,6 @@ func NewPresentation(c *Corpus) *Presentation {
Corpus: c,
mux: http.NewServeMux(),
fileServer: http.FileServer(http.FS(c.fs)),
TabWidth: 4,
DeclLinks: true,
}
p.cmdHandler = handlerServer{
p: p,

Просмотреть файл

@ -30,7 +30,6 @@ import (
"strconv"
"strings"
"text/template"
"time"
"golang.org/x/website/internal/spec"
"golang.org/x/website/internal/texthtml"
@ -176,22 +175,7 @@ func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode,
log.Println("parsing examples:", err)
}
info.Examples = collectExamples(h.c, pkg, files)
// collect any notes that we want to show
if info.PDoc.Notes != nil {
// could regexp.Compile only once per godoc, but probably not worth it
if rx := h.p.NotesRx; rx != nil {
for m, n := range info.PDoc.Notes {
if rx.MatchString(m) {
if info.Notes == nil {
info.Notes = make(map[string][]*doc.Note)
}
info.Notes[m] = n
}
}
}
}
info.Bugs = info.PDoc.Notes["BUG"]
} else {
// show source code
// TODO(gri) Consider eliminating export filtering in this mode,
@ -206,13 +190,11 @@ func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode,
// get directory information, if any
var dir *Directory
var timestamp time.Time
if tree, ts := h.c.fsTree.Get(); tree != nil && tree.(*Directory) != nil {
if tree, _ := h.c.fsTree.Get(); tree != nil && tree.(*Directory) != nil {
// directory tree is present; lookup respective directory
// (may still fail if the file system was updated and the
// new directory tree has not yet been computed)
dir = tree.(*Directory).lookup(abspath)
timestamp = ts
}
if dir == nil {
// TODO(agnivade): handle this case better, now since there is no CLI mode.
@ -222,11 +204,8 @@ func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode,
// note: cannot use path filter here because in general
// it doesn't contain the FSTree path
dir = h.c.newDirectory(abspath, 2)
timestamp = time.Now()
}
info.Dirs = dir.listing(true, func(path string) bool { return h.includePath(path, mode) })
info.DirTime = timestamp
info.DirFlat = mode&FlatDir != 0
return info
@ -273,7 +252,7 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
abspath := pathpkg.Join(h.fsRoot, relpath)
mode := h.p.GetPageInfoMode(r)
mode := GetPageInfoMode(r.FormValue("m"))
if relpath == builtinPkgPath {
// The fake built-in package contains unexported identifiers,
// but we want to show them. Also, disable type association,
@ -299,9 +278,6 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
tabtitle = info.Dirname
title = "Directory "
if h.p.ShowTimestamps {
subtitle = "Last update: " + info.DirTime.String()
}
}
if title == "" {
if info.IsMain {
@ -349,8 +325,6 @@ func (h *handlerServer) corpusInitialized() bool {
type PageInfoMode uint
const (
PageInfoModeQueryString = "m" // query string where PageInfoMode is stored
NoFiltering PageInfoMode = 1 << iota // do not filter exports
AllMethods // show all embedded methods
ShowSource // show source code, do not extract documentation
@ -387,18 +361,14 @@ func (m PageInfoMode) names() []string {
}
// GetPageInfoMode computes the PageInfoMode flags by analyzing the request
// URL form value "m". It is value is a comma-separated list of mode names
// as defined by modeNames (e.g.: m=src,text).
func (p *Presentation) GetPageInfoMode(r *http.Request) PageInfoMode {
// URL form value "m". It is value is a comma-separated list of mode names (for example, "all,flat").
func GetPageInfoMode(text string) PageInfoMode {
var mode PageInfoMode
for _, k := range strings.Split(r.FormValue(PageInfoModeQueryString), ",") {
for _, k := range strings.Split(text, ",") {
if m, found := modeNames[strings.TrimSpace(k)]; found {
mode |= m
}
}
if p.AdjustPageInfoMode != nil {
mode = p.AdjustPageInfoMode(r, mode)
}
return mode
}
@ -585,7 +555,7 @@ func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abs
return
}
if r.FormValue(PageInfoModeQueryString) == "text" {
if r.FormValue("m") == "text" {
p.ServeText(w, src)
return
}