Adding some embedded short codes (including code highlighting)
authorspf13 <steve.francia@gmail.com>
Thu, 9 Jan 2014 22:33:20 +0000 (17:33 -0500)
committerspf13 <steve.francia@gmail.com>
Sat, 11 Jan 2014 02:27:32 +0000 (21:27 -0500)
hugolib/shortcode.go
template/bundle/embedded.go [new file with mode: 0644]
template/bundle/template.go

index 2e91e02eac50f64cf0f07eefacae02f10e00f5ee..f1fcca4d28936f43f1fd9d5e101f153d5143d9ac 100644 (file)
 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, "&ldquo;") && !strings.HasPrefix(v, "\"") && !inQuote {
-                       final = append(final, v)
-               } else if inQuote && (strings.HasSuffix(v, "&rdquo;") ||
-                       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, "&ldquo;") ||
-                       strings.HasPrefix(v, "\"")) && !inQuote {
-                       if strings.HasSuffix(v, "&rdquo;") || 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, "&ldquo;") && !strings.HasPrefix(v, "\"") && !inQuote {
+            final = append(final, v)
+        } else if inQuote && (strings.HasSuffix(v, "&rdquo;") ||
+            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, "&ldquo;") ||
+            strings.HasPrefix(v, "\"")) && !inQuote {
+            if strings.HasSuffix(v, "&rdquo;") || 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()
 }
diff --git a/template/bundle/embedded.go b/template/bundle/embedded.go
new file mode 100644 (file)
index 0000000..41d2a1e
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright © 2013 Steve Francia <spf@spf13.com>.
+//
+// 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", `<!-- image -->
+<figure {{ if isset .Params "class" }}class="{{ index .Params "class" }}"{{ end }}>
+    {{ if isset .Params "link"}}<a href="{{ index .Params "link"}}">{{ end }}
+        <img src="{{ index .Params "src" }}" {{ if or (isset .Params "alt") (isset .Params "caption") }}alt="{{ if isset .Params "alt"}}{{ index .Params "alt"}}{{else}}{{ index .Params "caption" }}{{ end }}"{{ end }} />
+    {{ if isset .Params "link"}}</a>{{ end }}
+    {{ if or (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}}
+    <figcaption>{{ if isset .Params "title" }}
+        <h4>{{ index .Params "title" }}</h4>{{ end }}
+        {{ if or (isset .Params "caption") (isset .Params "attr")}}<p>
+        {{ index .Params "caption" }}
+        {{ if isset .Params "attrlink"}}<a href="{{ index .Params "attrlink"}}"> {{ end }}
+            {{ index .Params "attr" }}
+        {{ if isset .Params "attrlink"}}</a> {{ end }}
+        </p> {{ end }}
+    </figcaption>
+    {{ end }}
+</figure>
+<!-- image -->`)
+
+}
index 2137d01870d2b25afa6edae3db5e256eb7f01924..98a3920d0a3b34e6a31397392b603ed91224ce4a 100644 (file)
@@ -173,6 +173,7 @@ func NewTemplate() Template {
 }
 
 func (t *GoHtmlTemplate) LoadEmbedded() {
+    t.EmbedShortcodes()
 }
 
 func (t *GoHtmlTemplate) AddInternalTemplate(prefix, name, tpl string) error {