diff --git a/present/code.go.orig b/present/code.go.orig deleted file mode 100644 index ab4d888d8f..0000000000 --- a/present/code.go.orig +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2012 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 present - -import ( - "bufio" - "bytes" - "fmt" - "html/template" - "path/filepath" - "regexp" - "strconv" - "strings" -) - -// Is the playground available? -var PlayEnabled = false - -// TOOD(adg): replace the PlayEnabled flag with something less spaghetti-like. -// Instead this will probably be determined by a template execution Context -// value that contains various global metadata required when rendering -// templates. - -func init() { - Register("code", parseCode) - Register("play", parseCode) -} - -type Code struct { - Text template.HTML - Play bool // runnable code -} - -func (c Code) TemplateName() string { return "code" } - -// The input line is a .code or .play entry with a file name and an optional HLfoo marker on the end. -// Anything between the file and HL (if any) is an address expression, which we treat as a string here. -// We pick off the HL first, for easy parsing. -var ( - highlightRE = regexp.MustCompile(`\s+HL([a-zA-Z0-9_]+)?$`) - hlCommentRE = regexp.MustCompile(`(.+) // HL(.*)$`) - codeRE = regexp.MustCompile(`\.(code|play)\s+([^\s]+)(\s+)?(.*)?$`) -) - -func parseCode(ctx *Context, sourceFile string, sourceLine int, cmd string) (Elem, error) { - cmd = strings.TrimSpace(cmd) - - // Pull off the HL, if any, from the end of the input line. - highlight := "" - if hl := highlightRE.FindStringSubmatchIndex(cmd); len(hl) == 4 { - highlight = cmd[hl[2]:hl[3]] - cmd = cmd[:hl[2]-2] - } - - // Parse the remaining command line. - // Arguments: - // args[0]: whole match - // args[1]: .code/.play - // args[2]: file name - // args[3]: space, if any, before optional address - // args[4]: optional address - args := codeRE.FindStringSubmatch(cmd) - if len(args) != 5 { - return nil, fmt.Errorf("%s:%d: syntax error for .code/.play invocation", sourceFile, sourceLine) - } - command, file, addr := args[1], args[2], strings.TrimSpace(args[4]) - play := command == "play" && PlayEnabled - - // Read in code file and (optionally) match address. - filename := filepath.Join(filepath.Dir(sourceFile), file) - textBytes, err := ctx.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("%s:%d: %v", sourceFile, sourceLine, err) - } - lo, hi, err := addrToByteRange(addr, 0, textBytes) - if err != nil { - return nil, fmt.Errorf("%s:%d: %v", sourceFile, sourceLine, err) - } - - // Acme pattern matches can stop mid-line, - // so run to end of line in both directions if not at line start/end. - for lo > 0 && textBytes[lo-1] != '\n' { - lo-- - } - if hi > 0 { - for hi < len(textBytes) && textBytes[hi-1] != '\n' { - hi++ - } - } - - lines := codeLines(textBytes, lo, hi) - - for i, line := range lines { - // Replace tabs by spaces, which work better in HTML. - line.L = strings.Replace(line.L, "\t", " ", -1) - - // Highlight lines that end with "// HL[highlight]" - // and strip the magic comment. - if m := hlCommentRE.FindStringSubmatch(line.L); m != nil { - line.L = m[1] - line.HL = m[2] == highlight - } - - lines[i] = line - } - - data := &codeTemplateData{Lines: lines} - - // Include before and after in a hidden span for playground code. - if play { - data.Prefix = textBytes[:lo] - data.Suffix = textBytes[hi:] - } - - var buf bytes.Buffer - if err := codeTemplate.Execute(&buf, data); err != nil { - return nil, err - } - return Code{Text: template.HTML(buf.String()), Play: play}, nil -} - -type codeTemplateData struct { - Lines []codeLine - Prefix, Suffix []byte -} - -var leadingSpaceRE = regexp.MustCompile(`^[ \t]*`) - -var codeTemplate = template.Must(template.New("code").Funcs(template.FuncMap{ - "trimSpace": strings.TrimSpace, - "leadingSpace": leadingSpaceRE.FindString, -}).Parse(codeTemplateHTML)) - -const codeTemplateHTML = ` -{{with .Prefix}}
{{end}} - -{{range .Lines}}{{/*
- */}}{{if .HL}}{{leadingSpace .L}}{{trimSpace .L}}{{/*
- */}}{{else}}{{.L}}{{end}}{{/*
-*/}}
-{{end}}
-
-{{with .Suffix}} {{end}}
-`
-
-// codeLine represents a line of code extracted from a source file.
-type codeLine struct {
- L string // The line of code.
- N int // The line number from the source file.
- HL bool // Whether the line should be highlighted.
-}
-
-// codeLines takes a source file and returns the lines that
-// span the byte range specified by start and end.
-// It discards lines that end in "OMIT".
-func codeLines(src []byte, start, end int) (lines []codeLine) {
- startLine := 1
- for i, b := range src {
- if i == start {
- break
- }
- if b == '\n' {
- startLine++
- }
- }
- s := bufio.NewScanner(bytes.NewReader(src[start:end]))
- for n := startLine; s.Scan(); n++ {
- l := s.Text()
- if strings.HasSuffix(l, "OMIT") {
- continue
- }
- lines = append(lines, codeLine{L: l, N: n})
- }
- // Trim leading and trailing blank lines.
- for len(lines) > 0 && len(lines[0].L) == 0 {
- lines = lines[1:]
- }
- for len(lines) > 0 && len(lines[len(lines)-1].L) == 0 {
- lines = lines[:len(lines)-1]
- }
- return
-}
-
-func parseArgs(name string, line int, args []string) (res []interface{}, err error) {
- res = make([]interface{}, len(args))
- for i, v := range args {
- if len(v) == 0 {
- return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
- }
- switch v[0] {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- n, err := strconv.Atoi(v)
- if err != nil {
- return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
- }
- res[i] = n
- case '/':
- if len(v) < 2 || v[len(v)-1] != '/' {
- return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
- }
- res[i] = v
- case '$':
- res[i] = "$"
- default:
- return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
- }
- }
- return
-}
-
-// parseArg returns the integer or string value of the argument and tells which it is.
-func parseArg(arg interface{}, max int) (ival int, sval string, isInt bool, err error) {
- switch n := arg.(type) {
- case int:
- if n <= 0 || n > max {
- return 0, "", false, fmt.Errorf("%d is out of range", n)
- }
- return n, "", true, nil
- case string:
- return 0, n, false, nil
- }
- return 0, "", false, fmt.Errorf("unrecognized argument %v type %T", arg, arg)
-}
-
-// match identifies the input line that matches the pattern in a code invocation.
-// If start>0, match lines starting there rather than at the beginning.
-// The return value is 1-indexed.
-func match(file string, start int, lines []string, pattern string) (int, error) {
- // $ matches the end of the file.
- if pattern == "$" {
- if len(lines) == 0 {
- return 0, fmt.Errorf("%q: empty file", file)
- }
- return len(lines), nil
- }
- // /regexp/ matches the line that matches the regexp.
- if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
- re, err := regexp.Compile(pattern[1 : len(pattern)-1])
- if err != nil {
- return 0, err
- }
- for i := start; i < len(lines); i++ {
- if re.MatchString(lines[i]) {
- return i + 1, nil
- }
- }
- return 0, fmt.Errorf("%s: no match for %#q", file, pattern)
- }
- return 0, fmt.Errorf("unrecognized pattern: %q", pattern)
-}