mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-03-05 20:49:04 -08:00
feat(template): add global Version property
This commit is contained in:
parent
85a86be703
commit
93649abc21
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
|
@ -10,10 +10,13 @@
|
|||
"args": [
|
||||
"prompt",
|
||||
"print",
|
||||
"primary",
|
||||
"right",
|
||||
"--shell=pwsh",
|
||||
"--terminal-width=200"
|
||||
]
|
||||
],
|
||||
"env": {
|
||||
"POSH_THEME": "C:\\Users\\jande\\.posh.omp.jsonc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Tooltip",
|
||||
|
|
11
src/cache/template.go
vendored
11
src/cache/template.go
vendored
|
@ -8,19 +8,20 @@ type Template struct {
|
|||
SegmentsCache maps.Simple
|
||||
Segments *maps.Concurrent
|
||||
Var maps.Simple
|
||||
ShellVersion string
|
||||
AbsolutePWD string
|
||||
PWD string
|
||||
Folder string
|
||||
PSWD string
|
||||
UserName string
|
||||
HostName string
|
||||
PWD string
|
||||
ShellVersion string
|
||||
Shell string
|
||||
Folder string
|
||||
AbsolutePWD string
|
||||
OS string
|
||||
Code int
|
||||
Version string
|
||||
PromptCount int
|
||||
SHLVL int
|
||||
Jobs int
|
||||
Code int
|
||||
WSL bool
|
||||
Root bool
|
||||
}
|
||||
|
|
|
@ -7,10 +7,9 @@ import (
|
|||
|
||||
type Battery struct {
|
||||
base
|
||||
|
||||
*battery.Info
|
||||
Error string
|
||||
Icon string
|
||||
battery.Info
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -34,15 +33,16 @@ func (b *Battery) Enabled() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
var err error
|
||||
b.Info, err = b.env.BatteryState()
|
||||
info, err := b.env.BatteryState()
|
||||
|
||||
if !b.enabledWhileError(err) {
|
||||
return false
|
||||
}
|
||||
|
||||
b.Info = *info
|
||||
|
||||
// case on computer without batteries(no error, empty array)
|
||||
if err == nil && b.Info == nil {
|
||||
if err == nil && b.Info.Percentage == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/build"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/maps"
|
||||
|
@ -36,6 +37,7 @@ func loadCache(vars maps.Simple) {
|
|||
Cache.PromptCount = env.Flags().PromptCount
|
||||
Cache.Var = make(map[string]any)
|
||||
Cache.Jobs = env.Flags().JobCount
|
||||
Cache.Version = build.Version
|
||||
|
||||
if vars != nil {
|
||||
Cache.Var = vars
|
||||
|
|
|
@ -19,14 +19,15 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
shell string
|
||||
env runtime.Environment
|
||||
knownVariables []string
|
||||
shell string
|
||||
env runtime.Environment
|
||||
knownFields *maps.Concurrent
|
||||
)
|
||||
|
||||
func Init(environment runtime.Environment, vars maps.Simple) {
|
||||
env = environment
|
||||
shell = env.Shell()
|
||||
knownFields = maps.NewConcurrent()
|
||||
|
||||
renderPool = sync.Pool{
|
||||
New: func() any {
|
||||
|
@ -34,29 +35,6 @@ func Init(environment runtime.Environment, vars maps.Simple) {
|
|||
},
|
||||
}
|
||||
|
||||
knownVariables = []string{
|
||||
"Root",
|
||||
"PWD",
|
||||
"AbsolutePWD",
|
||||
"PSWD",
|
||||
"Folder",
|
||||
"Shell",
|
||||
"ShellVersion",
|
||||
"UserName",
|
||||
"HostName",
|
||||
"Code",
|
||||
"Env",
|
||||
"OS",
|
||||
"WSL",
|
||||
"PromptCount",
|
||||
"Segments",
|
||||
"SHLVL",
|
||||
"Templates",
|
||||
"Var",
|
||||
"Data",
|
||||
"Jobs",
|
||||
}
|
||||
|
||||
if Cache != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||
)
|
||||
|
||||
type Text struct {
|
||||
|
@ -31,29 +30,6 @@ func (t *Text) Render() (string, error) {
|
|||
}
|
||||
|
||||
func (t *Text) patchTemplate() {
|
||||
isKnownVariable := func(variable string) bool {
|
||||
variable = strings.TrimPrefix(variable, ".")
|
||||
splitted := strings.Split(variable, ".")
|
||||
|
||||
if len(splitted) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
variable = splitted[0]
|
||||
// check if alphanumeric
|
||||
if !regex.MatchString(`^[a-zA-Z0-9]+$`, variable) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, b := range knownVariables {
|
||||
if variable == b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fields := make(fields)
|
||||
fields.init(t.Context)
|
||||
|
||||
|
@ -70,10 +46,12 @@ func (t *Text) patchTemplate() {
|
|||
inTemplate = false
|
||||
}
|
||||
}
|
||||
|
||||
if !inTemplate {
|
||||
result += string(char)
|
||||
continue
|
||||
}
|
||||
|
||||
switch char {
|
||||
case '.':
|
||||
var lastChar rune
|
||||
|
@ -96,9 +74,6 @@ func (t *Text) patchTemplate() {
|
|||
}
|
||||
|
||||
switch {
|
||||
case !isKnownVariable(property):
|
||||
// end of a variable, needs to be appended
|
||||
result += ".Data" + property
|
||||
case strings.HasPrefix(property, ".Segments") && !strings.HasSuffix(property, ".Contains"):
|
||||
// as we can't provide a clean way to access the list
|
||||
// of segments, we need to replace the property with
|
||||
|
@ -149,10 +124,48 @@ func (f *fields) init(data any) {
|
|||
val := reflect.TypeOf(data)
|
||||
switch val.Kind() { //nolint:exhaustive
|
||||
case reflect.Struct:
|
||||
name := val.Name()
|
||||
|
||||
// ignore the base struct
|
||||
if name == "base" {
|
||||
return
|
||||
}
|
||||
|
||||
// check if we already know the fields of this struct
|
||||
if kf, OK := knownFields.Get(name); OK {
|
||||
for key := range kf.(fields) {
|
||||
(*f)[key] = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get struct fields and check embedded types
|
||||
fieldsNum := val.NumField()
|
||||
for i := 0; i < fieldsNum; i++ {
|
||||
(*f)[val.Field(i).Name] = true
|
||||
field := val.Field(i)
|
||||
(*f)[field.Name] = true
|
||||
|
||||
// If this is an embedded field, get its methods too
|
||||
if !field.Anonymous {
|
||||
continue
|
||||
}
|
||||
|
||||
embeddedType := field.Type
|
||||
|
||||
// Recursively check if the embedded type is also a struct
|
||||
if embeddedType.Kind() == reflect.Struct {
|
||||
f.init(reflect.New(embeddedType).Elem().Interface())
|
||||
}
|
||||
}
|
||||
|
||||
// Get pointer methods
|
||||
ptrType := reflect.PointerTo(val)
|
||||
methodsNum := ptrType.NumMethod()
|
||||
for i := 0; i < methodsNum; i++ {
|
||||
(*f)[ptrType.Method(i).Name] = true
|
||||
}
|
||||
|
||||
knownFields.Set(name, *f)
|
||||
case reflect.Map:
|
||||
m, ok := data.(map[string]any)
|
||||
if !ok {
|
||||
|
@ -168,6 +181,11 @@ func (f *fields) init(data any) {
|
|||
|
||||
func (f fields) hasField(field string) bool {
|
||||
field = strings.TrimPrefix(field, ".")
|
||||
|
||||
// get the first part of the field
|
||||
splitted := strings.Split(field, ".")
|
||||
field = splitted[0]
|
||||
|
||||
_, ok := f[field]
|
||||
return ok
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ func TestRenderTemplate(t *testing.T) {
|
|||
type Me struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
Context any
|
||||
Case string
|
||||
|
@ -161,6 +162,11 @@ func TestRenderTemplate(t *testing.T) {
|
|||
Context: tc.Context,
|
||||
}
|
||||
|
||||
env := new(mock.Environment)
|
||||
env.On("Shell").Return("foo")
|
||||
Cache = new(cache.Template)
|
||||
Init(env, nil)
|
||||
|
||||
text, err := tmpl.Render()
|
||||
if tc.ShouldError {
|
||||
assert.Error(t, err)
|
||||
|
@ -204,7 +210,7 @@ func TestRenderTemplateEnvVar(t *testing.T) {
|
|||
},
|
||||
{Case: "no env var", Expected: "hello world", Template: "{{.Text}} world", Context: struct{ Text string }{Text: "hello"}},
|
||||
{Case: "map", Expected: "hello world", Template: "{{.Text}} world", Context: map[string]any{"Text": "hello"}},
|
||||
{Case: "empty map", Expected: " world", Template: "{{.Text}} world", Context: map[string]string{}},
|
||||
{Case: "empty map", Expected: " world", Template: "{{.Text}} world", Context: map[string]string{}, ShouldError: true},
|
||||
{
|
||||
Case: "Struct with duplicate property",
|
||||
Expected: "posh",
|
||||
|
@ -335,15 +341,22 @@ func TestPatchTemplate(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
env := &mock.Environment{}
|
||||
env := new(mock.Environment)
|
||||
env.On("Shell").Return("foo")
|
||||
|
||||
Cache = new(cache.Template)
|
||||
Init(env, nil)
|
||||
|
||||
for _, tc := range cases {
|
||||
tmpl := &Text{
|
||||
Template: tc.Template,
|
||||
Context: map[string]any{"OS": "posh"},
|
||||
Context: map[string]any{
|
||||
"OS": true,
|
||||
"World": true,
|
||||
"WorldTrend": "chaos",
|
||||
"Working": true,
|
||||
"Staging": true,
|
||||
"CPU": true,
|
||||
},
|
||||
}
|
||||
|
||||
tmpl.patchTemplate()
|
||||
|
@ -351,6 +364,27 @@ func TestPatchTemplate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type Foo struct{}
|
||||
|
||||
func (f *Foo) Hello() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
func TestPatchTemplateStruct(t *testing.T) {
|
||||
env := new(mock.Environment)
|
||||
env.On("Shell").Return("foo")
|
||||
Cache = new(cache.Template)
|
||||
Init(env, nil)
|
||||
|
||||
tmpl := &Text{
|
||||
Template: "{{ .Hello }}",
|
||||
Context: Foo{},
|
||||
}
|
||||
|
||||
tmpl.patchTemplate()
|
||||
assert.Equal(t, "{{ .Data.Hello }}", tmpl.Template)
|
||||
}
|
||||
|
||||
func TestSegmentContains(t *testing.T) {
|
||||
cases := []struct {
|
||||
Case string
|
||||
|
|
|
@ -35,6 +35,7 @@ it with `.$` to reference it directly.
|
|||
| `.WSL` | `boolean` | in WSL yes/no |
|
||||
| `.Templates` | `string` | the [templates][templates] result |
|
||||
| `.PromptCount` | `int` | the prompt counter, increments with 1 for every prompt invocation |
|
||||
| `.Version` | `string` | the Oh My Posh version |
|
||||
|
||||
## Environment variables
|
||||
|
||||
|
|
Loading…
Reference in a new issue