// Use standard Go templates
func render(s string, funcs Funcs, vars Vars) (string, error) {
- f := Funcs{}
- for k, v := range funcs {
- f[k] = v
- }
- for k, v := range vars {
- f[k] = varFunc(v)
- }
- // Plugin functions
- files, _ := ioutil.ReadDir(ZSDIR)
- for _, file := range files {
- if !file.IsDir() {
- name := file.Name()
- if !strings.HasSuffix(name, ".html") && !strings.HasSuffix(name, ".amber") {
- f[strings.TrimSuffix(name, filepath.Ext(name))] = pluginFunc(name, vars)
- }
- }
- }
-
+ f := makeFuncs(funcs, vars)
tmpl, err := template.New("").Funcs(template.FuncMap(f)).Parse(s)
if err != nil {
return "", err
if err != nil {
return err
}
- v["content"] = string(blackfriday.MarkdownBasic([]byte(content)))
+ v["content"] = string(blackfriday.MarkdownCommon([]byte(content)))
if w == nil {
out, err := os.Create(filepath.Join(PUBDIR, renameExt(path, "", ".html")))
if err != nil {
for k, v := range vars {
data[k] = v
}
- for k, v := range funcs {
+ for k, v := range makeFuncs(funcs, Vars{}) {
data[k] = v
}
case "watch":
buildAll(true)
case "var":
- fmt.Println(Var(args))
+ fmt.Println(Var(args...))
case "lorem":
- fmt.Println(Lorem(args))
+ fmt.Println(Lorem(args...))
case "dateparse":
- fmt.Println(DateParse(args))
+ fmt.Println(DateParse(args...))
case "datefmt":
- fmt.Println(DateFmt(args))
+ fmt.Println(DateFmt(args...))
case "wc":
- fmt.Println(WordCount(args))
- case "timetoread":
- fmt.Println(TimeToRead(args))
+ fmt.Println(WordCount(args...))
+ case "ttr":
+ fmt.Println(TimeToRead(args...))
+ case "ls":
+ fmt.Println(strings.Join(List(args...), "\n"))
+ case "sort":
+ fmt.Println(strings.Join(Sort(args...), "\n"))
+ case "exec":
+ // TODO
default:
err := run(path.Join(ZSDIR, cmd), args, globals(), os.Stdout)
if err != nil {
import (
"bytes"
+ "log"
"os"
+ "path/filepath"
+ "sort"
"strconv"
"strings"
"time"
// zs var <filename> -- returns list of variables and their values
// zs var <filename> <var...> -- returns list of variable values
-func Var(args []string) string {
+func Var(args ...string) string {
if len(args) == 0 {
return "var: filename expected"
} else {
}
// zs lorem <n> -- returns <n> random lorem ipsum sentences
-func Lorem(args []string) string {
+func Lorem(args ...string) string {
if len(args) > 1 {
return "lorem: invalid usage"
}
}
// zs datefmt <fmt> <date> -- returns formatted date from unix time
-func DateFmt(args []string) string {
+func DateFmt(args ...string) string {
if len(args) == 0 || len(args) > 2 {
return "datefmt: invalid usage"
}
}
// zs dateparse <fmt> <date> -- returns unix time from the formatted date
-func DateParse(args []string) string {
+func DateParse(args ...string) string {
if len(args) == 0 || len(args) > 2 {
return "dateparse: invalid usage"
}
}
// zs wc <file> -- returns word count in the file (markdown, html or amber)
-func WordCount(args []string) int {
+func WordCount(args ...string) int {
if os.Getenv("ZS_RECURSION") != "" {
return 0
}
}
// zs timetoread <file> -- returns number of minutes required to read the text
-func TimeToRead(args []string) int {
- wc := WordCount(args)
+func TimeToRead(args ...string) int {
+ wc := WordCount(args...)
return int(math.Floor(float64(wc)/200.0 + .5))
}
+
+// zs ls <dir> <regexp>
+func List(args ...string) []string {
+ if len(args) != 2 {
+ return []string{}
+ }
+
+ dir := args[0]
+ mask := args[1]
+
+ res := []string{}
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return nil
+ }
+ if !info.IsDir() {
+ if ok, err := filepath.Match(mask, info.Name()); ok && err == nil {
+ res = append(res, path)
+ }
+ }
+ return nil
+ })
+ return res
+}
+
+// zs sort <key> <files...>
+func Sort(args ...string) []string {
+ delim := -1
+ for i, s := range args {
+ if s == "--" {
+ delim = i
+ }
+ }
+ cmd := []string{"var", "title"}
+ if delim != -1 {
+ cmd = args[:delim]
+ args = args[delim+1:]
+ }
+
+ sorted := map[string][]string{}
+ sortedKeys := []string{}
+ for _, f := range args {
+ params := append(cmd, f)
+ out := bytes.NewBuffer(nil)
+ run(os.Args[0], params, globals(), out)
+ val := string(out.Bytes())
+ sorted[val] = append(sorted[val], f)
+ sortedKeys = append(sortedKeys, val)
+ }
+ log.Println(sortedKeys)
+ sort.Strings(sortedKeys)
+ if !asc {
+ }
+
+ list := []string{}
+ for _, k := range sortedKeys {
+ vals := sorted[k]
+ sort.Strings(vals)
+ list = append(list, vals...)
+ }
+ return list
+}
import (
"bytes"
"io"
+ "io/ioutil"
"log"
"os"
"os/exec"
"strings"
)
+func makeFuncs(funcs Funcs, vars Vars) Funcs {
+ f := Funcs{}
+ for k, v := range funcs {
+ f[k] = v
+ }
+ for k, v := range vars {
+ f[k] = varFunc(v)
+ }
+ // Plugin functions
+ files, _ := ioutil.ReadDir(ZSDIR)
+ for _, file := range files {
+ if !file.IsDir() {
+ name := file.Name()
+ if !strings.HasSuffix(name, ".html") && !strings.HasSuffix(name, ".amber") {
+ f[renameExt(name, "", "")] = pluginFunc(name, vars)
+ } else {
+ f[renameExt(name, "", "")] = partialFunc(name, f, vars)
+ }
+ }
+ }
+ return f
+}
+
func varFunc(s string) func() string {
return func() string {
return s
}
}
+func partialFunc(name string, funcs Funcs, vars Vars) func() string {
+ return func() string {
+ var err error
+ w := bytes.NewBuffer(nil)
+ if strings.HasSuffix(name, ".amber") {
+ err = buildAmber(filepath.Join(ZSDIR, name), w, funcs, vars)
+ } else {
+ err = buildHTML(filepath.Join(ZSDIR, name), w, funcs, vars)
+ }
+ if err != nil {
+ return name + ":" + err.Error()
+ }
+ return string(w.Bytes())
+ }
+}
+
func builtins() Funcs {
exec := func(cmd string, args ...string) string {
out := bytes.NewBuffer(nil)
return ""
}
return Funcs{
- "exec": exec,
- "zs": func(args ...string) string {
- return exec(os.Args[0], args...)
+ "exec": exec,
+ "var": Var,
+ "lorem": Lorem,
+ "dateparse": DateParse,
+ "datefmt": DateFmt,
+ "wc": WordCount,
+ "ttr": TimeToRead,
+ "ls": List,
+ "...": func(args ...string) []string {
+ return append([]string{"..."}, args...)
+ },
+ "sort": func(args ...string) []string {
+
+ return Sort(args...)
},
}
}