From 3fd6c1a24e4f159ee300f0b6dbc177615455e5d6 Mon Sep 17 00:00:00 2001 From: spf13 Date: Thu, 9 Jan 2014 17:33:20 -0500 Subject: [PATCH] Adding some embedded short codes (including code highlighting) --- hugolib/shortcode.go | 304 ++++++++++++++++++------------------ template/bundle/embedded.go | 45 ++++++ template/bundle/template.go | 1 + 3 files changed, 201 insertions(+), 149 deletions(-) create mode 100644 template/bundle/embedded.go 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:]) + 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 + 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), "

") { - idx := strings.LastIndex(str, "

") - str = str[:idx] - } + if strings.HasSuffix(strings.TrimSpace(str), "

") { + idx := strings.LastIndex(str, "

") + str = str[:idx] + } - if strings.HasPrefix(strings.TrimSpace(str), "

") { - str = str[strings.Index(str, "

")+5:] - } + if strings.HasPrefix(strings.TrimSpace(str), "

") { + str = str[strings.Index(str, "

")+5:] + } - return str + return str } func FindEnd(str string, name string) (int, int) { - var endPos int - var startPos int - var try []string + 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+" %}}") + 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) - } - } + 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 + 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) + 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) - } + // 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 + var keys = make([]string, 0) + inQuote := false + start := 0 - for i, v := range first { - index := strings.Index(v, "=") + for i, v := range first { + index := strings.Index(v, "=") - if !inQuote { - if index > 1 { - keys = append(keys, v[:index]) - v = v[index+1:] - } - } + 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 - } - } + // 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:]...) - } - } + // 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 && (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] - } + if len(keys) > 0 { + var m = make(map[string]string) + for i, k := range keys { + m[k] = final[i] + } - return m - } + return m + } - return final + 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() } diff --git a/template/bundle/embedded.go b/template/bundle/embedded.go new file mode 100644 index 000000000..41d2a1e05 --- /dev/null +++ b/template/bundle/embedded.go @@ -0,0 +1,45 @@ +// Copyright © 2013 Steve Francia . +// +// Licensed under the Simple Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://opensource.org/licenses/Simple-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bundle + +type Tmpl struct { + Name string + Data string +} + +func (t *GoHtmlTemplate) EmbedShortcodes() { + const k = "shortcodes" + + t.AddInternalTemplate(k, "highlight.html", `{{ $lang := index .Params 0 }}{{ highlight .Inner $lang }}`) + t.AddInternalTemplate(k, "test.html", `This is a simple Test`) + t.AddInternalTemplate(k, "figure.html", ` +
+ {{ if isset .Params "link"}}{{ end }} + + {{ if isset .Params "link"}}{{ end }} + {{ if or (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}} +
{{ if isset .Params "title" }} +

{{ index .Params "title" }}

{{ end }} + {{ if or (isset .Params "caption") (isset .Params "attr")}}

+ {{ index .Params "caption" }} + {{ if isset .Params "attrlink"}} {{ end }} + {{ index .Params "attr" }} + {{ if isset .Params "attrlink"}} {{ end }} +

{{ end }} +
+ {{ end }} +
+`) + +} diff --git a/template/bundle/template.go b/template/bundle/template.go index 2137d0187..98a3920d0 100644 --- a/template/bundle/template.go +++ b/template/bundle/template.go @@ -173,6 +173,7 @@ func NewTemplate() Template { } func (t *GoHtmlTemplate) LoadEmbedded() { + t.EmbedShortcodes() } func (t *GoHtmlTemplate) AddInternalTemplate(prefix, name, tpl string) error {