1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 Fonts are demarcated by an initial and final char bracketing a
18 space-delimited word, plus possibly some terminal punctuation.
22 ` (back quote) for fixed width.
23 Inner appearances of the char become spaces. For instance,
26 <i>this is italic</i>!
30 funcs["style"] = Style
33 // Style returns s with HTML entities escaped and font indicators turned into
35 func Style(s string) template.HTML {
36 return template.HTML(font(html.EscapeString(s)))
39 // font returns s with font indicators turned into HTML font tags.
40 func font(s string) string {
41 if !strings.ContainsAny(s, "[`_*") {
47 for w, word := range words {
51 if link, _ := parseInlineLink(word); link != "" {
56 // Initial punctuation is OK but must be peeled off.
57 first := strings.IndexAny(word, marker)
61 // Opening marker must be at the beginning of the token or else preceded by punctuation.
63 r, _ := utf8.DecodeLastRuneInString(word[:first])
64 if !unicode.IsPunct(r) {
68 open, word := word[:first], word[first:]
69 char := word[0] // ASCII is OK.
84 // Closing marker must be at the end of the token or else followed by punctuation.
85 last := strings.LastIndex(word, word[:1])
89 if last+1 != len(word) {
90 r, _ := utf8.DecodeRuneInString(word[last+1:])
91 if !unicode.IsPunct(r) {
95 head, tail := word[:last+1], word[last+1:]
99 for i := 1; i < len(head)-1; i += wid {
101 r, wid = utf8.DecodeRuneInString(head[i:])
103 // Ordinary character.
107 if head[i+1] != char {
108 // Inner char becomes space.
112 // Doubled char becomes real char.
113 // Not worth worrying about "_x__".
115 wid++ // Consumed two chars, both ASCII.
117 b.WriteString(close) // Write closing tag.
118 b.WriteString(tail) // Restore trailing punctuation.
119 words[w] = b.String()
121 return strings.Join(words, "")
124 // split is like strings.Fields but also returns the runs of spaces
125 // and treats inline links as distinct words.
126 func split(s string) []string {
128 words = make([]string, 0, 10)
132 // appendWord appends the string s[start:end] to the words slice.
133 // If the word contains the beginning of a link, the non-link portion
134 // of the word and the entire link are appended as separate words,
135 // and the start index is advanced to the end of the link.
136 appendWord := func(end int) {
137 if j := strings.Index(s[start:end], "[["); j > -1 {
138 if _, l := parseInlineLink(s[start+j:]); l > 0 {
139 // Append portion before link, if any.
141 words = append(words, s[start:start+j])
143 // Append link itself.
144 words = append(words, s[start+j:start+j+l])
145 // Advance start index to end of link.
146 start = start + j + l
150 // No link; just add the word.
151 words = append(words, s[start:end])
156 for i, r := range s {
157 isSpace := unicode.IsSpace(r)
158 if i > start && isSpace != wasSpace {