zk/core/note/format.go

127 lines
3.2 KiB
Go
Raw Normal View History

2021-01-19 20:05:16 +00:00
package note
import (
"path/filepath"
"regexp"
"strings"
"time"
"github.com/mickael-menu/zk/core/style"
"github.com/mickael-menu/zk/core/templ"
"github.com/mickael-menu/zk/util/opt"
)
// Formatter formats notes to be printed on the screen.
type Formatter struct {
basePath string
currentPath string
renderer templ.Renderer
// Regex replacement for a term marked in a snippet.
snippetTermReplacement string
}
// NewFormatter creates a Formatter from a given format template.
//
// The absolute path to the slip box (basePath) and the working directory
// (currentPath) are used to make the path of each note relative to the working
// directory.
func NewFormatter(basePath string, currentPath string, format opt.String, templates templ.Loader, styler style.Styler) (*Formatter, error) {
template := resolveFormatTemplate(format)
renderer, err := templates.Load(template)
if err != nil {
return nil, err
}
termRepl, err := styler.Style("$1", style.RuleTerm)
if err != nil {
return nil, err
}
return &Formatter{
basePath: basePath,
currentPath: currentPath,
renderer: renderer,
snippetTermReplacement: termRepl,
}, nil
}
func resolveFormatTemplate(format opt.String) string {
templ, ok := formatTemplates[format.OrDefault("short")]
if !ok {
templ = format.String()
// Replace raw \n and \t by actual newlines and tabs in user format.
templ = strings.ReplaceAll(templ, "\\n", "\n")
templ = strings.ReplaceAll(templ, "\\t", "\t")
}
return templ
}
var formatTemplates = map[string]string{
"path": `{{path}}`,
"oneline": `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})`,
"short": `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})
2021-01-30 18:30:46 +00:00
{{list snippets}}`,
2021-01-19 20:05:16 +00:00
"medium": `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
2021-01-30 18:30:46 +00:00
{{list snippets}}`,
2021-01-19 20:05:16 +00:00
"long": `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Modified: {{date created "short"}}
2021-01-30 18:30:46 +00:00
{{list snippets}}`,
2021-01-19 20:05:16 +00:00
"full": `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Modified: {{date created "short"}}
2021-01-23 12:29:14 +00:00
{{prepend " " body}}
`,
2021-01-19 20:05:16 +00:00
}
var termRegex = regexp.MustCompile(`<zk:match>(.*?)</zk:match>`)
// Format formats a note to be printed on the screen.
func (f *Formatter) Format(match Match) (string, error) {
path, err := filepath.Rel(f.currentPath, filepath.Join(f.basePath, match.Path))
if err != nil {
return "", err
}
snippets := make([]string, 0)
for _, snippet := range match.Snippets {
snippets = append(snippets, termRegex.ReplaceAllString(snippet, f.snippetTermReplacement))
}
2021-01-19 20:05:16 +00:00
return f.renderer.Render(formatRenderContext{
Path: path,
Title: match.Title,
Lead: match.Lead,
Body: match.Body,
Snippets: snippets,
2021-01-19 20:05:16 +00:00
RawContent: match.RawContent,
WordCount: match.WordCount,
Created: match.Created,
Modified: match.Modified,
2021-01-19 22:06:17 +00:00
Checksum: match.Checksum,
2021-01-19 20:05:16 +00:00
})
}
type formatRenderContext struct {
Path string
Title string
Lead string
Body string
Snippets []string
2021-01-19 20:05:16 +00:00
RawContent string `handlebars:"raw-content"`
WordCount int `handlebars:"word-count"`
Created time.Time
Modified time.Time
2021-01-19 22:06:17 +00:00
Checksum string
2021-01-19 20:05:16 +00:00
}