func selectionTag(w io.Writer, text []byte, selections int) { if selections < len(startTags) { if tag := startTags[selections]; len(tag) > 0 { w.Write(tag) template.HTMLEscape(w, text) w.Write(endTag) return } } template.HTMLEscape(w, text) }
func posLink_urlFunc(node ast.Node, fset *token.FileSet) string { var relpath string var line int var low, high int // selection if p := node.Pos(); p.IsValid() { pos := fset.Position(p) relpath = relativeURL(pos.Filename) line = pos.Line low = pos.Offset } if p := node.End(); p.IsValid() { high = fset.Position(p).Offset } var buf bytes.Buffer template.HTMLEscape(&buf, []byte(relpath)) // selection ranges are of form "s=low:high" if low < high { fmt.Fprintf(&buf, "?s=%d:%d", low, high) // no need for URL escaping // if we have a selection, position the page // such that the selection is a bit below the top line -= 10 if line < 1 { line = 1 } } // line id's in html-printed source are of the // form "L%d" where %d stands for the line number if line > 0 { fmt.Fprintf(&buf, "#L%d", line) // no need for URL escaping } return buf.String() }
// Renders markdown in submitted messages. func Render(raw []byte) []byte { htmlFlags := 0 htmlFlags |= blackfriday.HTML_USE_XHTML htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES renderer := blackfriday.HtmlRenderer(htmlFlags, "", "") // set up the parser extensions := 0 extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS extensions |= blackfriday.EXTENSION_TABLES extensions |= blackfriday.EXTENSION_FENCED_CODE extensions |= blackfriday.EXTENSION_STRIKETHROUGH extensions |= blackfriday.EXTENSION_SPACE_HEADERS escaped := new(bytes.Buffer) template.HTMLEscape(escaped, raw) rendered := blackfriday.Markdown(escaped.Bytes(), renderer, extensions) enabled := true fmt.Println("Raw message:") fmt.Println(string(raw)) if enabled { fmt.Println("Rendered message:") fmt.Println(string(rendered)) return rendered } return raw }
// Write text to w; optionally html-escaped. func writeText(w io.Writer, text []byte, html bool) { if html { template.HTMLEscape(w, text) return } w.Write(text) }
// Write anything html-escaped to w. func writeAnyHTML(w io.Writer, fset *token.FileSet, x interface{}) { switch v := x.(type) { case []byte: template.HTMLEscape(w, v) case string: template.HTMLEscape(w, []byte(v)) case ast.Decl, ast.Expr, ast.Stmt, *ast.File: var buf bytes.Buffer writeNode(&buf, fset, x) FormatText(w, buf.Bytes(), -1, true, "", nil) default: var buf bytes.Buffer fmt.Fprint(&buf, x) template.HTMLEscape(w, buf.Bytes()) } }
// htmlEscape makes sure input is HTML clean, if necessary. func htmlEscape(input []byte) []byte { if !*html || bytes.IndexAny(input, `&"<>`) < 0 { return input } var b bytes.Buffer template.HTMLEscape(&b, input) return b.Bytes() }
// Escape comment text for HTML. // Also, turn `` into “ and '' into ”. func commentEscape(w io.Writer, s []byte) { last := 0 for i := 0; i < len(s)-1; i++ { if s[i] == s[i+1] && (s[i] == '`' || s[i] == '\'') { template.HTMLEscape(w, s[last:i]) last = i + 2 switch s[i] { case '`': w.Write(ldquo) case '\'': w.Write(rdquo) } i++ // loop will add one more } } template.HTMLEscape(w, s[last:len(s)]) }
// Template formatter for the various "url-xxx" formats. func urlFmt(w io.Writer, x interface{}, format string) { var path string var line int // determine path and position info, if any type positioner interface { Pos() token.Position } switch t := x.(type) { case string: path = t case positioner: pos := t.Pos() if pos.IsValid() { path = pos.Filename line = pos.Line } } // map path relpath := relativePath(path) // convert to URL switch format { default: // we should never reach here, but be resilient // and assume the url-pkg format instead log.Stderrf("INTERNAL ERROR: urlFmt(%s)", format) fallthrough case "url-pkg": // because of the irregular mapping under goroot // we need to correct certain relative paths if strings.HasPrefix(relpath, "src/pkg/") { relpath = relpath[len("src/pkg/"):] } template.HTMLEscape(w, []byte(pkgHandler.pattern+relpath)) case "url-src": template.HTMLEscape(w, []byte("/"+relpath)) case "url-pos": // line id's in html-printed source are of the // form "L%d" where %d stands for the line number template.HTMLEscape(w, []byte("/"+relpath)) fmt.Fprintf(w, "#L%d", line) } }
func codeToString(fset *token.FileSet, i interface{}) string { b := bytes.NewBuffer(make([]byte, 0, 128)) tmpb := bytes.NewBuffer(make([]byte, 0, 128)) flags := printer.UseSpaces | printer.TabIndent config := printer.Config{flags, 8} config.Fprint(tmpb, fset, i) template.HTMLEscape(b, tmpb.Bytes()) return b.String() }
// Escape comment text for HTML. If nice is set, // also turn `` into “ and '' into ”. func commentEscape(w io.Writer, s []byte, nice bool) { last := 0 if nice { for i := 0; i < len(s)-1; i++ { ch := s[i] if ch == s[i+1] && (ch == '`' || ch == '\'') { template.HTMLEscape(w, s[last:i]) last = i + 2 switch ch { case '`': w.Write(ldquo) case '\'': w.Write(rdquo) } i++ // loop will add one more } } } template.HTMLEscape(w, s[last:]) }
// codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi. // The filename f has already been retrieved and is passed as an argument. // Lo and hi are the numbers of the first and last line to highlight // in the response. This format is used for the middle window pane // of the codewalk pages. It is a separate iframe and does not get // the usual godoc HTML wrapper. func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) { abspath := absolutePath(f, *goroot) data, err := ioutil.ReadFile(abspath) if err != nil { log.Print(err) serveError(w, r, f, err) return } lo, _ := strconv.Atoi(r.FormValue("lo")) hi, _ := strconv.Atoi(r.FormValue("hi")) if hi < lo { hi = lo } lo = lineToByte(data, lo) hi = lineToByte(data, hi+1) // Put the mark 4 lines before lo, so that the iframe // shows a few lines of context before the highlighted // section. n := 4 mark := lo for ; mark > 0 && n > 0; mark-- { if data[mark-1] == '\n' { if n--; n == 0 { break } } } io.WriteString(w, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`) template.HTMLEscape(w, data[0:mark]) io.WriteString(w, "<a name='mark'></a>") template.HTMLEscape(w, data[mark:lo]) if lo < hi { io.WriteString(w, "<div class='codewalkhighlight'>") template.HTMLEscape(w, data[lo:hi]) io.WriteString(w, "</div>") } template.HTMLEscape(w, data[hi:]) io.WriteString(w, "</pre>") }
func serveTextFile(c *http.Conn, r *http.Request, path string) { src, err := ioutil.ReadFile(path) if err != nil { log.Stderrf("serveTextFile: %s", err) } var buf bytes.Buffer fmt.Fprintln(&buf, "<pre>") template.HTMLEscape(&buf, src) fmt.Fprintln(&buf, "</pre>") servePage(c, "Text file "+path, "", buf.Bytes()) }
func main() { // handle input flag.Parse() if *srcFn == "" || *getName == "" { flag.Usage() os.Exit(2) } // load file fs := token.NewFileSet() file, err := parser.ParseFile(fs, *srcFn, nil, 0) if err != nil { log.Fatal(err) } // create filter filter := func(name string) bool { return name == *getName } // filter if !ast.FilterFile(file, filter) { os.Exit(1) } // print the AST var b bytes.Buffer printer.Fprint(&b, fs, file) // drop package declaration if !*showPkg { for { c, err := b.ReadByte() if c == '\n' || err != nil { break } } } // drop leading newlines for { b, err := b.ReadByte() if err != nil { break } if b != '\n' { os.Stdout.Write([]byte{b}) break } } // output if *html { template.HTMLEscape(os.Stdout, b.Bytes()) } else { b.WriteTo(os.Stdout) } }
// Emphasize and escape a line of text for HTML. URLs are converted into links; // if the URL also appears in the words map, the link is taken from the map (if // the corresponding map value is the empty string, the URL is not converted // into a link). Go identifiers that appear in the words map are italicized; if // the corresponding map value is not the empty string, it is considered a URL // and the word is converted into a link. If nice is set, the remaining text's // appearance is improved where it makes sense (e.g., `` is turned into “ // and '' into ”). func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) { for { m := matchRx.FindSubmatchIndex(line) if m == nil { break } // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is identRx) // write text before match commentEscape(w, line[0:m[0]], nice) // analyze match match := line[m[0]:m[1]] url := "" italics := false if words != nil { url, italics = words[string(match)] } if m[2] < 0 { // didn't match against first parenthesized sub-regexp; must be match against urlRx if !italics { // no alternative URL in words list, use match instead url = string(match) } italics = false // don't italicize URLs } // write match if len(url) > 0 { w.Write(html_a) template.HTMLEscape(w, []byte(url)) w.Write(html_aq) } if italics { w.Write(html_i) } commentEscape(w, match, nice) if italics { w.Write(html_endi) } if len(url) > 0 { w.Write(html_enda) } // advance line = line[m[1]:] } commentEscape(w, line, nice) }
// FormatText HTML-escapes text and writes it to w. // Consecutive text segments are wrapped in HTML spans (with tags as // defined by startTags and endTag) as follows: // // - if line >= 0, line number (ln) spans are inserted before each line, // starting with the value of line // - if the text is Go source, comments get the "comment" span class // - each occurrence of the regular expression pattern gets the "highlight" // span class // - text segments covered by selection get the "selection" span class // // Comments, highlights, and selections may overlap arbitrarily; the respective // HTML span classes are specified in the startTags variable. // func FormatText(w io.Writer, text []byte, line int, goSource bool, pattern string, selection Selection) { var comments, highlights Selection if goSource { comments = commentSelection(text) } if pattern != "" { highlights = regexpSelection(text, pattern) } if line >= 0 || comments != nil || highlights != nil || selection != nil { var lineTag LinkWriter if line >= 0 { lineTag = func(w io.Writer, _ int, start bool) { if start { fmt.Fprintf(w, "<a id=\"L%d\"></a><span class=\"ln\">%6d</span>\t", line, line) line++ } } } FormatSelections(w, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection) } else { template.HTMLEscape(w, text) } }
// Template formatter for "urlquery-esc" format. func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) { var buf bytes.Buffer writeAny(&buf, fileset(x), x[0]) template.HTMLEscape(w, []byte(http.URLEscape(string(buf.Bytes())))) }
// Template formatter for "time" format. func timeFmt(w io.Writer, x interface{}, format string) { // note: os.Dir.Mtime_ns is in uint64 in ns! template.HTMLEscape(w, strings.Bytes(time.SecondsToLocalTime(int64(x.(uint64)/1e9)).String())) }
// Template formatter for the various "url-xxx" formats excluding url-esc. func urlFmt(w io.Writer, format string, x ...interface{}) { var path string var line int var low, high int // selection // determine path and position info, if any type positioner interface { Pos() token.Pos End() token.Pos } switch t := x[0].(type) { case string: path = t case positioner: fset := fileset(x) if p := t.Pos(); p.IsValid() { pos := fset.Position(p) path = pos.Filename line = pos.Line low = pos.Offset } if p := t.End(); p.IsValid() { high = fset.Position(p).Offset } default: // we should never reach here, but be resilient // and assume the position is invalid (empty path, // and line 0) log.Printf("INTERNAL ERROR: urlFmt(%s) without a string or positioner", format) } // map path relpath := relativeURL(path) // convert to relative URLs so that they can also // be used as relative file names in .txt templates switch format { default: // we should never reach here, but be resilient // and assume the url-pkg format instead log.Printf("INTERNAL ERROR: urlFmt(%s)", format) fallthrough case "url-pkg": // because of the irregular mapping under goroot // we need to correct certain relative paths if strings.HasPrefix(relpath, "src/pkg/") { relpath = relpath[len("src/pkg/"):] } template.HTMLEscape(w, []byte(pkgHandler.pattern[1:]+relpath)) // remove trailing '/' for relative URL case "url-src": template.HTMLEscape(w, []byte(relpath)) case "url-pos": template.HTMLEscape(w, []byte(relpath)) // selection ranges are of form "s=low:high" if low < high { fmt.Fprintf(w, "?s=%d:%d", low, high) // if we have a selection, position the page // such that the selection is a bit below the top line -= 10 if line < 1 { line = 1 } } // line id's in html-printed source are of the // form "L%d" where %d stands for the line number if line > 0 { fmt.Fprintf(w, "#L%d", line) } } }
// Template formatter for "time" format. func timeFmt(w io.Writer, format string, x ...interface{}) { template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x[0].(int64)/1e9).String())) }
// Template formatter for "html-esc" format. func htmlEscFmt(w io.Writer, x interface{}, format string) { var buf bytes.Buffer writeAny(&buf, x, false) template.HTMLEscape(w, buf.Bytes()) }
// Template formatter for "html-esc" format. func htmlEscFmt(w io.Writer, format string, x ...interface{}) { var buf bytes.Buffer writeAny(&buf, false, x[0]) template.HTMLEscape(w, buf.Bytes()) }
func htmlEscape(s string) string { var buf bytes.Buffer template.HTMLEscape(&buf, strings.Bytes(s)) return buf.String() }
// Template formatter for "localname" format. func localnameFmt(w io.Writer, format string, x ...interface{}) { _, localname := filepath.Split(x[0].(string)) template.HTMLEscape(w, []byte(localname)) }
func UrlHtmlFormatter(w io.Writer, fmt string, v ...interface{}) { template.HTMLEscape(w, []byte(http.URLEscape(v[0].(string)))) }
// Template formatter for "localname" format. func localnameFmt(w io.Writer, x interface{}, format string) { _, localname := pathutil.Split(x.(string)) template.HTMLEscape(w, []byte(localname)) }
func UrlHtmlFormatter(w io.Writer, v interface{}, fmt string) { template.HTMLEscape(w, strings.Bytes(http.URLEscape(v.(string)))); }
// Convert comment text to formatted HTML. // The comment was prepared by DocReader, // so it is known not to have leading, trailing blank lines // nor to have trailing spaces at the end of lines. // The comment markers have already been removed. // // Turn each run of multiple \n into </p><p> // Turn each run of indented lines into <pre> without indent. // // TODO(rsc): I'd like to pass in an array of variable names []string // and then italicize those strings when they appear as words. func ToHTML(w io.Writer, s []byte) { inpara := false close := func() { if inpara { w.Write(html_endp) inpara = false } } open := func() { if !inpara { w.Write(html_p) inpara = true } } lines := split(s) unindent(lines) for i := 0; i < len(lines); { line := lines[i] if isBlank(line) { // close paragraph close() i++ continue } if indentLen(line) > 0 { // close paragraph close() // count indented or blank lines j := i + 1 for j < len(lines) && (isBlank(lines[j]) || indentLen(lines[j]) > 0) { j++ } // but not trailing blank lines for j > i && isBlank(lines[j-1]) { j-- } block := lines[i:j] i = j unindent(block) // put those lines in a pre block. // they don't get the nice text formatting, // just html escaping w.Write(html_pre) for _, line := range block { template.HTMLEscape(w, line) } w.Write(html_endpre) continue } // open paragraph open() commentEscape(w, lines[i]) i++ } close() }