Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / present / style.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/present/style.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/present/style.go
new file mode 100644 (file)
index 0000000..e2c228e
--- /dev/null
@@ -0,0 +1,167 @@
+// 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 (
+       "bytes"
+       "html"
+       "html/template"
+       "strings"
+       "unicode"
+       "unicode/utf8"
+)
+
+/*
+       Fonts are demarcated by an initial and final char bracketing a
+       space-delimited word, plus possibly some terminal punctuation.
+       The chars are
+               _ for italic
+               * for bold
+               ` (back quote) for fixed width.
+       Inner appearances of the char become spaces. For instance,
+               _this_is_italic_!
+       becomes
+               <i>this is italic</i>!
+*/
+
+func init() {
+       funcs["style"] = Style
+}
+
+// Style returns s with HTML entities escaped and font indicators turned into
+// HTML font tags.
+func Style(s string) template.HTML {
+       return template.HTML(font(html.EscapeString(s)))
+}
+
+// font returns s with font indicators turned into HTML font tags.
+func font(s string) string {
+       if !strings.ContainsAny(s, "[`_*") {
+               return s
+       }
+       words := split(s)
+       var b bytes.Buffer
+Word:
+       for w, word := range words {
+               if len(word) < 2 {
+                       continue Word
+               }
+               if link, _ := parseInlineLink(word); link != "" {
+                       words[w] = link
+                       continue Word
+               }
+               const marker = "_*`"
+               // Initial punctuation is OK but must be peeled off.
+               first := strings.IndexAny(word, marker)
+               if first == -1 {
+                       continue Word
+               }
+               // Opening marker must be at the beginning of the token or else preceded by punctuation.
+               if first != 0 {
+                       r, _ := utf8.DecodeLastRuneInString(word[:first])
+                       if !unicode.IsPunct(r) {
+                               continue Word
+                       }
+               }
+               open, word := word[:first], word[first:]
+               char := word[0] // ASCII is OK.
+               close := ""
+               switch char {
+               default:
+                       continue Word
+               case '_':
+                       open += "<i>"
+                       close = "</i>"
+               case '*':
+                       open += "<b>"
+                       close = "</b>"
+               case '`':
+                       open += "<code>"
+                       close = "</code>"
+               }
+               // Closing marker must be at the end of the token or else followed by punctuation.
+               last := strings.LastIndex(word, word[:1])
+               if last == 0 {
+                       continue Word
+               }
+               if last+1 != len(word) {
+                       r, _ := utf8.DecodeRuneInString(word[last+1:])
+                       if !unicode.IsPunct(r) {
+                               continue Word
+                       }
+               }
+               head, tail := word[:last+1], word[last+1:]
+               b.Reset()
+               b.WriteString(open)
+               var wid int
+               for i := 1; i < len(head)-1; i += wid {
+                       var r rune
+                       r, wid = utf8.DecodeRuneInString(head[i:])
+                       if r != rune(char) {
+                               // Ordinary character.
+                               b.WriteRune(r)
+                               continue
+                       }
+                       if head[i+1] != char {
+                               // Inner char becomes space.
+                               b.WriteRune(' ')
+                               continue
+                       }
+                       // Doubled char becomes real char.
+                       // Not worth worrying about "_x__".
+                       b.WriteByte(char)
+                       wid++ // Consumed two chars, both ASCII.
+               }
+               b.WriteString(close) // Write closing tag.
+               b.WriteString(tail)  // Restore trailing punctuation.
+               words[w] = b.String()
+       }
+       return strings.Join(words, "")
+}
+
+// split is like strings.Fields but also returns the runs of spaces
+// and treats inline links as distinct words.
+func split(s string) []string {
+       var (
+               words = make([]string, 0, 10)
+               start = 0
+       )
+
+       // appendWord appends the string s[start:end] to the words slice.
+       // If the word contains the beginning of a link, the non-link portion
+       // of the word and the entire link are appended as separate words,
+       // and the start index is advanced to the end of the link.
+       appendWord := func(end int) {
+               if j := strings.Index(s[start:end], "[["); j > -1 {
+                       if _, l := parseInlineLink(s[start+j:]); l > 0 {
+                               // Append portion before link, if any.
+                               if j > 0 {
+                                       words = append(words, s[start:start+j])
+                               }
+                               // Append link itself.
+                               words = append(words, s[start+j:start+j+l])
+                               // Advance start index to end of link.
+                               start = start + j + l
+                               return
+                       }
+               }
+               // No link; just add the word.
+               words = append(words, s[start:end])
+               start = end
+       }
+
+       wasSpace := false
+       for i, r := range s {
+               isSpace := unicode.IsSpace(r)
+               if i > start && isSpace != wasSpace {
+                       appendWord(i)
+               }
+               wasSpace = isSpace
+       }
+       for start < len(s) {
+               appendWord(len(s))
+       }
+       return words
+}