some deletions
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / godoc / server.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/godoc/server.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/godoc/server.go
deleted file mode 100644 (file)
index 8724291..0000000
+++ /dev/null
@@ -1,837 +0,0 @@
-// Copyright 2013 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.
-
-package godoc
-
-import (
-       "bytes"
-       "encoding/json"
-       "errors"
-       "fmt"
-       "go/ast"
-       "go/build"
-       "go/doc"
-       "go/token"
-       htmlpkg "html"
-       htmltemplate "html/template"
-       "io"
-       "io/ioutil"
-       "log"
-       "net/http"
-       "os"
-       pathpkg "path"
-       "path/filepath"
-       "sort"
-       "strings"
-       "text/template"
-       "time"
-
-       "golang.org/x/tools/godoc/analysis"
-       "golang.org/x/tools/godoc/util"
-       "golang.org/x/tools/godoc/vfs"
-)
-
-// handlerServer is a migration from an old godoc http Handler type.
-// This should probably merge into something else.
-type handlerServer struct {
-       p           *Presentation
-       c           *Corpus  // copy of p.Corpus
-       pattern     string   // url pattern; e.g. "/pkg/"
-       stripPrefix string   // prefix to strip from import path; e.g. "pkg/"
-       fsRoot      string   // file system root to which the pattern is mapped; e.g. "/src"
-       exclude     []string // file system paths to exclude; e.g. "/src/cmd"
-}
-
-func (s *handlerServer) registerWithMux(mux *http.ServeMux) {
-       mux.Handle(s.pattern, s)
-}
-
-// GetPageInfo returns the PageInfo for a package directory abspath. If the
-// parameter genAST is set, an AST containing only the package exports is
-// computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
-// is extracted from the AST. If there is no corresponding package in the
-// directory, PageInfo.PAst and PageInfo.PDoc are nil. If there are no sub-
-// directories, PageInfo.Dirs is nil. If an error occurred, PageInfo.Err is
-// set to the respective error but the error is not logged.
-//
-func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode, goos, goarch string) *PageInfo {
-       info := &PageInfo{Dirname: abspath, Mode: mode}
-
-       // Restrict to the package files that would be used when building
-       // the package on this system.  This makes sure that if there are
-       // separate implementations for, say, Windows vs Unix, we don't
-       // jumble them all together.
-       // Note: If goos/goarch aren't set, the current binary's GOOS/GOARCH
-       // are used.
-       ctxt := build.Default
-       ctxt.IsAbsPath = pathpkg.IsAbs
-       ctxt.IsDir = func(path string) bool {
-               fi, err := h.c.fs.Stat(filepath.ToSlash(path))
-               return err == nil && fi.IsDir()
-       }
-       ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) {
-               f, err := h.c.fs.ReadDir(filepath.ToSlash(dir))
-               filtered := make([]os.FileInfo, 0, len(f))
-               for _, i := range f {
-                       if mode&NoFiltering != 0 || i.Name() != "internal" {
-                               filtered = append(filtered, i)
-                       }
-               }
-               return filtered, err
-       }
-       ctxt.OpenFile = func(name string) (r io.ReadCloser, err error) {
-               data, err := vfs.ReadFile(h.c.fs, filepath.ToSlash(name))
-               if err != nil {
-                       return nil, err
-               }
-               return ioutil.NopCloser(bytes.NewReader(data)), nil
-       }
-
-       // Make the syscall/js package always visible by default.
-       // It defaults to the host's GOOS/GOARCH, and golang.org's
-       // linux/amd64 means the wasm syscall/js package was blank.
-       // And you can't run godoc on js/wasm anyway, so host defaults
-       // don't make sense here.
-       if goos == "" && goarch == "" && relpath == "syscall/js" {
-               goos, goarch = "js", "wasm"
-       }
-       if goos != "" {
-               ctxt.GOOS = goos
-       }
-       if goarch != "" {
-               ctxt.GOARCH = goarch
-       }
-
-       pkginfo, err := ctxt.ImportDir(abspath, 0)
-       // continue if there are no Go source files; we still want the directory info
-       if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
-               info.Err = err
-               return info
-       }
-
-       // collect package files
-       pkgname := pkginfo.Name
-       pkgfiles := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
-       if len(pkgfiles) == 0 {
-               // Commands written in C have no .go files in the build.
-               // Instead, documentation may be found in an ignored file.
-               // The file may be ignored via an explicit +build ignore
-               // constraint (recommended), or by defining the package
-               // documentation (historic).
-               pkgname = "main" // assume package main since pkginfo.Name == ""
-               pkgfiles = pkginfo.IgnoredGoFiles
-       }
-
-       // get package information, if any
-       if len(pkgfiles) > 0 {
-               // build package AST
-               fset := token.NewFileSet()
-               files, err := h.c.parseFiles(fset, relpath, abspath, pkgfiles)
-               if err != nil {
-                       info.Err = err
-                       return info
-               }
-
-               // ignore any errors - they are due to unresolved identifiers
-               pkg, _ := ast.NewPackage(fset, files, poorMansImporter, nil)
-
-               // extract package documentation
-               info.FSet = fset
-               if mode&ShowSource == 0 {
-                       // show extracted documentation
-                       var m doc.Mode
-                       if mode&NoFiltering != 0 {
-                               m |= doc.AllDecls
-                       }
-                       if mode&AllMethods != 0 {
-                               m |= doc.AllMethods
-                       }
-                       info.PDoc = doc.New(pkg, pathpkg.Clean(relpath), m) // no trailing '/' in importpath
-                       if mode&NoTypeAssoc != 0 {
-                               for _, t := range info.PDoc.Types {
-                                       info.PDoc.Consts = append(info.PDoc.Consts, t.Consts...)
-                                       info.PDoc.Vars = append(info.PDoc.Vars, t.Vars...)
-                                       info.PDoc.Funcs = append(info.PDoc.Funcs, t.Funcs...)
-                                       t.Consts = nil
-                                       t.Vars = nil
-                                       t.Funcs = nil
-                               }
-                               // for now we cannot easily sort consts and vars since
-                               // go/doc.Value doesn't export the order information
-                               sort.Sort(funcsByName(info.PDoc.Funcs))
-                       }
-
-                       // collect examples
-                       testfiles := append(pkginfo.TestGoFiles, pkginfo.XTestGoFiles...)
-                       files, err = h.c.parseFiles(fset, relpath, abspath, testfiles)
-                       if err != nil {
-                               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
-                                               }
-                                       }
-                               }
-                       }
-
-               } else {
-                       // show source code
-                       // TODO(gri) Consider eliminating export filtering in this mode,
-                       //           or perhaps eliminating the mode altogether.
-                       if mode&NoFiltering == 0 {
-                               packageExports(fset, pkg)
-                       }
-                       info.PAst = files
-               }
-               info.IsMain = pkgname == "main"
-       }
-
-       // get directory information, if any
-       var dir *Directory
-       var timestamp time.Time
-       if tree, ts := 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.
-               // no directory tree present (happens in command-line mode);
-               // compute 2 levels for this page. The second level is to
-               // get the synopses of sub-directories.
-               // 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
-}
-
-func (h *handlerServer) includePath(path string, mode PageInfoMode) (r bool) {
-       // if the path is under one of the exclusion paths, don't list.
-       for _, e := range h.exclude {
-               if strings.HasPrefix(path, e) {
-                       return false
-               }
-       }
-
-       // if the path includes 'internal', don't list unless we are in the NoFiltering mode.
-       if mode&NoFiltering != 0 {
-               return true
-       }
-       if strings.Contains(path, "internal") || strings.Contains(path, "vendor") {
-               for _, c := range strings.Split(filepath.Clean(path), string(os.PathSeparator)) {
-                       if c == "internal" || c == "vendor" {
-                               return false
-                       }
-               }
-       }
-       return true
-}
-
-type funcsByName []*doc.Func
-
-func (s funcsByName) Len() int           { return len(s) }
-func (s funcsByName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
-func (s funcsByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
-
-func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-       if redirect(w, r) {
-               return
-       }
-
-       relpath := pathpkg.Clean(r.URL.Path[len(h.stripPrefix)+1:])
-
-       if !h.corpusInitialized() {
-               h.p.ServeError(w, r, relpath, errors.New("Scan is not yet complete. Please retry after a few moments"))
-               return
-       }
-
-       abspath := pathpkg.Join(h.fsRoot, relpath)
-       mode := h.p.GetPageInfoMode(r)
-       if relpath == builtinPkgPath {
-               // The fake built-in package contains unexported identifiers,
-               // but we want to show them. Also, disable type association,
-               // since it's not helpful for this fake package (see issue 6645).
-               mode |= NoFiltering | NoTypeAssoc
-       }
-       info := h.GetPageInfo(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)
-               return
-       }
-
-       var tabtitle, title, subtitle string
-       switch {
-       case info.PAst != nil:
-               for _, ast := range info.PAst {
-                       tabtitle = ast.Name.Name
-                       break
-               }
-       case info.PDoc != nil:
-               tabtitle = info.PDoc.Name
-       default:
-               tabtitle = info.Dirname
-               title = "Directory "
-               if h.p.ShowTimestamps {
-                       subtitle = "Last update: " + info.DirTime.String()
-               }
-       }
-       if title == "" {
-               if info.IsMain {
-                       // assume that the directory name is the command name
-                       _, tabtitle = pathpkg.Split(relpath)
-                       title = "Command "
-               } else {
-                       title = "Package "
-               }
-       }
-       title += tabtitle
-
-       // special cases for top-level package/command directories
-       switch tabtitle {
-       case "/src":
-               title = "Packages"
-               tabtitle = "Packages"
-       case "/src/cmd":
-               title = "Commands"
-               tabtitle = "Commands"
-       }
-
-       // Emit JSON array for type information.
-       pi := h.c.Analysis.PackageInfo(relpath)
-       hasTreeView := len(pi.CallGraph) != 0
-       info.CallGraphIndex = pi.CallGraphIndex
-       info.CallGraph = htmltemplate.JS(marshalJSON(pi.CallGraph))
-       info.AnalysisData = htmltemplate.JS(marshalJSON(pi.Types))
-       info.TypeInfoIndex = make(map[string]int)
-       for i, ti := range pi.Types {
-               info.TypeInfoIndex[ti.Name] = i
-       }
-
-       info.GoogleCN = googleCN(r)
-       var body []byte
-       if info.Dirname == "/src" {
-               body = applyTemplate(h.p.PackageRootHTML, "packageRootHTML", info)
-       } else {
-               body = applyTemplate(h.p.PackageHTML, "packageHTML", info)
-       }
-       h.p.ServePage(w, Page{
-               Title:    title,
-               Tabtitle: tabtitle,
-               Subtitle: subtitle,
-               Body:     body,
-               GoogleCN: info.GoogleCN,
-               TreeView: hasTreeView,
-       })
-}
-
-func (h *handlerServer) corpusInitialized() bool {
-       h.c.initMu.RLock()
-       defer h.c.initMu.RUnlock()
-       return h.c.initDone
-}
-
-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
-       FlatDir                              // show directory in a flat (non-indented) manner
-       NoTypeAssoc                          // don't associate consts, vars, and factory functions with types (not exposed via ?m= query parameter, used for package builtin, see issue 6645)
-)
-
-// modeNames defines names for each PageInfoMode flag.
-var modeNames = map[string]PageInfoMode{
-       "all":     NoFiltering,
-       "methods": AllMethods,
-       "src":     ShowSource,
-       "flat":    FlatDir,
-}
-
-// generate a query string for persisting PageInfoMode between pages.
-func modeQueryString(mode PageInfoMode) string {
-       if modeNames := mode.names(); len(modeNames) > 0 {
-               return "?m=" + strings.Join(modeNames, ",")
-       }
-       return ""
-}
-
-// alphabetically sorted names of active flags for a PageInfoMode.
-func (m PageInfoMode) names() []string {
-       var names []string
-       for name, mode := range modeNames {
-               if m&mode != 0 {
-                       names = append(names, name)
-               }
-       }
-       sort.Strings(names)
-       return names
-}
-
-// 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 {
-       var mode PageInfoMode
-       for _, k := range strings.Split(r.FormValue(PageInfoModeQueryString), ",") {
-               if m, found := modeNames[strings.TrimSpace(k)]; found {
-                       mode |= m
-               }
-       }
-       if p.AdjustPageInfoMode != nil {
-               mode = p.AdjustPageInfoMode(r, mode)
-       }
-       return mode
-}
-
-// poorMansImporter returns a (dummy) package object named
-// by the last path component of the provided package path
-// (as is the convention for packages). This is sufficient
-// to resolve package identifiers without doing an actual
-// import. It never returns an error.
-//
-func poorMansImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
-       pkg := imports[path]
-       if pkg == nil {
-               // note that strings.LastIndex returns -1 if there is no "/"
-               pkg = ast.NewObj(ast.Pkg, path[strings.LastIndex(path, "/")+1:])
-               pkg.Data = ast.NewScope(nil) // required by ast.NewPackage for dot-import
-               imports[path] = pkg
-       }
-       return pkg, nil
-}
-
-// globalNames returns a set of the names declared by all package-level
-// declarations. Method names are returned in the form Receiver_Method.
-func globalNames(pkg *ast.Package) map[string]bool {
-       names := make(map[string]bool)
-       for _, file := range pkg.Files {
-               for _, decl := range file.Decls {
-                       addNames(names, decl)
-               }
-       }
-       return names
-}
-
-// collectExamples collects examples for pkg from testfiles.
-func collectExamples(c *Corpus, pkg *ast.Package, testfiles map[string]*ast.File) []*doc.Example {
-       var files []*ast.File
-       for _, f := range testfiles {
-               files = append(files, f)
-       }
-
-       var examples []*doc.Example
-       globals := globalNames(pkg)
-       for _, e := range doc.Examples(files...) {
-               name := stripExampleSuffix(e.Name)
-               if name == "" || globals[name] {
-                       examples = append(examples, e)
-               } else if c.Verbose {
-                       log.Printf("skipping example 'Example%s' because '%s' is not a known function or type", e.Name, e.Name)
-               }
-       }
-
-       return examples
-}
-
-// addNames adds the names declared by decl to the names set.
-// Method names are added in the form ReceiverTypeName_Method.
-func addNames(names map[string]bool, decl ast.Decl) {
-       switch d := decl.(type) {
-       case *ast.FuncDecl:
-               name := d.Name.Name
-               if d.Recv != nil {
-                       var typeName string
-                       switch r := d.Recv.List[0].Type.(type) {
-                       case *ast.StarExpr:
-                               typeName = r.X.(*ast.Ident).Name
-                       case *ast.Ident:
-                               typeName = r.Name
-                       }
-                       name = typeName + "_" + name
-               }
-               names[name] = true
-       case *ast.GenDecl:
-               for _, spec := range d.Specs {
-                       switch s := spec.(type) {
-                       case *ast.TypeSpec:
-                               names[s.Name.Name] = true
-                       case *ast.ValueSpec:
-                               for _, id := range s.Names {
-                                       names[id.Name] = true
-                               }
-                       }
-               }
-       }
-}
-
-// packageExports is a local implementation of ast.PackageExports
-// which correctly updates each package file's comment list.
-// (The ast.PackageExports signature is frozen, hence the local
-// implementation).
-//
-func packageExports(fset *token.FileSet, pkg *ast.Package) {
-       for _, src := range pkg.Files {
-               cmap := ast.NewCommentMap(fset, src, src.Comments)
-               ast.FileExports(src)
-               src.Comments = cmap.Filter(src).Comments()
-       }
-}
-
-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()
-}
-
-type writerCapturesErr struct {
-       w   io.Writer
-       err error
-}
-
-func (w *writerCapturesErr) Write(p []byte) (int, error) {
-       n, err := w.w.Write(p)
-       if err != nil {
-               w.err = err
-       }
-       return n, err
-}
-
-// applyTemplateToResponseWriter uses an http.ResponseWriter as the io.Writer
-// for the call to template.Execute.  It uses an io.Writer wrapper to capture
-// errors from the underlying http.ResponseWriter.  Errors are logged only when
-// they come from the template processing and not the Writer; this avoid
-// polluting log files with error messages due to networking issues, such as
-// client disconnects and http HEAD protocol violations.
-func applyTemplateToResponseWriter(rw http.ResponseWriter, t *template.Template, data interface{}) {
-       w := &writerCapturesErr{w: rw}
-       err := t.Execute(w, data)
-       // There are some cases where template.Execute does not return an error when
-       // rw returns an error, and some where it does.  So check w.err first.
-       if w.err == nil && err != nil {
-               // Log template errors.
-               log.Printf("%s.Execute: %s", t.Name(), err)
-       }
-}
-
-func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
-       canonical := pathpkg.Clean(r.URL.Path)
-       if !strings.HasSuffix(canonical, "/") {
-               canonical += "/"
-       }
-       if r.URL.Path != canonical {
-               url := *r.URL
-               url.Path = canonical
-               http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
-               redirected = true
-       }
-       return
-}
-
-func redirectFile(w http.ResponseWriter, r *http.Request) (redirected bool) {
-       c := pathpkg.Clean(r.URL.Path)
-       c = strings.TrimRight(c, "/")
-       if r.URL.Path != c {
-               url := *r.URL
-               url.Path = c
-               http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
-               redirected = true
-       }
-       return
-}
-
-func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
-       src, err := vfs.ReadFile(p.Corpus.fs, abspath)
-       if err != nil {
-               log.Printf("ReadFile: %s", err)
-               p.ServeError(w, r, relpath, err)
-               return
-       }
-
-       if r.FormValue(PageInfoModeQueryString) == "text" {
-               p.ServeText(w, src)
-               return
-       }
-
-       h := r.FormValue("h")
-       s := RangeSelection(r.FormValue("s"))
-
-       var buf bytes.Buffer
-       if pathpkg.Ext(abspath) == ".go" {
-               // Find markup links for this file (e.g. "/src/fmt/print.go").
-               fi := p.Corpus.Analysis.FileInfo(abspath)
-               buf.WriteString("<script type='text/javascript'>document.ANALYSIS_DATA = ")
-               buf.Write(marshalJSON(fi.Data))
-               buf.WriteString(";</script>\n")
-
-               if status := p.Corpus.Analysis.Status(); status != "" {
-                       buf.WriteString("<a href='/lib/godoc/analysis/help.html'>Static analysis features</a> ")
-                       // TODO(adonovan): show analysis status at per-file granularity.
-                       fmt.Fprintf(&buf, "<span style='color: grey'>[%s]</span><br/>", htmlpkg.EscapeString(status))
-               }
-
-               buf.WriteString("<pre>")
-               formatGoSource(&buf, src, fi.Links, h, s)
-               buf.WriteString("</pre>")
-       } else {
-               buf.WriteString("<pre>")
-               FormatText(&buf, src, 1, false, h, s)
-               buf.WriteString("</pre>")
-       }
-       fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
-
-       p.ServePage(w, Page{
-               Title:    title,
-               SrcPath:  relpath,
-               Tabtitle: relpath,
-               Body:     buf.Bytes(),
-               GoogleCN: googleCN(r),
-       })
-}
-
-// formatGoSource HTML-escapes Go source text and writes it to w,
-// decorating it with the specified analysis links.
-//
-func formatGoSource(buf *bytes.Buffer, text []byte, links []analysis.Link, pattern string, selection Selection) {
-       // Emit to a temp buffer so that we can add line anchors at the end.
-       saved, buf := buf, new(bytes.Buffer)
-
-       var i int
-       var link analysis.Link // shared state of the two funcs below
-       segmentIter := func() (seg Segment) {
-               if i < len(links) {
-                       link = links[i]
-                       i++
-                       seg = Segment{link.Start(), link.End()}
-               }
-               return
-       }
-       linkWriter := func(w io.Writer, offs int, start bool) {
-               link.Write(w, offs, start)
-       }
-
-       comments := tokenSelection(text, token.COMMENT)
-       var highlights Selection
-       if pattern != "" {
-               highlights = regexpSelection(text, pattern)
-       }
-
-       FormatSelections(buf, text, linkWriter, segmentIter, selectionTag, comments, highlights, selection)
-
-       // Now copy buf to saved, adding line anchors.
-
-       // The lineSelection mechanism can't be composed with our
-       // linkWriter, so we have to add line spans as another pass.
-       n := 1
-       for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) {
-               // The line numbers are inserted into the document via a CSS ::before
-               // pseudo-element. This prevents them from being copied when users
-               // highlight and copy text.
-               // ::before is supported in 98% of browsers: https://caniuse.com/#feat=css-gencontent
-               // This is also the trick Github uses to hide line numbers.
-               //
-               // The first tab for the code snippet needs to start in column 9, so
-               // it indents a full 8 spaces, hence the two nbsp's. Otherwise the tab
-               // character only indents a short amount.
-               //
-               // Due to rounding and font width Firefox might not treat 8 rendered
-               // characters as 8 characters wide, and subsequently may treat the tab
-               // character in the 9th position as moving the width from (7.5 or so) up
-               // to 8. See
-               // https://github.com/webcompat/web-bugs/issues/17530#issuecomment-402675091
-               // for a fuller explanation. The solution is to add a CSS class to
-               // explicitly declare the width to be 8 characters.
-               fmt.Fprintf(saved, `<span id="L%d" class="ln">%6d&nbsp;&nbsp;</span>`, n, n)
-               n++
-               saved.Write(line)
-               saved.WriteByte('\n')
-       }
-}
-
-func (p *Presentation) serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
-       if redirect(w, r) {
-               return
-       }
-
-       list, err := p.Corpus.fs.ReadDir(abspath)
-       if err != nil {
-               p.ServeError(w, r, relpath, err)
-               return
-       }
-
-       p.ServePage(w, Page{
-               Title:    "Directory",
-               SrcPath:  relpath,
-               Tabtitle: relpath,
-               Body:     applyTemplate(p.DirlistHTML, "dirlistHTML", list),
-               GoogleCN: googleCN(r),
-       })
-}
-
-func (p *Presentation) ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
-       // get HTML body contents
-       src, err := vfs.ReadFile(p.Corpus.fs, abspath)
-       if err != nil {
-               log.Printf("ReadFile: %s", err)
-               p.ServeError(w, r, relpath, err)
-               return
-       }
-
-       // if it begins with "<!DOCTYPE " assume it is standalone
-       // html that doesn't need the template wrapping.
-       if bytes.HasPrefix(src, doctype) {
-               w.Write(src)
-               return
-       }
-
-       // if it begins with a JSON blob, read in the metadata.
-       meta, src, err := extractMetadata(src)
-       if err != nil {
-               log.Printf("decoding metadata %s: %v", relpath, err)
-       }
-
-       page := Page{
-               Title:    meta.Title,
-               Subtitle: meta.Subtitle,
-               GoogleCN: googleCN(r),
-       }
-
-       // evaluate as template if indicated
-       if meta.Template {
-               tmpl, err := template.New("main").Funcs(p.TemplateFuncs()).Parse(string(src))
-               if err != nil {
-                       log.Printf("parsing template %s: %v", relpath, err)
-                       p.ServeError(w, r, relpath, err)
-                       return
-               }
-               var buf bytes.Buffer
-               if err := tmpl.Execute(&buf, page); err != nil {
-                       log.Printf("executing template %s: %v", relpath, err)
-                       p.ServeError(w, r, relpath, err)
-                       return
-               }
-               src = buf.Bytes()
-       }
-
-       // if it's the language spec, add tags to EBNF productions
-       if strings.HasSuffix(abspath, "go_spec.html") {
-               var buf bytes.Buffer
-               Linkify(&buf, src)
-               src = buf.Bytes()
-       }
-
-       page.Body = src
-       p.ServePage(w, page)
-}
-
-func (p *Presentation) ServeFile(w http.ResponseWriter, r *http.Request) {
-       p.serveFile(w, r)
-}
-
-func (p *Presentation) serveFile(w http.ResponseWriter, r *http.Request) {
-       if strings.HasSuffix(r.URL.Path, "/index.html") {
-               // We'll show index.html for the directory.
-               // Use the dir/ version as canonical instead of dir/index.html.
-               http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
-               return
-       }
-
-       // Check to see if we need to redirect or serve another file.
-       relpath := r.URL.Path
-       if m := p.Corpus.MetadataFor(relpath); m != nil {
-               if m.Path != relpath {
-                       // Redirect to canonical path.
-                       http.Redirect(w, r, m.Path, http.StatusMovedPermanently)
-                       return
-               }
-               // Serve from the actual filesystem path.
-               relpath = m.filePath
-       }
-
-       abspath := relpath
-       relpath = relpath[1:] // strip leading slash
-
-       switch pathpkg.Ext(relpath) {
-       case ".html":
-               p.ServeHTMLDoc(w, r, abspath, relpath)
-               return
-
-       case ".go":
-               p.serveTextFile(w, r, abspath, relpath, "Source file")
-               return
-       }
-
-       dir, err := p.Corpus.fs.Lstat(abspath)
-       if err != nil {
-               log.Print(err)
-               p.ServeError(w, r, relpath, err)
-               return
-       }
-
-       if dir != nil && dir.IsDir() {
-               if redirect(w, r) {
-                       return
-               }
-               if index := pathpkg.Join(abspath, "index.html"); util.IsTextFile(p.Corpus.fs, index) {
-                       p.ServeHTMLDoc(w, r, index, index)
-                       return
-               }
-               p.serveDirectory(w, r, abspath, relpath)
-               return
-       }
-
-       if util.IsTextFile(p.Corpus.fs, abspath) {
-               if redirectFile(w, r) {
-                       return
-               }
-               p.serveTextFile(w, r, abspath, relpath, "Text file")
-               return
-       }
-
-       p.fileServer.ServeHTTP(w, r)
-}
-
-func (p *Presentation) ServeText(w http.ResponseWriter, text []byte) {
-       w.Header().Set("Content-Type", "text/plain; charset=utf-8")
-       w.Write(text)
-}
-
-func marshalJSON(x interface{}) []byte {
-       var data []byte
-       var err error
-       const indentJSON = false // for easier debugging
-       if indentJSON {
-               data, err = json.MarshalIndent(x, "", "    ")
-       } else {
-               data, err = json.Marshal(x)
-       }
-       if err != nil {
-               panic(fmt.Sprintf("json.Marshal failed: %s", err))
-       }
-       return data
-}