diff options
author | spf13 <steve.francia@gmail.com> | 2014-01-09 17:33:20 -0500 |
---|---|---|
committer | spf13 <steve.francia@gmail.com> | 2014-01-10 21:27:32 -0500 |
commit | 3fd6c1a24e4f159ee300f0b6dbc177615455e5d6 (patch) | |
tree | 78f2653c3db0c1410277c1410b766f1c9a6396f8 /hugolib | |
parent | 13b067b5064cc1c59ade383612906fce944dcf33 (diff) |
Adding some embedded short codes (including code highlighting)
Diffstat (limited to 'hugolib')
-rw-r--r-- | hugolib/shortcode.go | 332 |
1 files changed, 169 insertions, 163 deletions
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go index 2e91e02ea..f1fcca4d2 100644 --- a/hugolib/shortcode.go +++ b/hugolib/shortcode.go @@ -14,12 +14,12 @@ package hugolib import ( - "bytes" - "fmt" - "github.com/spf13/hugo/template/bundle" - "html/template" - "strings" - "unicode" + "bytes" + "fmt" + "github.com/spf13/hugo/template/bundle" + "html/template" + "strings" + "unicode" ) var _ = fmt.Println @@ -27,195 +27,201 @@ var _ = fmt.Println type ShortcodeFunc func([]string) string type Shortcode struct { - Name string - Func ShortcodeFunc + Name string + Func ShortcodeFunc } type ShortcodeWithPage struct { - Params interface{} - Inner template.HTML - Page *Page + Params interface{} + Inner template.HTML + Page *Page } type Shortcodes map[string]ShortcodeFunc func ShortcodesHandle(stringToParse string, p *Page, t bundle.Template) string { - leadStart := strings.Index(stringToParse, `{{%`) - if leadStart >= 0 { - leadEnd := strings.Index(stringToParse[leadStart:], `%}}`) + leadStart - if leadEnd > leadStart { - name, par := SplitParams(stringToParse[leadStart+3 : leadEnd]) - tmpl := GetTemplate(name, t) - if tmpl == nil { - return stringToParse - } - params := Tokenize(par) - // Always look for closing tag. - endStart, endEnd := FindEnd(stringToParse[leadEnd:], name) - var data = &ShortcodeWithPage{Params: params, Page: p} - if endStart > 0 { - s := stringToParse[leadEnd+3 : leadEnd+endStart] - data.Inner = template.HTML(CleanP(ShortcodesHandle(s, p, t))) - remainder := CleanP(stringToParse[leadEnd+endEnd:]) - - return CleanP(stringToParse[:leadStart]) + - ShortcodeRender(tmpl, data) + - CleanP(ShortcodesHandle(remainder, p, t)) - } - return CleanP(stringToParse[:leadStart]) + - ShortcodeRender(tmpl, data) + - CleanP(ShortcodesHandle(stringToParse[leadEnd+3:], p, - t)) - } - } - return stringToParse + leadStart := strings.Index(stringToParse, `{{%`) + if leadStart >= 0 { + leadEnd := strings.Index(stringToParse[leadStart:], `%}}`) + leadStart + if leadEnd > leadStart { + name, par := SplitParams(stringToParse[leadStart+3 : leadEnd]) + tmpl := GetTemplate(name, t) + if tmpl == nil { + return stringToParse + } + params := Tokenize(par) + // Always look for closing tag. + endStart, endEnd := FindEnd(stringToParse[leadEnd:], name) + var data = &ShortcodeWithPage{Params: params, Page: p} + if endStart > 0 { + s := stringToParse[leadEnd+3 : leadEnd+endStart] + data.Inner = template.HTML(CleanP(ShortcodesHandle(s, p, t))) + remainder := CleanP(stringToParse[leadEnd+endEnd:]) + + return CleanP(stringToParse[:leadStart]) + + ShortcodeRender(tmpl, data) + + CleanP(ShortcodesHandle(remainder, p, t)) + } + return CleanP(stringToParse[:leadStart]) + + ShortcodeRender(tmpl, data) + + CleanP(ShortcodesHandle(stringToParse[leadEnd+3:], p, + t)) + } + } + return stringToParse } // Clean up odd behavior when closing tag is on first line // or opening tag is on the last line due to extra line in markdown file func CleanP(str string) string { - if strings.HasSuffix(strings.TrimSpace(str), "<p>") { - idx := strings.LastIndex(str, "<p>") - str = str[:idx] - } + if strings.HasSuffix(strings.TrimSpace(str), "<p>") { + idx := strings.LastIndex(str, "<p>") + str = str[:idx] + } - if strings.HasPrefix(strings.TrimSpace(str), "</p>") { - str = str[strings.Index(str, "</p>")+5:] - } + if strings.HasPrefix(strings.TrimSpace(str), "</p>") { + str = str[strings.Index(str, "</p>")+5:] + } - return str + return str } func FindEnd(str string, name string) (int, int) { - var endPos int - var startPos int - var try []string - - try = append(try, "{{% /"+name+" %}}") - try = append(try, "{{% /"+name+"%}}") - try = append(try, "{{%/"+name+"%}}") - try = append(try, "{{%/"+name+" %}}") - - lowest := len(str) - for _, x := range try { - start := strings.Index(str, x) - if start < lowest && start > 0 { - startPos = start - endPos = startPos + len(x) - } - } - - return startPos, endPos + var endPos int + var startPos int + var try []string + + try = append(try, "{{% /"+name+" %}}") + try = append(try, "{{% /"+name+"%}}") + try = append(try, "{{%/"+name+"%}}") + try = append(try, "{{%/"+name+" %}}") + + lowest := len(str) + for _, x := range try { + start := strings.Index(str, x) + if start < lowest && start > 0 { + startPos = start + endPos = startPos + len(x) + } + } + + return startPos, endPos } func GetTemplate(name string, t bundle.Template) *template.Template { - return t.Lookup("shortcodes/" + name + ".html") + if x := t.Lookup("shortcodes/" + name + ".html"); x != nil { + return x + } + return t.Lookup("_internal/shortcodes/" + name + ".html") } func StripShortcodes(stringToParse string) string { - posStart := strings.Index(stringToParse, "{{%") - if posStart > 0 { - posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart - if posEnd > posStart { - newString := stringToParse[:posStart] + StripShortcodes(stringToParse[posEnd+3:]) - return newString - } - } - return stringToParse + posStart := strings.Index(stringToParse, "{{%") + if posStart > 0 { + posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart + if posEnd > posStart { + newString := stringToParse[:posStart] + StripShortcodes(stringToParse[posEnd+3:]) + return newString + } + } + return stringToParse } func Tokenize(in string) interface{} { - first := strings.Fields(in) - var final = make([]string, 0) - - // if don't need to parse, don't parse. - if strings.Index(in, " ") < 0 && strings.Index(in, "=") < 1 { - return append(final, in) - } - - var keys = make([]string, 0) - inQuote := false - start := 0 - - for i, v := range first { - index := strings.Index(v, "=") - - if !inQuote { - if index > 1 { - keys = append(keys, v[:index]) - v = v[index+1:] - } - } - - // Adjusted to handle htmlencoded and non htmlencoded input - if !strings.HasPrefix(v, "“") && !strings.HasPrefix(v, "\"") && !inQuote { - final = append(final, v) - } else if inQuote && (strings.HasSuffix(v, "”") || - strings.HasSuffix(v, "\"")) && !strings.HasSuffix(v, "\\\"") { - if strings.HasSuffix(v, "\"") { - first[i] = v[:len(v)-1] - } else { - first[i] = v[:len(v)-7] - } - final = append(final, strings.Join(first[start:i+1], " ")) - inQuote = false - } else if (strings.HasPrefix(v, "“") || - strings.HasPrefix(v, "\"")) && !inQuote { - if strings.HasSuffix(v, "”") || strings.HasSuffix(v, - "\"") { - if strings.HasSuffix(v, "\"") { - if len(v) > 1 { - final = append(final, v[1:len(v)-1]) - } else { - final = append(final, "") - } - } else { - final = append(final, v[7:len(v)-7]) - } - } else { - start = i - if strings.HasPrefix(v, "\"") { - first[i] = v[1:] - } else { - first[i] = v[7:] - } - inQuote = true - } - } - - // No closing "... just make remainder the final token - if inQuote && i == len(first) { - final = append(final, first[start:]...) - } - } - - if len(keys) > 0 && (len(keys) != len(final)) { - panic("keys and final different lengths") - } - - if len(keys) > 0 { - var m = make(map[string]string) - for i, k := range keys { - m[k] = final[i] - } - - return m - } - - return final + first := strings.Fields(in) + var final = make([]string, 0) + + // if don't need to parse, don't parse. + if strings.Index(in, " ") < 0 && strings.Index(in, "=") < 1 { + return append(final, in) + } + + var keys = make([]string, 0) + inQuote := false + start := 0 + + for i, v := range first { + index := strings.Index(v, "=") + + if !inQuote { + if index > 1 { + keys = append(keys, v[:index]) + v = v[index+1:] + } + } + + // Adjusted to handle htmlencoded and non htmlencoded input + if !strings.HasPrefix(v, "“") && !strings.HasPrefix(v, "\"") && !inQuote { + final = append(final, v) + } else if inQuote && (strings.HasSuffix(v, "”") || + strings.HasSuffix(v, "\"")) && !strings.HasSuffix(v, "\\\"") { + if strings.HasSuffix(v, "\"") { + first[i] = v[:len(v)-1] + } else { + first[i] = v[:len(v)-7] + } + final = append(final, strings.Join(first[start:i+1], " ")) + inQuote = false + } else if (strings.HasPrefix(v, "“") || + strings.HasPrefix(v, "\"")) && !inQuote { + if strings.HasSuffix(v, "”") || strings.HasSuffix(v, + "\"") { + if strings.HasSuffix(v, "\"") { + if len(v) > 1 { + final = append(final, v[1:len(v)-1]) + } else { + final = append(final, "") + } + } else { + final = append(final, v[7:len(v)-7]) + } + } else { + start = i + if strings.HasPrefix(v, "\"") { + first[i] = v[1:] + } else { + first[i] = v[7:] + } + inQuote = true + } + } + + // No closing "... just make remainder the final token + if inQuote && i == len(first) { + final = append(final, first[start:]...) + } + } + + if len(keys) > 0 && (len(keys) != len(final)) { + panic("keys and final different lengths") + } + + if len(keys) > 0 { + var m = make(map[string]string) + for i, k := range keys { + m[k] = final[i] + } + + return m + } + + return final } func SplitParams(in string) (name string, par2 string) { - i := strings.IndexFunc(strings.TrimSpace(in), unicode.IsSpace) - if i < 1 { - return strings.TrimSpace(in), "" - } + i := strings.IndexFunc(strings.TrimSpace(in), unicode.IsSpace) + if i < 1 { + return strings.TrimSpace(in), "" + } - return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:]) + return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:]) } func ShortcodeRender(tmpl *template.Template, data *ShortcodeWithPage) string { - buffer := new(bytes.Buffer) - tmpl.Execute(buffer, data) - return buffer.String() + buffer := new(bytes.Buffer) + err := tmpl.Execute(buffer, data) + if err != nil { + fmt.Println("error processing shortcode", tmpl.Name(), "\n ERR:", err) + } + return buffer.String() } |