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 {--
⑨