.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / present / code.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/present/code.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/present/code.go
new file mode 100644 (file)
index 0000000..eb91555
--- /dev/null
@@ -0,0 +1,270 @@
+// 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"
+)
+
+// PlayEnabled specifies whether runnable playground snippets should be
+// displayed in the present user interface.
+var PlayEnabled = false
+
+// TODO(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.
+
+// NotesEnabled specifies whether presenter notes should be displayed in the
+// present user interface.
+var NotesEnabled = false
+
+func init() {
+       Register("code", parseCode)
+       Register("play", parseCode)
+}
+
+type Code struct {
+       Cmd      string // original command from present source
+       Text     template.HTML
+       Play     bool   // runnable code
+       Edit     bool   // editable code
+       FileName string // file name
+       Ext      string // file extension
+       Raw      []byte // content of the file
+}
+
+func (c Code) PresentCmd() string   { return c.Cmd }
+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+((?:(?:-edit|-numbers)\s+)*)([^\s]+)(?:\s+(.*))?$`)
+)
+
+// parseCode parses a code present directive. Its syntax:
+//   .code [-numbers] [-edit] <filename> [address] [highlight]
+// The directive may also be ".play" if the snippet is executable.
+func parseCode(ctx *Context, sourceFile string, sourceLine int, cmd string) (Elem, error) {
+       cmd = strings.TrimSpace(cmd)
+       origCmd := cmd
+
+       // Pull off the HL, if any, from the end of the input line.
+       highlight := ""
+       if hl := highlightRE.FindStringSubmatchIndex(cmd); len(hl) == 4 {
+               if hl[2] < 0 || hl[3] < 0 {
+                       return nil, fmt.Errorf("%s:%d invalid highlight syntax", sourceFile, sourceLine)
+               }
+               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]: flags ("-edit -numbers")
+       // args[3]: file name
+       // 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, flags, file, addr := args[1], args[2], args[3], 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)
+       }
+       if lo > hi {
+               // The search in addrToByteRange can wrap around so we might
+               // end up with the range ending before its starting point
+               hi, lo = lo, hi
+       }
+
+       // 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)
+
+       data := &codeTemplateData{
+               Lines:   formatLines(lines, highlight),
+               Edit:    strings.Contains(flags, "-edit"),
+               Numbers: strings.Contains(flags, "-numbers"),
+       }
+
+       // 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{
+               Cmd:      origCmd,
+               Text:     template.HTML(buf.String()),
+               Play:     play,
+               Edit:     data.Edit,
+               FileName: filepath.Base(filename),
+               Ext:      filepath.Ext(filename),
+               Raw:      rawCode(lines),
+       }, nil
+}
+
+// formatLines returns a new slice of codeLine with the given lines
+// replacing tabs with spaces and adding highlighting where needed.
+func formatLines(lines []codeLine, highlight string) []codeLine {
+       formatted := make([]codeLine, len(lines))
+       for i, line := range lines {
+               // Replace tabs with 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
+               }
+
+               formatted[i] = line
+       }
+       return formatted
+}
+
+// rawCode returns the code represented by the given codeLines without any kind
+// of formatting.
+func rawCode(lines []codeLine) []byte {
+       b := new(bytes.Buffer)
+       for _, line := range lines {
+               b.WriteString(line.L)
+               b.WriteByte('\n')
+       }
+       return b.Bytes()
+}
+
+type codeTemplateData struct {
+       Lines          []codeLine
+       Prefix, Suffix []byte
+       Edit, Numbers  bool
+}
+
+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}}<pre style="display: none"><span>{{printf "%s" .}}</span></pre>{{end -}}
+
+<pre{{if .Edit}} contenteditable="true" spellcheck="false"{{end}}{{if .Numbers}} class="numbers"{{end}}>{{/*
+       */}}{{range .Lines}}<span num="{{.N}}">{{/*
+       */}}{{if .HL}}{{leadingSpace .L}}<b>{{trimSpace .L}}</b>{{/*
+       */}}{{else}}{{.L}}{{end}}{{/*
+*/}}</span>
+{{end}}</pre>
+{{with .Suffix}}<pre style="display: none"><span>{{printf "%s" .}}</span></pre>{{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] = "$"
+               case '_':
+                       if len(v) == 1 {
+                               // Do nothing; "_" indicates an intentionally empty parameter.
+                               break
+                       }
+                       fallthrough
+               default:
+                       return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
+               }
+       }
+       return
+}