ref: 3fd6c1a24e4f159ee300f0b6dbc177615455e5d6
parent: 13b067b5064cc1c59ade383612906fce944dcf33
author: spf13 <steve.francia@gmail.com>
date: Thu Jan 9 12:33:20 EST 2014
Adding some embedded short codes (including code highlighting)
--- 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 @@
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), "<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
+ 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()
}
--- /dev/null
+++ b/template/bundle/embedded.go
@@ -1,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 -->`)
+
+}
--- a/template/bundle/template.go
+++ b/template/bundle/template.go
@@ -173,6 +173,7 @@
}
func (t *GoHtmlTemplate) LoadEmbedded() {+ t.EmbedShortcodes()
}
func (t *GoHtmlTemplate) AddInternalTemplate(prefix, name, tpl string) error {--
⑨