2022-01-26 06:54:36 -08:00
|
|
|
package template
|
2021-02-07 01:54:36 -08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2021-04-11 06:24:03 -07:00
|
|
|
"errors"
|
2022-01-12 14:39:34 -08:00
|
|
|
"fmt"
|
2022-01-26 01:23:18 -08:00
|
|
|
"oh-my-posh/environment"
|
|
|
|
"oh-my-posh/regex"
|
2021-05-26 12:12:58 -07:00
|
|
|
"strings"
|
2021-02-07 01:54:36 -08:00
|
|
|
"text/template"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Errors to show when the template handling fails
|
2022-01-26 06:54:36 -08:00
|
|
|
InvalidTemplate = "invalid template text"
|
|
|
|
IncorrectTemplate = "unable to create text based on template"
|
2021-02-07 01:54:36 -08:00
|
|
|
)
|
|
|
|
|
2022-01-26 06:54:36 -08:00
|
|
|
type Text struct {
|
2022-07-08 02:47:08 -07:00
|
|
|
Template string
|
|
|
|
Context interface{}
|
|
|
|
Env environment.Environment
|
|
|
|
TemplatesResult string
|
2021-02-07 01:54:36 -08:00
|
|
|
}
|
|
|
|
|
2022-01-12 14:39:34 -08:00
|
|
|
type Data interface{}
|
|
|
|
|
|
|
|
type Context struct {
|
2022-05-05 23:41:58 -07:00
|
|
|
*environment.TemplateCache
|
2022-01-18 00:48:47 -08:00
|
|
|
|
|
|
|
// Simple container to hold ANY object
|
|
|
|
Data
|
2022-07-08 02:47:08 -07:00
|
|
|
Templates string
|
2022-01-18 00:48:47 -08:00
|
|
|
}
|
|
|
|
|
2022-01-26 06:54:36 -08:00
|
|
|
func (c *Context) init(t *Text) {
|
2022-01-12 14:39:34 -08:00
|
|
|
c.Data = t.Context
|
2022-07-08 02:47:08 -07:00
|
|
|
c.Templates = t.TemplatesResult
|
2022-01-23 12:37:51 -08:00
|
|
|
if cache := t.Env.TemplateCache(); cache != nil {
|
2022-05-05 23:41:58 -07:00
|
|
|
c.TemplateCache = cache
|
2022-01-12 14:39:34 -08:00
|
|
|
return
|
2021-06-15 12:23:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-26 06:54:36 -08:00
|
|
|
func (t *Text) Render() (string, error) {
|
2022-01-12 14:39:34 -08:00
|
|
|
t.cleanTemplate()
|
2021-12-11 08:31:58 -08:00
|
|
|
tmpl, err := template.New("title").Funcs(funcMap()).Parse(t.Template)
|
2021-02-07 01:54:36 -08:00
|
|
|
if err != nil {
|
2022-05-12 11:12:25 -07:00
|
|
|
t.Env.Log(environment.Error, "Render", err.Error())
|
2022-01-26 06:54:36 -08:00
|
|
|
return "", errors.New(InvalidTemplate)
|
2021-02-07 01:54:36 -08:00
|
|
|
}
|
2022-01-12 14:39:34 -08:00
|
|
|
context := &Context{}
|
|
|
|
context.init(t)
|
2021-02-07 01:54:36 -08:00
|
|
|
buffer := new(bytes.Buffer)
|
|
|
|
defer buffer.Reset()
|
2022-01-12 14:39:34 -08:00
|
|
|
err = tmpl.Execute(buffer, context)
|
2021-02-07 01:54:36 -08:00
|
|
|
if err != nil {
|
2022-05-12 11:12:25 -07:00
|
|
|
t.Env.Log(environment.Error, "Render", err.Error())
|
2022-01-26 06:54:36 -08:00
|
|
|
return "", errors.New(IncorrectTemplate)
|
2021-02-07 01:54:36 -08:00
|
|
|
}
|
2021-05-26 12:12:58 -07:00
|
|
|
text := buffer.String()
|
|
|
|
// issue with missingkey=zero ignored for map[string]interface{}
|
|
|
|
// https://github.com/golang/go/issues/24963
|
|
|
|
text = strings.ReplaceAll(text, "<no value>", "")
|
|
|
|
return text, nil
|
|
|
|
}
|
|
|
|
|
2022-01-26 06:54:36 -08:00
|
|
|
func (t *Text) cleanTemplate() {
|
2022-01-12 14:39:34 -08:00
|
|
|
unknownVariable := func(variable string, knownVariables *[]string) (string, bool) {
|
|
|
|
variable = strings.TrimPrefix(variable, ".")
|
|
|
|
splitted := strings.Split(variable, ".")
|
|
|
|
if len(splitted) == 0 {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
for _, b := range *knownVariables {
|
|
|
|
if b == splitted[0] {
|
|
|
|
return "", false
|
|
|
|
}
|
2021-05-26 12:12:58 -07:00
|
|
|
}
|
2022-01-12 14:39:34 -08:00
|
|
|
*knownVariables = append(*knownVariables, splitted[0])
|
|
|
|
return splitted[0], true
|
2021-05-26 12:12:58 -07:00
|
|
|
}
|
2022-06-28 11:23:07 -07:00
|
|
|
|
2022-07-08 02:47:08 -07:00
|
|
|
knownVariables := []string{
|
|
|
|
"Root",
|
|
|
|
"PWD",
|
|
|
|
"Folder",
|
|
|
|
"Shell",
|
|
|
|
"ShellVersion",
|
|
|
|
"UserName",
|
|
|
|
"HostName",
|
|
|
|
"Env",
|
|
|
|
"Data",
|
|
|
|
"Code",
|
|
|
|
"OS",
|
|
|
|
"WSL",
|
|
|
|
"Segments",
|
|
|
|
"Templates",
|
|
|
|
}
|
2022-06-28 11:23:07 -07:00
|
|
|
matches := regex.FindAllNamedRegexMatch(`(?: |{|\()(?P<VAR>(\.[a-zA-Z_][a-zA-Z0-9]*)+)`, t.Template)
|
2021-05-26 12:12:58 -07:00
|
|
|
for _, match := range matches {
|
2022-06-28 11:23:07 -07:00
|
|
|
if variable, OK := unknownVariable(match["VAR"], &knownVariables); OK {
|
2022-01-12 14:39:34 -08:00
|
|
|
pattern := fmt.Sprintf(`\.%s\b`, variable)
|
|
|
|
dataVar := fmt.Sprintf(".Data.%s", variable)
|
2022-01-26 01:23:18 -08:00
|
|
|
t.Template = regex.ReplaceAllString(pattern, t.Template, dataVar)
|
2021-05-27 22:55:57 -07:00
|
|
|
}
|
2021-05-26 12:12:58 -07:00
|
|
|
}
|
2022-06-28 11:23:07 -07:00
|
|
|
// allow literal dots in template
|
|
|
|
t.Template = strings.ReplaceAll(t.Template, `\.`, ".")
|
2021-02-07 01:54:36 -08:00
|
|
|
}
|