mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-12-24 18:44:04 -08:00
refactor: move TemplateCache to template package
This commit is contained in:
parent
1a313f48ec
commit
077135e6cc
61
src/cache/path.go
vendored
Normal file
61
src/cache/path.go
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
)
|
||||
|
||||
func Path() string {
|
||||
defer log.Trace(time.Now())
|
||||
|
||||
returnOrBuildCachePath := func(input string) (string, bool) {
|
||||
// validate root path
|
||||
if _, err := os.Stat(input); err != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// validate oh-my-posh folder, if non existent, create it
|
||||
cachePath := filepath.Join(input, "oh-my-posh")
|
||||
if _, err := os.Stat(cachePath); err == nil {
|
||||
return cachePath, true
|
||||
}
|
||||
|
||||
if err := os.Mkdir(cachePath, 0o755); err != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return cachePath, true
|
||||
}
|
||||
|
||||
// allow the user to set the cache path using OMP_CACHE_DIR
|
||||
if cachePath, OK := returnOrBuildCachePath(os.Getenv("OMP_CACHE_DIR")); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
// WINDOWS cache folder, should not exist elsewhere
|
||||
if cachePath, OK := returnOrBuildCachePath(os.Getenv("LOCALAPPDATA")); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
// get XDG_CACHE_HOME if present
|
||||
if cachePath, OK := returnOrBuildCachePath(os.Getenv("XDG_CACHE_HOME")); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
// try to create the cache folder in the user's home directory if non-existent
|
||||
dotCache := filepath.Join(path.Home(), ".cache")
|
||||
if _, err := os.Stat(dotCache); err != nil {
|
||||
_ = os.Mkdir(dotCache, 0o755)
|
||||
}
|
||||
|
||||
// HOME cache folder
|
||||
if cachePath, OK := returnOrBuildCachePath(dotCache); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
return path.Home()
|
||||
}
|
|
@ -6,7 +6,6 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -34,18 +33,11 @@ You can do the following:
|
|||
return
|
||||
}
|
||||
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{},
|
||||
}
|
||||
|
||||
env.Init()
|
||||
defer env.Close()
|
||||
|
||||
switch args[0] {
|
||||
case "path":
|
||||
fmt.Println(env.CachePath())
|
||||
fmt.Println(cache.Path())
|
||||
case "clear":
|
||||
deletedFiles, err := cache.Clear(env.CachePath(), true)
|
||||
deletedFiles, err := cache.Clear(cache.Path(), true)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
|
@ -55,7 +47,7 @@ You can do the following:
|
|||
fmt.Println("removed cache file:", file)
|
||||
}
|
||||
case "edit":
|
||||
cacheFilePath := filepath.Join(env.CachePath(), cache.FileName)
|
||||
cacheFilePath := filepath.Join(cache.Path(), cache.FileName)
|
||||
os.Exit(editFileWithEditor(cacheFilePath))
|
||||
}
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -31,13 +31,8 @@ You can export, migrate or edit the config (via the editor specified in the envi
|
|||
}
|
||||
switch args[0] {
|
||||
case "edit":
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Config: configFlag,
|
||||
},
|
||||
}
|
||||
env.ResolveConfigPath()
|
||||
os.Exit(editFileWithEditor(env.CmdFlags.Config))
|
||||
path := config.Path((configFlag))
|
||||
os.Exit(editFileWithEditor(path))
|
||||
case "get":
|
||||
// only here for backwards compatibility
|
||||
fmt.Print(time.Now().UnixNano() / 1000000)
|
||||
|
|
|
@ -7,7 +7,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -39,14 +40,7 @@ Exports the current config to "~/new_config.omp.json" (in JSON format).`,
|
|||
os.Exit(2)
|
||||
}
|
||||
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Config: configFlag,
|
||||
},
|
||||
}
|
||||
env.Init()
|
||||
defer env.Close()
|
||||
cfg := config.Load(env)
|
||||
cfg := config.Load(configFlag, shell.GENERIC, false)
|
||||
|
||||
validateExportFormat := func() {
|
||||
format = strings.ToLower(format)
|
||||
|
@ -74,7 +68,7 @@ Exports the current config to "~/new_config.omp.json" (in JSON format).`,
|
|||
return
|
||||
}
|
||||
|
||||
cfg.Output = cleanOutputPath(output, env)
|
||||
cfg.Output = cleanOutputPath(output)
|
||||
|
||||
if len(format) == 0 {
|
||||
format = strings.TrimPrefix(filepath.Ext(output), ".")
|
||||
|
@ -85,16 +79,16 @@ Exports the current config to "~/new_config.omp.json" (in JSON format).`,
|
|||
},
|
||||
}
|
||||
|
||||
func cleanOutputPath(path string, env runtime.Environment) string {
|
||||
path = runtime.ReplaceTildePrefixWithHomeDir(env, path)
|
||||
func cleanOutputPath(output string) string {
|
||||
output = path.ReplaceTildePrefixWithHomeDir(output)
|
||||
|
||||
if !filepath.IsAbs(path) {
|
||||
if absPath, err := filepath.Abs(path); err == nil {
|
||||
path = absPath
|
||||
if !filepath.IsAbs(output) {
|
||||
if absPath, err := filepath.Abs(output); err == nil {
|
||||
output = absPath
|
||||
}
|
||||
}
|
||||
|
||||
return filepath.Clean(path)
|
||||
return filepath.Clean(output)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -50,31 +50,31 @@ Exports the config to an image file ~/mytheme.png.
|
|||
Exports the config to an image file using customized output options.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Config: configFlag,
|
||||
Shell: shell.GENERIC,
|
||||
TerminalWidth: 150,
|
||||
},
|
||||
cfg := config.Load(configFlag, shell.GENERIC, false)
|
||||
|
||||
flags := &runtime.Flags{
|
||||
Config: configFlag,
|
||||
Shell: shell.GENERIC,
|
||||
TerminalWidth: 150,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
defer env.Close()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
|
||||
template.Init(env)
|
||||
template.Init(env, cfg.Var)
|
||||
|
||||
cfg := config.Load(env)
|
||||
defer func() {
|
||||
template.SaveCache()
|
||||
env.Close()
|
||||
}()
|
||||
|
||||
// set sane defaults for things we don't print
|
||||
cfg.ConsoleTitleTemplate = ""
|
||||
cfg.PWD = ""
|
||||
|
||||
// add variables to the environment
|
||||
env.Var = cfg.Var
|
||||
|
||||
terminal.Init(shell.GENERIC)
|
||||
terminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()
|
||||
terminal.Colors = cfg.MakeColors()
|
||||
terminal.Colors = cfg.MakeColors(env)
|
||||
|
||||
eng := &prompt.Engine{
|
||||
Config: cfg,
|
||||
|
@ -90,7 +90,7 @@ Exports the config to an image file using customized output options.`,
|
|||
}
|
||||
|
||||
if outputImage != "" {
|
||||
imageCreator.Path = cleanOutputPath(outputImage, env)
|
||||
imageCreator.Path = cleanOutputPath(outputImage)
|
||||
}
|
||||
|
||||
err := imageCreator.Init(env)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -39,15 +40,17 @@ Migrates the ~/myconfig.omp.json config file to TOML and writes the result to yo
|
|||
A backup of the current config can be found at ~/myconfig.omp.json.bak.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Config: configFlag,
|
||||
Migrate: true,
|
||||
},
|
||||
cfg := config.Load(configFlag, shell.GENERIC, true)
|
||||
|
||||
flags := &runtime.Flags{
|
||||
Config: configFlag,
|
||||
Migrate: true,
|
||||
}
|
||||
env.Init()
|
||||
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
defer env.Close()
|
||||
cfg := config.Load(env)
|
||||
|
||||
if write {
|
||||
cfg.BackupAndMigrate()
|
||||
return
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -34,15 +35,15 @@ Migrates the ~/myconfig.omp.json config file's glyphs and writes the result to y
|
|||
A backup of the current config can be found at ~/myconfig.omp.json.bak.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Config: configFlag,
|
||||
},
|
||||
cfg := config.Load(configFlag, shell.GENERIC, false)
|
||||
|
||||
flags := &runtime.Flags{
|
||||
Config: configFlag,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
defer env.Close()
|
||||
cfg := config.Load(env)
|
||||
|
||||
cfg.MigrateGlyphs = true
|
||||
if len(format) == 0 {
|
||||
|
|
|
@ -36,29 +36,29 @@ func createDebugCmd() *cobra.Command {
|
|||
return
|
||||
}
|
||||
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Config: configFlag,
|
||||
Debug: true,
|
||||
PWD: pwd,
|
||||
Shell: args[0],
|
||||
Plain: plain,
|
||||
},
|
||||
cfg := config.Load(configFlag, args[0], false)
|
||||
|
||||
flags := &runtime.Flags{
|
||||
Config: configFlag,
|
||||
Debug: true,
|
||||
PWD: pwd,
|
||||
Shell: args[0],
|
||||
Plain: plain,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
defer env.Close()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
|
||||
template.Init(env)
|
||||
template.Init(env, cfg.Var)
|
||||
|
||||
cfg := config.Load(env)
|
||||
|
||||
// add variables to the environment
|
||||
env.Var = cfg.Var
|
||||
defer func() {
|
||||
template.SaveCache()
|
||||
env.Close()
|
||||
}()
|
||||
|
||||
terminal.Init(args[0])
|
||||
terminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()
|
||||
terminal.Colors = cfg.MakeColors()
|
||||
terminal.Colors = cfg.MakeColors(env)
|
||||
terminal.Plain = plain
|
||||
|
||||
eng := &prompt.Engine{
|
||||
|
|
|
@ -43,14 +43,13 @@ func init() {
|
|||
}
|
||||
|
||||
func toggleFeature(cmd *cobra.Command, feature string, enable bool) {
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Shell: shellName,
|
||||
SaveCache: true,
|
||||
},
|
||||
flags := &runtime.Flags{
|
||||
Shell: shellName,
|
||||
SaveCache: true,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
defer env.Close()
|
||||
|
||||
if len(feature) == 0 {
|
||||
|
|
|
@ -36,13 +36,12 @@ This command is used to install fonts and configure the font in your terminal.
|
|||
fontName = args[1]
|
||||
}
|
||||
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
SaveCache: true,
|
||||
},
|
||||
flags := &runtime.Flags{
|
||||
SaveCache: true,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
defer env.Close()
|
||||
|
||||
terminal.Init(env.Shell())
|
||||
|
|
|
@ -45,12 +45,12 @@ This command is used to get the value of the following variables:
|
|||
return
|
||||
}
|
||||
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Shell: shellName,
|
||||
},
|
||||
flags := &runtime.Flags{
|
||||
Shell: shellName,
|
||||
}
|
||||
env.Init()
|
||||
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
defer env.Close()
|
||||
|
||||
switch args[0] {
|
||||
|
|
|
@ -70,23 +70,26 @@ func runInit(sh string) {
|
|||
startTime = time.Now()
|
||||
}
|
||||
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
Shell: sh,
|
||||
Config: configFlag,
|
||||
Strict: strict,
|
||||
Debug: debug,
|
||||
},
|
||||
cfg := config.Load(configFlag, sh, false)
|
||||
|
||||
flags := &runtime.Flags{
|
||||
Shell: sh,
|
||||
Config: configFlag,
|
||||
Strict: strict,
|
||||
Debug: debug,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
defer env.Close()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
|
||||
template.Init(env)
|
||||
template.Init(env, cfg.Var)
|
||||
|
||||
cfg := config.Load(env)
|
||||
defer func() {
|
||||
template.SaveCache()
|
||||
env.Close()
|
||||
}()
|
||||
|
||||
feats := cfg.Features()
|
||||
feats := cfg.Features(env)
|
||||
|
||||
var output string
|
||||
|
||||
|
|
|
@ -15,13 +15,12 @@ var noticeCmd = &cobra.Command{
|
|||
Long: "Print the upgrade notice when a new version is available.",
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
SaveCache: true,
|
||||
},
|
||||
flags := &runtime.Flags{
|
||||
SaveCache: true,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
defer env.Close()
|
||||
|
||||
if notice, hasNotice := upgrade.Notice(env, false); hasNotice {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/prompt"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -81,7 +82,11 @@ func createPrintCmd() *cobra.Command {
|
|||
}
|
||||
|
||||
eng := prompt.New(flags)
|
||||
defer eng.Env.Close()
|
||||
|
||||
defer func() {
|
||||
template.SaveCache()
|
||||
eng.Env.Close()
|
||||
}()
|
||||
|
||||
switch args[0] {
|
||||
case prompt.DEBUG:
|
||||
|
|
|
@ -20,13 +20,12 @@ var toggleCmd = &cobra.Command{
|
|||
return
|
||||
}
|
||||
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: &runtime.Flags{
|
||||
SaveCache: true,
|
||||
},
|
||||
flags := &runtime.Flags{
|
||||
SaveCache: true,
|
||||
}
|
||||
|
||||
env.Init()
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
defer env.Close()
|
||||
|
||||
togglesCache, _ := env.Session().Get(cache.TOGGLECACHE)
|
||||
|
|
|
@ -33,7 +33,7 @@ var upgradeCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
env := &runtime.Terminal{}
|
||||
env.Init()
|
||||
env.Init(nil)
|
||||
defer env.Close()
|
||||
|
||||
terminal.Init(env.Shell())
|
||||
|
|
|
@ -81,13 +81,11 @@ func TestAnsiRender(t *testing.T) {
|
|||
|
||||
for _, tc := range cases {
|
||||
env := new(mock.Environment)
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("TemplateCache").Return(&cache.Template{})
|
||||
env.On("Getenv", "TERM_PROGRAM").Return(tc.Term)
|
||||
env.On("Shell").Return("foo")
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
|
||||
template.Init(env)
|
||||
template.Cache = new(cache.Template)
|
||||
template.Init(env, nil)
|
||||
|
||||
ansi := Ansi("{{ if eq \"vscode\" .Env.TERM_PROGRAM }}#123456{{end}}")
|
||||
got := ansi.ResolveTemplate()
|
||||
|
|
|
@ -22,7 +22,6 @@ const (
|
|||
|
||||
// Config holds all the theme for rendering the prompt
|
||||
type Config struct {
|
||||
env runtime.Environment
|
||||
Palette color.Palette `json:"palette,omitempty" toml:"palette,omitempty"`
|
||||
DebugPrompt *Segment `json:"debug_prompt,omitempty" toml:"debug_prompt,omitempty"`
|
||||
Var map[string]any `json:"var,omitempty" toml:"var,omitempty"`
|
||||
|
@ -53,9 +52,9 @@ type Config struct {
|
|||
FinalSpace bool `json:"final_space,omitempty" toml:"final_space,omitempty"`
|
||||
}
|
||||
|
||||
func (cfg *Config) MakeColors() color.String {
|
||||
cacheDisabled := cfg.env.Getenv("OMP_CACHE_DISABLED") == "1"
|
||||
return color.MakeColors(cfg.getPalette(), !cacheDisabled, cfg.AccentColor, cfg.env)
|
||||
func (cfg *Config) MakeColors(env runtime.Environment) color.String {
|
||||
cacheDisabled := env.Getenv("OMP_CACHE_DISABLED") == "1"
|
||||
return color.MakeColors(cfg.getPalette(), !cacheDisabled, cfg.AccentColor, env)
|
||||
}
|
||||
|
||||
func (cfg *Config) getPalette() color.Palette {
|
||||
|
@ -88,7 +87,7 @@ func (cfg *Config) getPalette() color.Palette {
|
|||
return palette
|
||||
}
|
||||
|
||||
func (cfg *Config) Features() shell.Features {
|
||||
func (cfg *Config) Features(env runtime.Environment) shell.Features {
|
||||
var feats shell.Features
|
||||
|
||||
if cfg.TransientPrompt != nil {
|
||||
|
@ -100,12 +99,12 @@ func (cfg *Config) Features() shell.Features {
|
|||
}
|
||||
|
||||
autoUpgrade := cfg.AutoUpgrade
|
||||
if _, OK := cfg.env.Cache().Get(AUTOUPGRADE); OK {
|
||||
if _, OK := env.Cache().Get(AUTOUPGRADE); OK {
|
||||
autoUpgrade = true
|
||||
}
|
||||
|
||||
upgradeNotice := cfg.UpgradeNotice
|
||||
if _, OK := cfg.env.Cache().Get(UPGRADENOTICE); OK {
|
||||
if _, OK := env.Cache().Get(UPGRADENOTICE); OK {
|
||||
upgradeNotice = true
|
||||
}
|
||||
|
||||
|
@ -125,7 +124,7 @@ func (cfg *Config) Features() shell.Features {
|
|||
feats = append(feats, shell.Tooltips)
|
||||
}
|
||||
|
||||
if cfg.env.Shell() == shell.FISH && cfg.ITermFeatures != nil && cfg.ITermFeatures.Contains(terminal.PromptMark) {
|
||||
if env.Shell() == shell.FISH && cfg.ITermFeatures != nil && cfg.ITermFeatures.Contains(terminal.PromptMark) {
|
||||
feats = append(feats, shell.PromptMark)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestGetPalette(t *testing.T) {
|
||||
|
@ -92,17 +91,14 @@ func TestGetPalette(t *testing.T) {
|
|||
|
||||
for _, tc := range cases {
|
||||
env := &mock.Environment{}
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
Shell: "bash",
|
||||
})
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("Shell").Return("bash")
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
|
||||
template.Init(env)
|
||||
template.Cache = &cache.Template{
|
||||
Shell: "bash",
|
||||
}
|
||||
template.Init(env, nil)
|
||||
|
||||
cfg := &Config{
|
||||
env: env,
|
||||
Palette: tc.Palette,
|
||||
Palettes: tc.Palettes,
|
||||
}
|
||||
|
|
|
@ -3,11 +3,10 @@ package config
|
|||
import (
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/color"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/segments"
|
||||
)
|
||||
|
||||
func Default(env runtime.Environment, warning bool) *Config {
|
||||
func Default(warning bool) *Config {
|
||||
exitBackgroundTemplate := "{{ if gt .Code 0 }}p:red{{ end }}"
|
||||
exitTemplate := " {{ if gt .Code 0 }}\uf00d{{ else }}\uf00c{{ end }} "
|
||||
|
||||
|
@ -197,6 +196,5 @@ func Default(env runtime.Environment, warning bool) *Config {
|
|||
},
|
||||
}
|
||||
|
||||
cfg.env = env
|
||||
return cfg
|
||||
}
|
||||
|
|
|
@ -3,13 +3,17 @@ package config
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
stdOS "os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/goutil/jsonutil"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
|
||||
json "github.com/goccy/go-json"
|
||||
|
@ -18,11 +22,15 @@ import (
|
|||
)
|
||||
|
||||
// LoadConfig returns the default configuration including possible user overrides
|
||||
func Load(env runtime.Environment) *Config {
|
||||
cfg := loadConfig(env)
|
||||
func Load(configFile, sh string, migrate bool) *Config {
|
||||
defer log.Trace(time.Now())
|
||||
|
||||
configFile = Path(configFile)
|
||||
|
||||
cfg := loadConfig(configFile)
|
||||
|
||||
// only migrate automatically when the switch isn't set
|
||||
if !env.Flags().Migrate && cfg.Version < Version {
|
||||
if !migrate && cfg.Version < Version {
|
||||
cfg.BackupAndMigrate()
|
||||
}
|
||||
|
||||
|
@ -39,7 +47,7 @@ func Load(env runtime.Environment) *Config {
|
|||
// elv - broken OSC sequences
|
||||
// xonsh - broken OSC sequences
|
||||
// tcsh - overall broken, FTCS_COMMAND_EXECUTED could be added to POSH_POSTCMD in the future
|
||||
switch env.Shell() {
|
||||
switch sh {
|
||||
case shell.ELVISH, shell.XONSH, shell.TCSH, shell.NU:
|
||||
cfg.ShellIntegration = false
|
||||
}
|
||||
|
@ -47,24 +55,71 @@ func Load(env runtime.Environment) *Config {
|
|||
return cfg
|
||||
}
|
||||
|
||||
func loadConfig(env runtime.Environment) *Config {
|
||||
defer env.Trace(time.Now())
|
||||
configFile := env.Flags().Config
|
||||
func Path(config string) string {
|
||||
defer log.Trace(time.Now())
|
||||
|
||||
// if the config flag is set, we'll use that over POSH_THEME
|
||||
// in our internal shell logic, we'll always use the POSH_THEME
|
||||
// due to not using --config to set the configuration
|
||||
hasConfig := len(config) > 0
|
||||
|
||||
if poshTheme := os.Getenv("POSH_THEME"); len(poshTheme) > 0 && !hasConfig {
|
||||
log.Debug("config set using POSH_THEME: %s", poshTheme)
|
||||
return poshTheme
|
||||
}
|
||||
|
||||
if len(config) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if strings.HasPrefix(config, "https://") {
|
||||
filePath, err := Download(cache.Path(), config)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return filePath
|
||||
}
|
||||
|
||||
isCygwin := func() bool {
|
||||
return runtime.GOOS == "windows" && len(os.Getenv("OSTYPE")) > 0
|
||||
}
|
||||
|
||||
// Cygwin path always needs the full path as we're on Windows but not really.
|
||||
// Doing filepath actions will convert it to a Windows path and break the init script.
|
||||
if isCygwin() {
|
||||
log.Debug("cygwin detected, using full path for config")
|
||||
return config
|
||||
}
|
||||
|
||||
configFile := path.ReplaceTildePrefixWithHomeDir(config)
|
||||
|
||||
abs, err := filepath.Abs(configFile)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return filepath.Clean(configFile)
|
||||
}
|
||||
|
||||
return abs
|
||||
}
|
||||
|
||||
func loadConfig(configFile string) *Config {
|
||||
defer log.Trace(time.Now())
|
||||
|
||||
if len(configFile) == 0 {
|
||||
env.Debug("no config file specified, using default")
|
||||
return Default(env, false)
|
||||
log.Debug("no config file specified, using default")
|
||||
return Default(false)
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
cfg.origin = configFile
|
||||
cfg.Format = strings.TrimPrefix(filepath.Ext(configFile), ".")
|
||||
cfg.env = env
|
||||
|
||||
data, err := stdOS.ReadFile(configFile)
|
||||
if err != nil {
|
||||
env.Error(err)
|
||||
return Default(env, true)
|
||||
log.Error(err)
|
||||
return Default(true)
|
||||
}
|
||||
|
||||
switch cfg.Format {
|
||||
|
@ -87,8 +142,8 @@ func loadConfig(env runtime.Environment) *Config {
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
env.Error(err)
|
||||
return Default(env, true)
|
||||
log.Error(err)
|
||||
return Default(true)
|
||||
}
|
||||
|
||||
return &cfg
|
||||
|
|
|
@ -121,7 +121,7 @@ func (segment *Segment) Execute(env runtime.Environment) {
|
|||
|
||||
if segment.writer.Enabled() {
|
||||
segment.Enabled = true
|
||||
env.TemplateCache().AddSegmentData(segment.Name(), segment.writer)
|
||||
template.Cache.AddSegmentData(segment.Name(), segment.writer)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ func (segment *Segment) Render() {
|
|||
segment.Enabled = len(strings.ReplaceAll(text, " ", "")) > 0
|
||||
|
||||
if !segment.Enabled {
|
||||
segment.env.TemplateCache().RemoveSegmentData(segment.Name())
|
||||
template.Cache.RemoveSegmentData(segment.Name())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ func (segment *Segment) Render() {
|
|||
segment.setCache()
|
||||
|
||||
// We do this to make `.Text` available for a cross-segment reference in an extra prompt.
|
||||
segment.env.TemplateCache().AddSegmentData(segment.Name(), segment.writer)
|
||||
template.Cache.AddSegmentData(segment.Name(), segment.writer)
|
||||
}
|
||||
|
||||
func (segment *Segment) Text() string {
|
||||
|
@ -231,7 +231,7 @@ func (segment *Segment) restoreCache() bool {
|
|||
}
|
||||
|
||||
segment.Enabled = true
|
||||
segment.env.TemplateCache().AddSegmentData(segment.Name(), segment.writer)
|
||||
template.Cache.AddSegmentData(segment.Name(), segment.writer)
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import (
|
|||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
fontCLI "github.com/jandedobbeleer/oh-my-posh/src/font"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
|
@ -218,7 +219,7 @@ func (ir *Renderer) setOutputPath(config string) {
|
|||
func (ir *Renderer) loadFonts() error {
|
||||
var data []byte
|
||||
|
||||
fontCachePath := filepath.Join(ir.env.CachePath(), "Hack.zip")
|
||||
fontCachePath := filepath.Join(cache.Path(), "Hack.zip")
|
||||
if _, err := stdOS.Stat(fontCachePath); err == nil {
|
||||
data, _ = stdOS.ReadFile(fontCachePath)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
)
|
||||
|
@ -66,7 +67,7 @@ func (e *Engine) PrintDebug(startTime time.Time, version string) string {
|
|||
}
|
||||
|
||||
e.write(fmt.Sprintf("\n%s %s\n", log.Text("Run duration:").Green().Bold().Plain(), time.Since(startTime)))
|
||||
e.write(fmt.Sprintf("\n%s %s\n", log.Text("Cache path:").Green().Bold().Plain(), e.Env.CachePath()))
|
||||
e.write(fmt.Sprintf("\n%s %s\n", log.Text("Cache path:").Green().Bold().Plain(), cache.Path()))
|
||||
|
||||
cfg := e.Env.Flags().Config
|
||||
if len(cfg) == 0 {
|
||||
|
|
|
@ -462,19 +462,12 @@ func (e *Engine) rectifyTerminalWidth(diff int) {
|
|||
// given configuration options, and is ready to print any
|
||||
// of the prompt components.
|
||||
func New(flags *runtime.Flags) *Engine {
|
||||
env := &runtime.Terminal{
|
||||
CmdFlags: flags,
|
||||
}
|
||||
cfg := config.Load(flags.Config, flags.Shell, flags.Migrate)
|
||||
|
||||
env.Init()
|
||||
cfg := config.Load(env)
|
||||
env.Var = cfg.Var
|
||||
env := &runtime.Terminal{}
|
||||
env.Init(flags)
|
||||
|
||||
// To prevent cross-segment template referencing issues, this should not be moved elsewhere.
|
||||
// Related: https://github.com/JanDeDobbeleer/oh-my-posh/discussions/2885#discussioncomment-4497439
|
||||
env.PopulateTemplateCache()
|
||||
|
||||
template.Init(env)
|
||||
template.Init(env, cfg.Var)
|
||||
|
||||
flags.HasExtra = cfg.DebugPrompt != nil ||
|
||||
cfg.SecondaryPrompt != nil ||
|
||||
|
@ -484,7 +477,7 @@ func New(flags *runtime.Flags) *Engine {
|
|||
|
||||
terminal.Init(env.Shell())
|
||||
terminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()
|
||||
terminal.Colors = cfg.MakeColors()
|
||||
terminal.Colors = cfg.MakeColors(env)
|
||||
terminal.Plain = flags.Plain
|
||||
|
||||
eng := &Engine{
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/maps"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
|
@ -13,7 +14,6 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestCanWriteRPrompt(t *testing.T) {
|
||||
|
@ -64,7 +64,7 @@ func TestPrintPWD(t *testing.T) {
|
|||
{Case: "OSC7", Config: terminal.OSC7, Expected: "\x1b]7;file://host/pwd\x1b\\"},
|
||||
{Case: "OSC51", Config: terminal.OSC51, Expected: "\x1b]51;Auser@host:pwd\x1b\\"},
|
||||
{Case: "Template (empty)", Config: "{{ if eq .Shell \"pwsh\" }}osc7{{ end }}"},
|
||||
{Case: "Template (non empty)", Config: "{{ if eq .Shell \"shell\" }}osc7{{ end }}", Expected: "\x1b]7;file://host/pwd\x1b\\"},
|
||||
{Case: "Template (non empty)", Shell: shell.GENERIC, Config: "{{ if eq .Shell \"shell\" }}osc7{{ end }}", Expected: "\x1b]7;file://host/pwd\x1b\\"},
|
||||
{
|
||||
Case: "OSC99 Cygwin",
|
||||
Pwd: `C:\Users\user\Documents\GitHub\oh-my-posh`,
|
||||
|
@ -89,16 +89,16 @@ func TestPrintPWD(t *testing.T) {
|
|||
env.On("Pwd").Return(tc.Pwd)
|
||||
env.On("User").Return("user")
|
||||
env.On("Shell").Return(tc.Shell)
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("IsCygwin").Return(tc.Cygwin)
|
||||
env.On("Host").Return("host", nil)
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
Shell: "shell",
|
||||
})
|
||||
|
||||
template.Cache = &cache.Template{
|
||||
Shell: tc.Shell,
|
||||
Segments: maps.NewConcurrent(),
|
||||
}
|
||||
template.Init(env, nil)
|
||||
|
||||
terminal.Init(shell.GENERIC)
|
||||
template.Init(env)
|
||||
|
||||
engine := &Engine{
|
||||
Env: env,
|
||||
|
@ -121,15 +121,21 @@ func BenchmarkEngineRender(b *testing.B) {
|
|||
}
|
||||
|
||||
func engineRender() {
|
||||
cfg := config.Load("", shell.GENERIC, false)
|
||||
|
||||
env := &runtime.Terminal{}
|
||||
env.Init()
|
||||
env.Init(nil)
|
||||
|
||||
defer env.Close()
|
||||
|
||||
cfg := config.Load(env)
|
||||
template.Cache = &cache.Template{
|
||||
Segments: maps.NewConcurrent(),
|
||||
}
|
||||
template.Init(env, nil)
|
||||
|
||||
terminal.Init(shell.GENERIC)
|
||||
terminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()
|
||||
terminal.Colors = cfg.MakeColors()
|
||||
terminal.Colors = cfg.MakeColors(env)
|
||||
|
||||
engine := &Engine{
|
||||
Config: cfg,
|
||||
|
@ -139,12 +145,6 @@ func engineRender() {
|
|||
engine.Primary()
|
||||
}
|
||||
|
||||
func BenchmarkEngineRenderPalette(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
engineRender()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTitle(t *testing.T) {
|
||||
cases := []struct {
|
||||
Template string
|
||||
|
@ -185,21 +185,21 @@ func TestGetTitle(t *testing.T) {
|
|||
env.On("Pwd").Return(tc.Cwd)
|
||||
env.On("Home").Return("/usr/home")
|
||||
env.On("PathSeparator").Return(tc.PathSeparator)
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
env.On("Getenv", "USERDOMAIN").Return("MyCompany")
|
||||
env.On("Shell").Return(tc.ShellName)
|
||||
|
||||
terminal.Init(shell.GENERIC)
|
||||
|
||||
template.Cache = &cache.Template{
|
||||
Shell: tc.ShellName,
|
||||
UserName: "MyUser",
|
||||
Root: tc.Root,
|
||||
HostName: "MyHost",
|
||||
PWD: tc.Cwd,
|
||||
Folder: "vagrant",
|
||||
})
|
||||
env.On("Getenv", "USERDOMAIN").Return("MyCompany")
|
||||
env.On("Shell").Return(tc.ShellName)
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
|
||||
terminal.Init(shell.GENERIC)
|
||||
template.Init(env)
|
||||
Segments: maps.NewConcurrent(),
|
||||
}
|
||||
template.Init(env, nil)
|
||||
|
||||
engine := &Engine{
|
||||
Config: &config.Config{
|
||||
|
@ -249,19 +249,19 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {
|
|||
env := new(mock.Environment)
|
||||
env.On("Pwd").Return(tc.Cwd)
|
||||
env.On("Home").Return("/usr/home")
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
env.On("Getenv", "USERDOMAIN").Return("MyCompany")
|
||||
env.On("Shell").Return(tc.ShellName)
|
||||
|
||||
terminal.Init(shell.GENERIC)
|
||||
|
||||
template.Cache = &cache.Template{
|
||||
Shell: tc.ShellName,
|
||||
UserName: "MyUser",
|
||||
Root: tc.Root,
|
||||
HostName: "",
|
||||
})
|
||||
env.On("Getenv", "USERDOMAIN").Return("MyCompany")
|
||||
env.On("Shell").Return(tc.ShellName)
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
|
||||
terminal.Init(shell.GENERIC)
|
||||
template.Init(env)
|
||||
Segments: maps.NewConcurrent(),
|
||||
}
|
||||
template.Init(env, nil)
|
||||
|
||||
engine := &Engine{
|
||||
Config: &config.Config{
|
||||
|
|
|
@ -33,42 +33,39 @@ type Environment interface {
|
|||
Shell() string
|
||||
Platform() string
|
||||
StatusCodes() (int, string)
|
||||
PathSeparator() string
|
||||
HasFiles(pattern string) bool
|
||||
HasFilesInDir(dir, pattern string) bool
|
||||
HasFolder(folder string) bool
|
||||
HasParentFilePath(path string, followSymlinks bool) (fileInfo *FileInfo, err error)
|
||||
HasParentFilePath(input string, followSymlinks bool) (fileInfo *FileInfo, err error)
|
||||
HasFileInParentDirs(pattern string, depth uint) bool
|
||||
ResolveSymlink(path string) (string, error)
|
||||
ResolveSymlink(input string) (string, error)
|
||||
DirMatchesOneOf(dir string, regexes []string) bool
|
||||
DirIsWritable(path string) bool
|
||||
DirIsWritable(input string) bool
|
||||
CommandPath(command string) string
|
||||
HasCommand(command string) bool
|
||||
FileContent(file string) string
|
||||
LsDir(path string) []fs.DirEntry
|
||||
LsDir(input string) []fs.DirEntry
|
||||
RunCommand(command string, args ...string) (string, error)
|
||||
RunShellCommand(shell, command string) string
|
||||
ExecutionTime() float64
|
||||
Flags() *Flags
|
||||
BatteryState() (*battery.Info, error)
|
||||
QueryWindowTitles(processName, windowTitleRegex string) (string, error)
|
||||
WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error)
|
||||
WindowsRegistryKeyValue(key string) (*WindowsRegistryValue, error)
|
||||
HTTPRequest(url string, body io.Reader, timeout int, requestModifiers ...http.RequestModifier) ([]byte, error)
|
||||
IsWsl() bool
|
||||
IsWsl2() bool
|
||||
IsCygwin() bool
|
||||
StackCount() int
|
||||
TerminalWidth() (int, error)
|
||||
CachePath() string
|
||||
Cache() cache.Cache
|
||||
Session() cache.Cache
|
||||
Close()
|
||||
Logs() string
|
||||
InWSLSharedDrive() bool
|
||||
ConvertToLinuxPath(path string) string
|
||||
ConvertToWindowsPath(path string) string
|
||||
ConvertToLinuxPath(input string) string
|
||||
ConvertToWindowsPath(input string) string
|
||||
Connection(connectionType ConnectionType) (*Connection, error)
|
||||
TemplateCache() *cache.Template
|
||||
CursorPosition() (row, col int)
|
||||
SystemInfo() (*SystemInfo, error)
|
||||
Debug(message string)
|
||||
|
@ -84,6 +81,7 @@ type Flags struct {
|
|||
Shell string
|
||||
ShellVersion string
|
||||
PWD string
|
||||
AbsolutePWD string
|
||||
Type string
|
||||
ErrorCode int
|
||||
PromptCount int
|
||||
|
|
|
@ -47,8 +47,8 @@ func (env *Environment) HasFolder(folder string) bool {
|
|||
return args.Bool(0)
|
||||
}
|
||||
|
||||
func (env *Environment) ResolveSymlink(path string) (string, error) {
|
||||
args := env.Called(path)
|
||||
func (env *Environment) ResolveSymlink(input string) (string, error) {
|
||||
args := env.Called(input)
|
||||
return args.String(0), args.Error(1)
|
||||
}
|
||||
|
||||
|
@ -57,16 +57,11 @@ func (env *Environment) FileContent(file string) string {
|
|||
return args.String(0)
|
||||
}
|
||||
|
||||
func (env *Environment) LsDir(path string) []fs.DirEntry {
|
||||
args := env.Called(path)
|
||||
func (env *Environment) LsDir(input string) []fs.DirEntry {
|
||||
args := env.Called(input)
|
||||
return args.Get(0).([]fs.DirEntry)
|
||||
}
|
||||
|
||||
func (env *Environment) PathSeparator() string {
|
||||
args := env.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (env *Environment) User() string {
|
||||
args := env.Called()
|
||||
return args.String(0)
|
||||
|
@ -226,11 +221,6 @@ func (env *Environment) Connection(connectionType runtime.ConnectionType) (*runt
|
|||
return args.Get(0).(*runtime.Connection), args.Error(1)
|
||||
}
|
||||
|
||||
func (env *Environment) TemplateCache() *cache.Template {
|
||||
args := env.Called()
|
||||
return args.Get(0).(*cache.Template)
|
||||
}
|
||||
|
||||
func (env *Environment) MockGitCommand(dir, returnValue string, args ...string) {
|
||||
args = append([]string{"-C", dir, "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}, args...)
|
||||
env.On("RunCommand", "git", args).Return(returnValue, nil)
|
||||
|
|
123
src/runtime/path/clean.go
Normal file
123
src/runtime/path/clean.go
Normal file
|
@ -0,0 +1,123 @@
|
|||
package path
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||
)
|
||||
|
||||
// Base returns the last element of path.
|
||||
// Trailing path separators are removed before extracting the last element.
|
||||
// If the path consists entirely of separators, Base returns a single separator.
|
||||
func Base(input string) string {
|
||||
volumeName := filepath.VolumeName(input)
|
||||
// Strip trailing slashes.
|
||||
for len(input) > 0 && IsSeparator(input[len(input)-1]) {
|
||||
input = input[0 : len(input)-1]
|
||||
}
|
||||
|
||||
if len(input) == 0 {
|
||||
return Separator()
|
||||
}
|
||||
|
||||
if volumeName == input {
|
||||
return input
|
||||
}
|
||||
|
||||
// Throw away volume name
|
||||
input = input[len(filepath.VolumeName(input)):]
|
||||
// Find the last element
|
||||
i := len(input) - 1
|
||||
for i >= 0 && !IsSeparator(input[i]) {
|
||||
i--
|
||||
}
|
||||
|
||||
if i >= 0 {
|
||||
input = input[i+1:]
|
||||
}
|
||||
|
||||
// If empty now, it had only slashes.
|
||||
if len(input) == 0 {
|
||||
return Separator()
|
||||
}
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
func Clean(input string) string {
|
||||
if len(input) == 0 {
|
||||
return input
|
||||
}
|
||||
|
||||
cleaned := input
|
||||
separator := Separator()
|
||||
|
||||
// The prefix can be empty for a relative path.
|
||||
var prefix string
|
||||
if IsSeparator(cleaned[0]) {
|
||||
prefix = separator
|
||||
}
|
||||
|
||||
if runtime.GOOS == windows {
|
||||
// Normalize (forward) slashes to backslashes on Windows.
|
||||
cleaned = strings.ReplaceAll(cleaned, "/", `\`)
|
||||
|
||||
// Clean the prefix for a UNC path, if any.
|
||||
if regex.MatchString(`^\\{2}[^\\]+`, cleaned) {
|
||||
cleaned = strings.TrimPrefix(cleaned, `\\.\UNC\`)
|
||||
if len(cleaned) == 0 {
|
||||
return cleaned
|
||||
}
|
||||
prefix = `\\`
|
||||
}
|
||||
|
||||
// Always use an uppercase drive letter on Windows.
|
||||
driveLetter := regex.GetCompiledRegex(`^[a-z]:`)
|
||||
cleaned = driveLetter.ReplaceAllStringFunc(cleaned, strings.ToUpper)
|
||||
}
|
||||
|
||||
sb := new(strings.Builder)
|
||||
sb.WriteString(prefix)
|
||||
|
||||
// Clean slashes.
|
||||
matches := regex.FindAllNamedRegexMatch(fmt.Sprintf(`(?P<element>[^\%s]+)`, separator), cleaned)
|
||||
n := len(matches) - 1
|
||||
for i, m := range matches {
|
||||
sb.WriteString(m["element"])
|
||||
if i != n {
|
||||
sb.WriteString(separator)
|
||||
}
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func ReplaceHomeDirPrefixWithTilde(path string) string {
|
||||
home := Home()
|
||||
if !strings.HasPrefix(path, home) {
|
||||
return path
|
||||
}
|
||||
|
||||
rem := path[len(home):]
|
||||
if len(rem) == 0 || IsSeparator(rem[0]) {
|
||||
return "~" + rem
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func ReplaceTildePrefixWithHomeDir(path string) string {
|
||||
if !strings.HasPrefix(path, "~") {
|
||||
return path
|
||||
}
|
||||
|
||||
rem := path[1:]
|
||||
if len(rem) == 0 || IsSeparator(rem[0]) {
|
||||
return Home() + rem
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
27
src/runtime/path/home.go
Normal file
27
src/runtime/path/home.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package path
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
)
|
||||
|
||||
func Home() string {
|
||||
home := os.Getenv("HOME")
|
||||
defer func() {
|
||||
log.Debug(home)
|
||||
}()
|
||||
|
||||
if len(home) > 0 {
|
||||
return home
|
||||
}
|
||||
|
||||
// fallback to older implemenations on Windows
|
||||
home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||
|
||||
if len(home) == 0 {
|
||||
home = os.Getenv("USERPROFILE")
|
||||
}
|
||||
|
||||
return home
|
||||
}
|
34
src/runtime/path/separator.go
Normal file
34
src/runtime/path/separator.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package path
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
)
|
||||
|
||||
const (
|
||||
windows = "windows"
|
||||
)
|
||||
|
||||
func Separator() string {
|
||||
defer log.Trace(time.Now())
|
||||
|
||||
if runtime.GOOS == windows {
|
||||
return `\`
|
||||
}
|
||||
|
||||
return "/"
|
||||
}
|
||||
|
||||
func IsSeparator(c uint8) bool {
|
||||
if c == '/' {
|
||||
return true
|
||||
}
|
||||
|
||||
if runtime.GOOS == windows && c == '\\' {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
|
@ -2,7 +2,6 @@ package runtime
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -22,8 +21,8 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/maps"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/cmd"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/config"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/http"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
|
||||
disk "github.com/shirou/gopsutil/v3/disk"
|
||||
load "github.com/shirou/gopsutil/v3/load"
|
||||
|
@ -32,20 +31,20 @@ import (
|
|||
|
||||
type Terminal struct {
|
||||
CmdFlags *Flags
|
||||
Var maps.Simple
|
||||
cmdCache *cache.Command
|
||||
deviceCache *cache.File
|
||||
sessionCache *cache.File
|
||||
tmplCache *cache.Template
|
||||
lsDirMap maps.Concurrent
|
||||
cwd string
|
||||
host string
|
||||
networks []*Connection
|
||||
}
|
||||
|
||||
func (term *Terminal) Init() {
|
||||
func (term *Terminal) Init(flags *Flags) {
|
||||
defer term.Trace(time.Now())
|
||||
|
||||
term.CmdFlags = flags
|
||||
|
||||
if term.CmdFlags == nil {
|
||||
term.CmdFlags = &Flags{}
|
||||
}
|
||||
|
@ -61,9 +60,9 @@ func (term *Terminal) Init() {
|
|||
}
|
||||
|
||||
initCache := func(fileName string) *cache.File {
|
||||
cache := &cache.File{}
|
||||
cache.Init(filepath.Join(term.CachePath(), fileName), term.CmdFlags.SaveCache)
|
||||
return cache
|
||||
fileCache := &cache.File{}
|
||||
fileCache.Init(filepath.Join(cache.Path(), fileName), term.CmdFlags.SaveCache)
|
||||
return fileCache
|
||||
}
|
||||
|
||||
term.deviceCache = initCache(cache.FileName)
|
||||
|
@ -72,67 +71,9 @@ func (term *Terminal) Init() {
|
|||
|
||||
term.setPwd()
|
||||
|
||||
term.ResolveConfigPath()
|
||||
|
||||
term.cmdCache = &cache.Command{
|
||||
Commands: maps.NewConcurrent(),
|
||||
}
|
||||
|
||||
term.tmplCache = new(cache.Template)
|
||||
}
|
||||
|
||||
func (term *Terminal) ResolveConfigPath() {
|
||||
defer term.Trace(time.Now())
|
||||
|
||||
// if the config flag is set, we'll use that over POSH_THEME
|
||||
// in our internal shell logic, we'll always use the POSH_THEME
|
||||
// due to not using --config to set the configuration
|
||||
hasConfigFlag := len(term.CmdFlags.Config) > 0
|
||||
|
||||
if poshTheme := term.Getenv("POSH_THEME"); len(poshTheme) > 0 && !hasConfigFlag {
|
||||
term.DebugF("config set using POSH_THEME: %s", poshTheme)
|
||||
term.CmdFlags.Config = poshTheme
|
||||
return
|
||||
}
|
||||
|
||||
if len(term.CmdFlags.Config) == 0 {
|
||||
term.Debug("no config set, fallback to default config")
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(term.CmdFlags.Config, "https://") {
|
||||
filePath, err := config.Download(term.CachePath(), term.CmdFlags.Config)
|
||||
if err != nil {
|
||||
term.Error(err)
|
||||
term.CmdFlags.Config = ""
|
||||
return
|
||||
}
|
||||
|
||||
term.CmdFlags.Config = filePath
|
||||
return
|
||||
}
|
||||
|
||||
isCygwin := func() bool {
|
||||
return term.Platform() == WINDOWS && len(term.Getenv("OSTYPE")) > 0
|
||||
}
|
||||
|
||||
// Cygwin path always needs the full path as we're on Windows but not really.
|
||||
// Doing filepath actions will convert it to a Windows path and break the init script.
|
||||
if isCygwin() {
|
||||
term.Debug("cygwin detected, using full path for config")
|
||||
return
|
||||
}
|
||||
|
||||
configFile := ReplaceTildePrefixWithHomeDir(term, term.CmdFlags.Config)
|
||||
|
||||
abs, err := filepath.Abs(configFile)
|
||||
if err != nil {
|
||||
term.Error(err)
|
||||
term.CmdFlags.Config = filepath.Clean(configFile)
|
||||
return
|
||||
}
|
||||
|
||||
term.CmdFlags.Config = abs
|
||||
}
|
||||
|
||||
func (term *Terminal) Trace(start time.Time, args ...string) {
|
||||
|
@ -179,7 +120,7 @@ func (term *Terminal) setPwd() {
|
|||
}
|
||||
|
||||
if term.CmdFlags != nil && term.CmdFlags.PWD != "" {
|
||||
term.cwd = CleanPath(term, term.CmdFlags.PWD)
|
||||
term.cwd = path.Clean(term.CmdFlags.PWD)
|
||||
term.Debug(term.cwd)
|
||||
return
|
||||
}
|
||||
|
@ -277,9 +218,9 @@ func (term *Terminal) HasFolder(folder string) bool {
|
|||
return isDir
|
||||
}
|
||||
|
||||
func (term *Terminal) ResolveSymlink(path string) (string, error) {
|
||||
defer term.Trace(time.Now(), path)
|
||||
link, err := filepath.EvalSymlinks(path)
|
||||
func (term *Terminal) ResolveSymlink(input string) (string, error) {
|
||||
defer term.Trace(time.Now(), input)
|
||||
link, err := filepath.EvalSymlinks(input)
|
||||
if err != nil {
|
||||
term.Error(err)
|
||||
return "", err
|
||||
|
@ -293,35 +234,32 @@ func (term *Terminal) FileContent(file string) string {
|
|||
if !filepath.IsAbs(file) {
|
||||
file = filepath.Join(term.Pwd(), file)
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
term.Error(err)
|
||||
return ""
|
||||
}
|
||||
|
||||
fileContent := string(content)
|
||||
term.Debug(fileContent)
|
||||
|
||||
return fileContent
|
||||
}
|
||||
|
||||
func (term *Terminal) LsDir(path string) []fs.DirEntry {
|
||||
defer term.Trace(time.Now(), path)
|
||||
entries, err := os.ReadDir(path)
|
||||
func (term *Terminal) LsDir(input string) []fs.DirEntry {
|
||||
defer term.Trace(time.Now(), input)
|
||||
|
||||
entries, err := os.ReadDir(input)
|
||||
if err != nil {
|
||||
term.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
term.DebugF("%v", entries)
|
||||
return entries
|
||||
}
|
||||
|
||||
func (term *Terminal) PathSeparator() string {
|
||||
defer term.Trace(time.Now())
|
||||
if term.GOOS() == WINDOWS {
|
||||
return `\`
|
||||
}
|
||||
return "/"
|
||||
}
|
||||
|
||||
func (term *Terminal) User() string {
|
||||
defer term.Trace(time.Now())
|
||||
user := os.Getenv("USER")
|
||||
|
@ -356,6 +294,10 @@ func (term *Terminal) GOOS() string {
|
|||
return runtime.GOOS
|
||||
}
|
||||
|
||||
func (term *Terminal) Home() string {
|
||||
return path.Home()
|
||||
}
|
||||
|
||||
func (term *Terminal) RunCommand(command string, args ...string) (string, error) {
|
||||
defer term.Trace(time.Now(), append([]string{command}, args...)...)
|
||||
|
||||
|
@ -384,16 +326,16 @@ func (term *Terminal) RunShellCommand(shell, command string) string {
|
|||
|
||||
func (term *Terminal) CommandPath(command string) string {
|
||||
defer term.Trace(time.Now(), command)
|
||||
if path, ok := term.cmdCache.Get(command); ok {
|
||||
term.Debug(path)
|
||||
return path
|
||||
if cmdPath, ok := term.cmdCache.Get(command); ok {
|
||||
term.Debug(cmdPath)
|
||||
return cmdPath
|
||||
}
|
||||
|
||||
path, err := exec.LookPath(command)
|
||||
cmdPath, err := exec.LookPath(command)
|
||||
if err == nil {
|
||||
term.cmdCache.Set(command, path)
|
||||
term.Debug(path)
|
||||
return path
|
||||
term.cmdCache.Set(command, cmdPath)
|
||||
term.Debug(cmdPath)
|
||||
return cmdPath
|
||||
}
|
||||
|
||||
term.Error(err)
|
||||
|
@ -402,9 +344,11 @@ func (term *Terminal) CommandPath(command string) string {
|
|||
|
||||
func (term *Terminal) HasCommand(command string) bool {
|
||||
defer term.Trace(time.Now(), command)
|
||||
if path := term.CommandPath(command); path != "" {
|
||||
|
||||
if cmdPath := term.CommandPath(command); cmdPath != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -529,20 +473,20 @@ func (term *Terminal) HTTPRequest(targetURL string, body io.Reader, timeout int,
|
|||
func (term *Terminal) HasParentFilePath(parent string, followSymlinks bool) (*FileInfo, error) {
|
||||
defer term.Trace(time.Now(), parent)
|
||||
|
||||
path := term.Pwd()
|
||||
pwd := term.Pwd()
|
||||
if followSymlinks {
|
||||
if actual, err := term.ResolveSymlink(path); err == nil {
|
||||
path = actual
|
||||
if actual, err := term.ResolveSymlink(pwd); err == nil {
|
||||
pwd = actual
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
fileSystem := os.DirFS(path)
|
||||
fileSystem := os.DirFS(pwd)
|
||||
info, err := fs.Stat(fileSystem, parent)
|
||||
if err == nil {
|
||||
return &FileInfo{
|
||||
ParentFolder: path,
|
||||
Path: filepath.Join(path, parent),
|
||||
ParentFolder: pwd,
|
||||
Path: filepath.Join(pwd, parent),
|
||||
IsDir: info.IsDir(),
|
||||
}, nil
|
||||
}
|
||||
|
@ -551,8 +495,8 @@ func (term *Terminal) HasParentFilePath(parent string, followSymlinks bool) (*Fi
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if dir := filepath.Dir(path); dir != path {
|
||||
path = dir
|
||||
if dir := filepath.Dir(pwd); dir != pwd {
|
||||
pwd = dir
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -563,6 +507,7 @@ func (term *Terminal) HasParentFilePath(parent string, followSymlinks bool) (*Fi
|
|||
|
||||
func (term *Terminal) StackCount() int {
|
||||
defer term.Trace(time.Now())
|
||||
|
||||
if term.CmdFlags.StackCount < 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -578,26 +523,8 @@ func (term *Terminal) Session() cache.Cache {
|
|||
return term.sessionCache
|
||||
}
|
||||
|
||||
func (term *Terminal) saveTemplateCache() {
|
||||
// only store this when in a primary prompt
|
||||
// and when we have any extra prompt in the config
|
||||
canSave := term.CmdFlags.Type == PRIMARY && term.CmdFlags.HasExtra
|
||||
if !canSave {
|
||||
return
|
||||
}
|
||||
|
||||
tmplCache := term.TemplateCache()
|
||||
tmplCache.SegmentsCache = tmplCache.Segments.ToSimple()
|
||||
|
||||
templateCache, err := json.Marshal(tmplCache)
|
||||
if err == nil {
|
||||
term.sessionCache.Set(cache.TEMPLATECACHE, string(templateCache), cache.ONEDAY)
|
||||
}
|
||||
}
|
||||
|
||||
func (term *Terminal) Close() {
|
||||
defer term.Trace(time.Now())
|
||||
term.saveTemplateCache()
|
||||
term.clearCacheFiles()
|
||||
term.deviceCache.Close()
|
||||
term.sessionCache.Close()
|
||||
|
@ -608,7 +535,7 @@ func (term *Terminal) clearCacheFiles() {
|
|||
return
|
||||
}
|
||||
|
||||
deletedFiles, err := cache.Clear(term.CachePath(), false)
|
||||
deletedFiles, err := cache.Clear(cache.Path(), false)
|
||||
if err != nil {
|
||||
term.Error(err)
|
||||
return
|
||||
|
@ -619,88 +546,10 @@ func (term *Terminal) clearCacheFiles() {
|
|||
}
|
||||
}
|
||||
|
||||
func (term *Terminal) PopulateTemplateCache() {
|
||||
if !term.CmdFlags.IsPrimary {
|
||||
// Load the template cache for a non-primary prompt before rendering any templates.
|
||||
term.loadTemplateCache()
|
||||
return
|
||||
}
|
||||
|
||||
tmplCache := term.tmplCache
|
||||
|
||||
tmplCache.Root = term.Root()
|
||||
tmplCache.Shell = term.Shell()
|
||||
tmplCache.ShellVersion = term.CmdFlags.ShellVersion
|
||||
tmplCache.Code, _ = term.StatusCodes()
|
||||
tmplCache.WSL = term.IsWsl()
|
||||
tmplCache.Segments = maps.NewConcurrent()
|
||||
tmplCache.PromptCount = term.CmdFlags.PromptCount
|
||||
tmplCache.Var = make(map[string]any)
|
||||
tmplCache.Jobs = term.CmdFlags.JobCount
|
||||
|
||||
if term.Var != nil {
|
||||
tmplCache.Var = term.Var
|
||||
}
|
||||
|
||||
pwd := term.Pwd()
|
||||
tmplCache.PWD = ReplaceHomeDirPrefixWithTilde(term, pwd)
|
||||
|
||||
tmplCache.AbsolutePWD = pwd
|
||||
if term.IsWsl() {
|
||||
tmplCache.AbsolutePWD, _ = term.RunCommand("wslpath", "-m", pwd)
|
||||
}
|
||||
|
||||
tmplCache.PSWD = term.CmdFlags.PSWD
|
||||
|
||||
tmplCache.Folder = Base(term, pwd)
|
||||
if term.GOOS() == WINDOWS && strings.HasSuffix(tmplCache.Folder, ":") {
|
||||
tmplCache.Folder += `\`
|
||||
}
|
||||
|
||||
tmplCache.UserName = term.User()
|
||||
if host, err := term.Host(); err == nil {
|
||||
tmplCache.HostName = host
|
||||
}
|
||||
|
||||
goos := term.GOOS()
|
||||
tmplCache.OS = goos
|
||||
if goos == LINUX {
|
||||
tmplCache.OS = term.Platform()
|
||||
}
|
||||
|
||||
val := term.Getenv("SHLVL")
|
||||
if shlvl, err := strconv.Atoi(val); err == nil {
|
||||
tmplCache.SHLVL = shlvl
|
||||
}
|
||||
}
|
||||
|
||||
func (term *Terminal) loadTemplateCache() {
|
||||
defer term.Trace(time.Now())
|
||||
|
||||
val, OK := term.sessionCache.Get(cache.TEMPLATECACHE)
|
||||
if !OK {
|
||||
return
|
||||
}
|
||||
|
||||
tmplCache := term.tmplCache
|
||||
|
||||
err := json.Unmarshal([]byte(val), &tmplCache)
|
||||
if err != nil {
|
||||
term.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
tmplCache.Segments = tmplCache.SegmentsCache.ToConcurrent()
|
||||
}
|
||||
|
||||
func (term *Terminal) Logs() string {
|
||||
return log.String()
|
||||
}
|
||||
|
||||
func (term *Terminal) TemplateCache() *cache.Template {
|
||||
return term.tmplCache
|
||||
}
|
||||
|
||||
func (term *Terminal) DirMatchesOneOf(dir string, regexes []string) (match bool) {
|
||||
// sometimes the function panics inside golang, we want to silence that error
|
||||
// and assume that there's no match. Not perfect, but better than crashing
|
||||
|
@ -797,170 +646,6 @@ func (term *Terminal) SystemInfo() (*SystemInfo, error) {
|
|||
return s, nil
|
||||
}
|
||||
|
||||
func (term *Terminal) CachePath() string {
|
||||
defer term.Trace(time.Now())
|
||||
|
||||
returnOrBuildCachePath := func(path string) (string, bool) {
|
||||
// validate root path
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// validate oh-my-posh folder, if non existent, create it
|
||||
cachePath := filepath.Join(path, "oh-my-posh")
|
||||
if _, err := os.Stat(cachePath); err == nil {
|
||||
return cachePath, true
|
||||
}
|
||||
|
||||
if err := os.Mkdir(cachePath, 0o755); err != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return cachePath, true
|
||||
}
|
||||
|
||||
// WINDOWS cache folder, should not exist elsewhere
|
||||
if cachePath, OK := returnOrBuildCachePath(term.Getenv("LOCALAPPDATA")); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
// allow the user to set the cache path using OMP_CACHE_DIR
|
||||
if cachePath, OK := returnOrBuildCachePath(term.Getenv("OMP_CACHE_DIR")); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
// get XDG_CACHE_HOME if present
|
||||
if cachePath, OK := returnOrBuildCachePath(term.Getenv("XDG_CACHE_HOME")); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
// try to create the cache folder in the user's home directory if non-existent
|
||||
dotCache := filepath.Join(term.Home(), ".cache")
|
||||
if _, err := os.Stat(dotCache); err != nil {
|
||||
_ = os.Mkdir(dotCache, 0o755)
|
||||
}
|
||||
|
||||
// HOME cache folder
|
||||
if cachePath, OK := returnOrBuildCachePath(dotCache); OK {
|
||||
return cachePath
|
||||
}
|
||||
|
||||
return term.Home()
|
||||
}
|
||||
|
||||
func IsPathSeparator(env Environment, c uint8) bool {
|
||||
if c == '/' {
|
||||
return true
|
||||
}
|
||||
if env.GOOS() == WINDOWS && c == '\\' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Base returns the last element of path.
|
||||
// Trailing path separators are removed before extracting the last element.
|
||||
// If the path consists entirely of separators, Base returns a single separator.
|
||||
func Base(env Environment, path string) string {
|
||||
volumeName := filepath.VolumeName(path)
|
||||
// Strip trailing slashes.
|
||||
for len(path) > 0 && IsPathSeparator(env, path[len(path)-1]) {
|
||||
path = path[0 : len(path)-1]
|
||||
}
|
||||
if len(path) == 0 {
|
||||
return env.PathSeparator()
|
||||
}
|
||||
if volumeName == path {
|
||||
return path
|
||||
}
|
||||
// Throw away volume name
|
||||
path = path[len(filepath.VolumeName(path)):]
|
||||
// Find the last element
|
||||
i := len(path) - 1
|
||||
for i >= 0 && !IsPathSeparator(env, path[i]) {
|
||||
i--
|
||||
}
|
||||
if i >= 0 {
|
||||
path = path[i+1:]
|
||||
}
|
||||
// If empty now, it had only slashes.
|
||||
if len(path) == 0 {
|
||||
return env.PathSeparator()
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func CleanPath(env Environment, path string) string {
|
||||
if len(path) == 0 {
|
||||
return path
|
||||
}
|
||||
|
||||
cleaned := path
|
||||
separator := env.PathSeparator()
|
||||
|
||||
// The prefix can be empty for a relative path.
|
||||
var prefix string
|
||||
if IsPathSeparator(env, cleaned[0]) {
|
||||
prefix = separator
|
||||
}
|
||||
|
||||
if env.GOOS() == WINDOWS {
|
||||
// Normalize (forward) slashes to backslashes on Windows.
|
||||
cleaned = strings.ReplaceAll(cleaned, "/", `\`)
|
||||
|
||||
// Clean the prefix for a UNC path, if any.
|
||||
if regex.MatchString(`^\\{2}[^\\]+`, cleaned) {
|
||||
cleaned = strings.TrimPrefix(cleaned, `\\.\UNC\`)
|
||||
if len(cleaned) == 0 {
|
||||
return cleaned
|
||||
}
|
||||
prefix = `\\`
|
||||
}
|
||||
|
||||
// Always use an uppercase drive letter on Windows.
|
||||
driveLetter := regex.GetCompiledRegex(`^[a-z]:`)
|
||||
cleaned = driveLetter.ReplaceAllStringFunc(cleaned, strings.ToUpper)
|
||||
}
|
||||
|
||||
sb := new(strings.Builder)
|
||||
sb.WriteString(prefix)
|
||||
|
||||
// Clean slashes.
|
||||
matches := regex.FindAllNamedRegexMatch(fmt.Sprintf(`(?P<element>[^\%s]+)`, separator), cleaned)
|
||||
n := len(matches) - 1
|
||||
for i, m := range matches {
|
||||
sb.WriteString(m["element"])
|
||||
if i != n {
|
||||
sb.WriteString(separator)
|
||||
}
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func ReplaceTildePrefixWithHomeDir(env Environment, path string) string {
|
||||
if !strings.HasPrefix(path, "~") {
|
||||
return path
|
||||
}
|
||||
rem := path[1:]
|
||||
if len(rem) == 0 || IsPathSeparator(env, rem[0]) {
|
||||
return env.Home() + rem
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func ReplaceHomeDirPrefixWithTilde(env Environment, path string) string {
|
||||
home := env.Home()
|
||||
if !strings.HasPrefix(path, home) {
|
||||
return path
|
||||
}
|
||||
rem := path[len(home):]
|
||||
if len(rem) == 0 || IsPathSeparator(env, rem[0]) {
|
||||
return "~" + rem
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func cleanHostName(hostName string) string {
|
||||
garbage := []string{
|
||||
".lan",
|
||||
|
|
|
@ -20,10 +20,6 @@ func (term *Terminal) Root() bool {
|
|||
return os.Geteuid() == 0
|
||||
}
|
||||
|
||||
func (term *Terminal) Home() string {
|
||||
return os.Getenv("HOME")
|
||||
}
|
||||
|
||||
func (term *Terminal) QueryWindowTitles(_, _ string) (string, error) {
|
||||
return "", &NotImplemented{}
|
||||
}
|
||||
|
@ -132,24 +128,24 @@ func (term *Terminal) InWSLSharedDrive() bool {
|
|||
return !strings.HasPrefix(windowsPath, `//wsl.localhost/`) && !strings.HasPrefix(windowsPath, `//wsl$/`)
|
||||
}
|
||||
|
||||
func (term *Terminal) ConvertToWindowsPath(path string) string {
|
||||
windowsPath, err := term.RunCommand("wslpath", "-m", path)
|
||||
func (term *Terminal) ConvertToWindowsPath(input string) string {
|
||||
windowsPath, err := term.RunCommand("wslpath", "-m", input)
|
||||
if err == nil {
|
||||
return windowsPath
|
||||
}
|
||||
return path
|
||||
return input
|
||||
}
|
||||
|
||||
func (term *Terminal) ConvertToLinuxPath(path string) string {
|
||||
if linuxPath, err := term.RunCommand("wslpath", "-u", path); err == nil {
|
||||
func (term *Terminal) ConvertToLinuxPath(input string) string {
|
||||
if linuxPath, err := term.RunCommand("wslpath", "-u", input); err == nil {
|
||||
return linuxPath
|
||||
}
|
||||
return path
|
||||
return input
|
||||
}
|
||||
|
||||
func (term *Terminal) DirIsWritable(path string) bool {
|
||||
defer term.Trace(time.Now(), path)
|
||||
return unix.Access(path, unix.W_OK) == nil
|
||||
func (term *Terminal) DirIsWritable(input string) bool {
|
||||
defer term.Trace(time.Now(), input)
|
||||
return unix.Access(input, unix.W_OK) == nil
|
||||
}
|
||||
|
||||
func (term *Terminal) Connection(_ ConnectionType) (*Connection, error) {
|
||||
|
|
|
@ -3,12 +3,12 @@ package runtime
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-ansiterm/winterm"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
@ -50,22 +50,6 @@ func (term *Terminal) Root() bool {
|
|||
return member
|
||||
}
|
||||
|
||||
func (term *Terminal) Home() string {
|
||||
home := os.Getenv("HOME")
|
||||
defer func() {
|
||||
term.Debug(home)
|
||||
}()
|
||||
if len(home) > 0 {
|
||||
return home
|
||||
}
|
||||
// fallback to older implemenations on Windows
|
||||
home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||
if home == "" {
|
||||
home = os.Getenv("USERPROFILE")
|
||||
}
|
||||
return home
|
||||
}
|
||||
|
||||
func (term *Terminal) QueryWindowTitles(processName, windowTitleRegex string) (string, error) {
|
||||
defer term.Trace(time.Now(), windowTitleRegex)
|
||||
title, err := queryWindowTitles(processName, windowTitleRegex)
|
||||
|
@ -128,8 +112,8 @@ func (term *Terminal) Platform() string {
|
|||
// If the path ends in "\", the "(Default)" key in that path is retrieved.
|
||||
//
|
||||
// Returns a variant type if successful; nil and an error if not.
|
||||
func (term *Terminal) WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error) {
|
||||
term.Trace(time.Now(), path)
|
||||
func (term *Terminal) WindowsRegistryKeyValue(input string) (*WindowsRegistryValue, error) {
|
||||
term.Trace(time.Now(), input)
|
||||
|
||||
// Format:
|
||||
// "HKLM\Software\Microsoft\Windows NT\CurrentVersion\EditionID"
|
||||
|
@ -143,16 +127,16 @@ func (term *Terminal) WindowsRegistryKeyValue(path string) (*WindowsRegistryValu
|
|||
//
|
||||
// If 3 is "" (i.e. the path ends with "\"), then get (Default) key.
|
||||
//
|
||||
rootKey, regPath, found := strings.Cut(path, `\`)
|
||||
rootKey, regPath, found := strings.Cut(input, `\`)
|
||||
if !found {
|
||||
err := fmt.Errorf("Error, malformed registry path: '%s'", path)
|
||||
err := fmt.Errorf("Error, malformed registry path: '%s'", input)
|
||||
term.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var regKey string
|
||||
if !strings.HasSuffix(regPath, `\`) {
|
||||
regKey = Base(term, regPath)
|
||||
regKey = path.Base(regPath)
|
||||
if len(regKey) != 0 {
|
||||
regPath = strings.TrimSuffix(regPath, `\`+regKey)
|
||||
}
|
||||
|
@ -218,17 +202,17 @@ func (term *Terminal) InWSLSharedDrive() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (term *Terminal) ConvertToWindowsPath(path string) string {
|
||||
return strings.ReplaceAll(path, `\`, "/")
|
||||
func (term *Terminal) ConvertToWindowsPath(input string) string {
|
||||
return strings.ReplaceAll(input, `\`, "/")
|
||||
}
|
||||
|
||||
func (term *Terminal) ConvertToLinuxPath(path string) string {
|
||||
return path
|
||||
func (term *Terminal) ConvertToLinuxPath(input string) string {
|
||||
return input
|
||||
}
|
||||
|
||||
func (term *Terminal) DirIsWritable(path string) bool {
|
||||
func (term *Terminal) DirIsWritable(input string) bool {
|
||||
defer term.Trace(time.Now())
|
||||
return term.isWriteable(path)
|
||||
return term.isWriteable(input)
|
||||
}
|
||||
|
||||
func (term *Terminal) Connection(connectionType ConnectionType) (*Connection, error) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
@ -365,8 +366,8 @@ func (g *Git) getBareRepoInfo() {
|
|||
// we can still have a pointer to a bare repo
|
||||
if file, err := g.env.HasParentFilePath(".git", true); err == nil && !file.IsDir {
|
||||
content := g.FileContents(file.ParentFolder, ".git")
|
||||
path := strings.TrimPrefix(content, "gitdir: ")
|
||||
g.workingDir = filepath.Join(file.ParentFolder, path)
|
||||
dir := strings.TrimPrefix(content, "gitdir: ")
|
||||
g.workingDir = filepath.Join(file.ParentFolder, dir)
|
||||
}
|
||||
|
||||
head := g.FileContents(g.workingDir, "HEAD")
|
||||
|
@ -384,7 +385,7 @@ func (g *Git) getBareRepoInfo() {
|
|||
}
|
||||
|
||||
func (g *Git) setDir(dir string) {
|
||||
dir = runtime.ReplaceHomeDirPrefixWithTilde(g.env, dir) // align with template PWD
|
||||
dir = path.ReplaceHomeDirPrefixWithTilde(dir) // align with template PWD
|
||||
if g.env.GOOS() == runtime.WINDOWS {
|
||||
g.Dir = strings.TrimSuffix(dir, `\.git`)
|
||||
return
|
||||
|
@ -516,9 +517,9 @@ func (g *Git) cleanUpstreamURL(url string) string {
|
|||
}
|
||||
|
||||
if len(match) != 0 {
|
||||
path := strings.Trim(match["PATH"], "/")
|
||||
path = strings.TrimSuffix(path, ".git")
|
||||
return fmt.Sprintf("https://%s/%s", match["URL"], path)
|
||||
repoPath := strings.Trim(match["PATH"], "/")
|
||||
repoPath = strings.TrimSuffix(repoPath, ".git")
|
||||
return fmt.Sprintf("https://%s/%s", match["URL"], repoPath)
|
||||
}
|
||||
|
||||
// codecommit::region-identifier-id://repo-name
|
||||
|
@ -923,12 +924,12 @@ func (g *Git) getSwitchMode(property properties.Property, gitSwitch, mode string
|
|||
|
||||
func (g *Git) repoName() string {
|
||||
if !g.IsWorkTree {
|
||||
return runtime.Base(g.env, g.convertToLinuxPath(g.realDir))
|
||||
return path.Base(g.convertToLinuxPath(g.realDir))
|
||||
}
|
||||
|
||||
ind := strings.LastIndex(g.workingDir, ".git/worktrees")
|
||||
if ind > -1 {
|
||||
return runtime.Base(g.env, g.workingDir[:ind])
|
||||
return path.Base(g.workingDir[:ind])
|
||||
}
|
||||
|
||||
return ""
|
||||
|
|
|
@ -9,5 +9,6 @@ func resolveGitPath(base, path string) string {
|
|||
if filepath.IsAbs(path) {
|
||||
return path
|
||||
}
|
||||
|
||||
return filepath.Join(base, path)
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@ func resolveGitPath(base, path string) string {
|
|||
if len(path) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
if filepath.IsAbs(path) {
|
||||
return path
|
||||
}
|
||||
|
||||
// Note that git on Windows uses slashes exclusively. And it's okay
|
||||
// because Windows actually accepts both directory separators. More
|
||||
// importantly, however, parts of the git segment depend on those
|
||||
|
@ -18,5 +20,6 @@ func resolveGitPath(base, path string) string {
|
|||
// path is a disk-relative path.
|
||||
return filepath.VolumeName(base) + path
|
||||
}
|
||||
|
||||
return filepath.ToSlash(filepath.Join(base, path))
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -90,7 +91,7 @@ func (hg *Mercurial) shouldDisplay() bool {
|
|||
}
|
||||
|
||||
func (hg *Mercurial) setDir(dir string) {
|
||||
dir = runtime.ReplaceHomeDirPrefixWithTilde(hg.env, dir) // align with template PWD
|
||||
dir = path.ReplaceHomeDirPrefixWithTilde(dir) // align with template PWD
|
||||
if hg.env.GOOS() == runtime.WINDOWS {
|
||||
hg.Dir = strings.TrimSuffix(dir, `\.hg`)
|
||||
return
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -89,9 +90,6 @@ func TestOSInfo(t *testing.T) {
|
|||
env := new(mock.Environment)
|
||||
env.On("GOOS").Return(tc.GOOS)
|
||||
env.On("Platform").Return(tc.Platform)
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
WSL: tc.IsWSL,
|
||||
})
|
||||
|
||||
props := properties.Map{
|
||||
DisplayDistroName: tc.DisplayDistroName,
|
||||
|
@ -106,6 +104,10 @@ func TestOSInfo(t *testing.T) {
|
|||
osInfo := &Os{}
|
||||
osInfo.Init(props, env)
|
||||
|
||||
template.Cache = &cache.Template{
|
||||
WSL: tc.IsWSL,
|
||||
}
|
||||
|
||||
_ = osInfo.Enabled()
|
||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, osInfo.Template(), osInfo), tc.Case)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
)
|
||||
|
@ -126,7 +127,7 @@ func (pt *Path) Enabled() bool {
|
|||
pt.setStyle()
|
||||
pwd := pt.env.Pwd()
|
||||
|
||||
pt.Location = pt.env.TemplateCache().AbsolutePWD
|
||||
pt.Location = pt.env.Flags().AbsolutePWD
|
||||
if pt.env.GOOS() == runtime.WINDOWS {
|
||||
pt.Location = strings.ReplaceAll(pt.Location, `\`, `/`)
|
||||
}
|
||||
|
@ -152,7 +153,7 @@ func (pt *Path) setPaths() {
|
|||
|
||||
pt.cygPath = displayCygpath()
|
||||
pt.windowsPath = pt.env.GOOS() == runtime.WINDOWS && !pt.cygPath
|
||||
pt.pathSeparator = pt.env.PathSeparator()
|
||||
pt.pathSeparator = path.Separator()
|
||||
|
||||
pt.pwd = pt.env.Pwd()
|
||||
if (pt.env.Shell() == shell.PWSH || pt.env.Shell() == shell.PWSH5) && len(pt.env.Flags().PSWD) != 0 {
|
||||
|
@ -186,10 +187,12 @@ func (pt *Path) Parent() string {
|
|||
if !pt.endWithSeparator(pt.root) {
|
||||
sb.WriteString(folderSeparator)
|
||||
}
|
||||
|
||||
for _, folder := range folders[:len(folders)-1] {
|
||||
sb.WriteString(folder)
|
||||
sb.WriteString(folderSeparator)
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
|
@ -267,6 +270,7 @@ func (pt *Path) getFolderSeparator() string {
|
|||
if len(separator) == 0 {
|
||||
return pt.pathSeparator
|
||||
}
|
||||
|
||||
return separator
|
||||
}
|
||||
|
||||
|
@ -568,21 +572,21 @@ func (pt *Path) setMappedLocations() {
|
|||
Context: pt,
|
||||
}
|
||||
|
||||
path, err := tmpl.Render()
|
||||
location, err := tmpl.Render()
|
||||
if err != nil {
|
||||
pt.env.Error(err)
|
||||
}
|
||||
|
||||
if len(path) == 0 {
|
||||
if len(location) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// When two templates resolve to the same key, the values are compared in ascending order and the latter is taken.
|
||||
if v, exist := mappedLocations[pt.normalize(path)]; exist && value <= v {
|
||||
if v, exist := mappedLocations[pt.normalize(location)]; exist && value <= v {
|
||||
continue
|
||||
}
|
||||
|
||||
mappedLocations[pt.normalize(path)] = value
|
||||
mappedLocations[pt.normalize(location)] = value
|
||||
}
|
||||
|
||||
pt.mappedLocations = mappedLocations
|
||||
|
@ -660,9 +664,9 @@ func (pt *Path) parsePath(inputPath string) (string, string) {
|
|||
}
|
||||
|
||||
if pt.cygPath {
|
||||
path, err := pt.env.RunCommand("cygpath", "-u", inputPath)
|
||||
if len(path) != 0 {
|
||||
inputPath = path
|
||||
cygPath, err := pt.env.RunCommand("cygpath", "-u", inputPath)
|
||||
if len(cygPath) != 0 {
|
||||
inputPath = cygPath
|
||||
pt.pathSeparator = "/"
|
||||
}
|
||||
|
||||
|
@ -697,25 +701,26 @@ func (pt *Path) parsePath(inputPath string) (string, string) {
|
|||
return root, relative
|
||||
}
|
||||
|
||||
func (pt *Path) isRootFS(path string) bool {
|
||||
return len(path) == 1 && runtime.IsPathSeparator(pt.env, path[0])
|
||||
func (pt *Path) isRootFS(inputPath string) bool {
|
||||
return len(inputPath) == 1 && path.IsSeparator(inputPath[0])
|
||||
}
|
||||
|
||||
func (pt *Path) endWithSeparator(path string) bool {
|
||||
if len(path) == 0 {
|
||||
func (pt *Path) endWithSeparator(inputPath string) bool {
|
||||
if len(inputPath) == 0 {
|
||||
return false
|
||||
}
|
||||
return runtime.IsPathSeparator(pt.env, path[len(path)-1])
|
||||
|
||||
return path.IsSeparator(inputPath[len(inputPath)-1])
|
||||
}
|
||||
|
||||
func (pt *Path) normalize(inputPath string) string {
|
||||
normalized := inputPath
|
||||
|
||||
if strings.HasPrefix(normalized, "~") && (len(normalized) == 1 || runtime.IsPathSeparator(pt.env, normalized[1])) {
|
||||
if strings.HasPrefix(normalized, "~") && (len(normalized) == 1 || path.IsSeparator(normalized[1])) {
|
||||
normalized = pt.env.Home() + normalized[1:]
|
||||
}
|
||||
|
||||
normalized = runtime.CleanPath(pt.env, normalized)
|
||||
normalized = path.Clean(normalized)
|
||||
|
||||
if pt.env.GOOS() == runtime.WINDOWS || pt.env.GOOS() == runtime.DARWIN {
|
||||
normalized = strings.ToLower(normalized)
|
||||
|
@ -827,9 +832,9 @@ func (pt *Path) makeFolderFormatMap() map[string]string {
|
|||
if gitDirFormat := pt.props.GetString(GitDirFormat, ""); len(gitDirFormat) != 0 {
|
||||
dir, err := pt.env.HasParentFilePath(".git", false)
|
||||
if err == nil && dir.IsDir {
|
||||
// Make it consistent with the modified path.
|
||||
path := pt.join(pt.replaceMappedLocations(dir.ParentFolder))
|
||||
folderFormatMap[path] = gitDirFormat
|
||||
// Make it consistent with the modified parent.
|
||||
parent := pt.join(pt.replaceMappedLocations(dir.ParentFolder))
|
||||
folderFormatMap[parent] = gitDirFormat
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
812
src/segments/path_unix_test.go
Normal file
812
src/segments/path_unix_test.go
Normal file
|
@ -0,0 +1,812 @@
|
|||
//go:build !windows
|
||||
|
||||
package segments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var testParentCases = []testParentCase{
|
||||
{
|
||||
Case: "Inside Home folder",
|
||||
Expected: "~/",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/test",
|
||||
GOOS: runtime.DARWIN,
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Home folder",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir,
|
||||
GOOS: runtime.DARWIN,
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Home folder with a trailing separator",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/",
|
||||
GOOS: runtime.DARWIN,
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Root",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/",
|
||||
GOOS: runtime.DARWIN,
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Root + 1",
|
||||
Expected: "/",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr",
|
||||
GOOS: runtime.DARWIN,
|
||||
PathSeparator: "/",
|
||||
},
|
||||
}
|
||||
|
||||
var testAgnosterPathStyleCases = []testAgnosterPathStyleCase{
|
||||
{
|
||||
Style: Unique,
|
||||
Expected: "~ > a > ab > abcd",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/ab/abc/abcd",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Unique,
|
||||
Expected: "~ > a > .a > abcd",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/ab/.abc/abcd",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Unique,
|
||||
Expected: "~ > a > ab > abcd",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/ab/ab/abcd",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Unique,
|
||||
Expected: "a",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/ab",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
|
||||
{
|
||||
Style: Powerlevel,
|
||||
Expected: "t > w > o > a > v > l > p > wh > we > i > wa > th > the > d > f > u > it > c > to > a > co > stream",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/there/was/once/a/very/long/path/which/wended/its/way/through/the/dark/forest/until/it/came/to/a/cold/stream",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxWidth: 20,
|
||||
},
|
||||
{
|
||||
Style: Powerlevel,
|
||||
Expected: "t > w > o > a > v > l > p > which > wended > its > way > through > the",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/there/was/once/a/very/long/path/which/wended/its/way/through/the",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxWidth: 70,
|
||||
},
|
||||
{
|
||||
Style: Powerlevel,
|
||||
Expected: "var/cache/pacman",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/var/cache/pacman",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: "/",
|
||||
MaxWidth: 50,
|
||||
},
|
||||
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "~",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir,
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "~ > a > w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/ab/whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > b > a > w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/burp/ab/whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > .b > a > w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/.burp/ab/whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > .b > a > .w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/.burp/ab/.whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > .b > a > ._w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/.burp/ab/._whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > .ä > ū > .w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/.äufbau/ūmgebung/.whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > .b > 1 > .w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/.burp/12345/.whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > .b > 1 > .w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/.burp/12345abc/.whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "u > .b > __p > .w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/.burp/__pycache__/.whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "➼ > .w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/➼/.whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "➼ s > .w > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/➼ something/.whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "w",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/whatever",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
|
||||
{
|
||||
Style: Mixed,
|
||||
Expected: "~ > .. > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Mixed,
|
||||
Expected: "~ > ab > .. > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/ab/whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Mixed,
|
||||
Expected: "usr > foo > bar > .. > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/foo/bar/foobar/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Mixed,
|
||||
Expected: "whatever > .. > foo > bar",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/whatever/foobar/foo/bar",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterFull,
|
||||
Expected: "usr > location > whatever",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/location/whatever",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterFull,
|
||||
Expected: "PSDRIVE: | src",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/foo",
|
||||
Pswd: "PSDRIVE:/src",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " | ",
|
||||
},
|
||||
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: ".. | src | init",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/foo",
|
||||
Pswd: "PSDRIVE:/src/init",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " | ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "usr > foo > bar > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/foo/bar/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 3,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "PSDRIVE: | src",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/foo",
|
||||
Pswd: "PSDRIVE:/src",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " | ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > projects",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/projects",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir,
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 1,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "usr > .. > bar > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/foo/bar/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > .. > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "usr > .. > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/location/whatever/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > .. > bar > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/foo/bar/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > foo > bar > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/foo/bar/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 3,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "PSDRIVE: | .. | init",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/foo",
|
||||
Pswd: "PSDRIVE:/src/init",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " | ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: ".. > foo",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/foo",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 1,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: ".. > bar > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/bar/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: ".. > foo > bar > man",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/usr/foo/bar/man",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 3,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > foo",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/foo",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > foo > bar",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/foo/bar",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 3,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "C: | ",
|
||||
HomePath: homeDir,
|
||||
Pwd: "/mnt/c",
|
||||
Pswd: "C:",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " | ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ | space foo",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/space foo",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " | ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: ".. | space foo",
|
||||
HomePath: homeDir,
|
||||
Pwd: homeDir + "/space foo",
|
||||
PathSeparator: "/",
|
||||
FolderSeparatorIcon: " | ",
|
||||
MaxDepth: 1,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
}
|
||||
|
||||
var testAgnosterPathCases = []testAgnosterPathCase{
|
||||
{
|
||||
Case: "Unix outside home",
|
||||
Expected: "mnt > f > f > location",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/go/test/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Unix inside home",
|
||||
Expected: "~ > f > f > location",
|
||||
Home: homeDir,
|
||||
PWD: homeDir + "/docs/jan/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Unix outside home zero levels",
|
||||
Expected: "mnt > location",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Unix outside home one level",
|
||||
Expected: "mnt > f > location",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/folder/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Unix, colorize",
|
||||
Expected: "<blue>mnt</> > <yellow>f</> > <blue>location</>",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/folder/location",
|
||||
PathSeparator: "/",
|
||||
Cycle: []string{"blue", "yellow"},
|
||||
},
|
||||
{
|
||||
Case: "Unix, colorize with folder separator",
|
||||
Expected: "<blue>mnt</><yellow> > </><yellow>f</><blue> > </><blue>location</>",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/folder/location",
|
||||
PathSeparator: "/",
|
||||
Cycle: []string{"blue", "yellow"},
|
||||
ColorSeparator: true,
|
||||
},
|
||||
{
|
||||
Case: "Unix one level",
|
||||
Expected: "mnt",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
}
|
||||
|
||||
var testAgnosterLeftPathCases = []testAgnosterLeftPathCase{
|
||||
{
|
||||
Case: "Unix outside home",
|
||||
Expected: "mnt > go > f > f",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/go/test/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Unix inside home",
|
||||
Expected: "~ > docs > f > f",
|
||||
Home: homeDir,
|
||||
PWD: homeDir + "/docs/jan/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Unix outside home zero levels",
|
||||
Expected: "mnt > location",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
{
|
||||
Case: "Unix outside home one level",
|
||||
Expected: "mnt > folder > f",
|
||||
Home: homeDir,
|
||||
PWD: "/mnt/folder/location",
|
||||
PathSeparator: "/",
|
||||
},
|
||||
}
|
||||
|
||||
var testFullAndFolderPathCases = []testFullAndFolderPathCase{
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", Expected: "/"},
|
||||
{Style: Full, Pwd: "/", Expected: "/"},
|
||||
{Style: Full, Pwd: homeDir, Expected: "~"},
|
||||
{Style: Full, Pwd: homeDir + abc, Expected: "~/abc"},
|
||||
{Style: Full, Pwd: homeDir + abc, Expected: homeDir + abc, DisableMappedLocations: true},
|
||||
{Style: Full, Pwd: abcd, Expected: abcd},
|
||||
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "~"},
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "/home|someone", DisableMappedLocations: true},
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: homeDir + abc, Expected: "~|abc"},
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: abcd, Expected: "/a|b|c|d"},
|
||||
|
||||
{Style: FolderType, Pwd: "/", Expected: "/"},
|
||||
{Style: FolderType, Pwd: homeDir, Expected: "~"},
|
||||
{Style: FolderType, Pwd: homeDir, Expected: "someone", DisableMappedLocations: true},
|
||||
{Style: FolderType, Pwd: homeDir + abc, Expected: "abc"},
|
||||
{Style: FolderType, Pwd: abcd, Expected: "d"},
|
||||
|
||||
{Style: FolderType, FolderSeparatorIcon: "|", Pwd: "/", Expected: "/"},
|
||||
{Style: FolderType, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "~"},
|
||||
{Style: FolderType, FolderSeparatorIcon: "|", Pwd: homeDir, Expected: "someone", DisableMappedLocations: true},
|
||||
{Style: FolderType, FolderSeparatorIcon: "|", Pwd: homeDir + abc, Expected: "abc"},
|
||||
{Style: FolderType, FolderSeparatorIcon: "|", Pwd: abcd, Expected: "d"},
|
||||
|
||||
// StackCountEnabled=true and StackCount=2
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: 2, Expected: "2 /"},
|
||||
{Style: Full, Pwd: "/", StackCount: 2, Expected: "2 /"},
|
||||
{Style: Full, Pwd: homeDir, StackCount: 2, Expected: "2 ~"},
|
||||
{Style: Full, Pwd: homeDir + abc, StackCount: 2, Expected: "2 ~/abc"},
|
||||
{Style: Full, Pwd: homeDir + abc, StackCount: 2, Expected: "2 " + homeDir + abc, DisableMappedLocations: true},
|
||||
{Style: Full, Pwd: abcd, StackCount: 2, Expected: "2 /a/b/c/d"},
|
||||
|
||||
// StackCountEnabled=false and StackCount=2
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", Template: "{{ .Path }}", StackCount: 2, Expected: "/"},
|
||||
{Style: Full, Pwd: "/", Template: "{{ .Path }}", StackCount: 2, Expected: "/"},
|
||||
{Style: Full, Pwd: homeDir, Template: "{{ .Path }}", StackCount: 2, Expected: "~"},
|
||||
|
||||
{Style: Full, Pwd: homeDir + abc, Template: "{{ .Path }}", StackCount: 2, Expected: homeDir + abc, DisableMappedLocations: true},
|
||||
{Style: Full, Pwd: abcd, Template: "{{ .Path }}", StackCount: 2, Expected: abcd},
|
||||
|
||||
// StackCountEnabled=true and StackCount=0
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: 0, Expected: "/"},
|
||||
{Style: Full, Pwd: "/", StackCount: 0, Expected: "/"},
|
||||
{Style: Full, Pwd: homeDir, StackCount: 0, Expected: "~"},
|
||||
{Style: Full, Pwd: homeDir + abc, StackCount: 0, Expected: "~/abc"},
|
||||
{Style: Full, Pwd: homeDir + abc, StackCount: 0, Expected: homeDir + abc, DisableMappedLocations: true},
|
||||
{Style: Full, Pwd: abcd, StackCount: 0, Expected: abcd},
|
||||
|
||||
// StackCountEnabled=true and StackCount<0
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: -1, Expected: "/"},
|
||||
{Style: Full, Pwd: "/", StackCount: -1, Expected: "/"},
|
||||
{Style: Full, Pwd: homeDir, StackCount: -1, Expected: "~"},
|
||||
{Style: Full, Pwd: homeDir + abc, StackCount: -1, Expected: "~/abc"},
|
||||
{Style: Full, Pwd: homeDir + abc, StackCount: -1, Expected: homeDir + abc, DisableMappedLocations: true},
|
||||
{Style: Full, Pwd: abcd, StackCount: -1, Expected: abcd},
|
||||
|
||||
// StackCountEnabled=true and StackCount not set
|
||||
{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", Expected: "/"},
|
||||
{Style: Full, Pwd: "/", Expected: "/"},
|
||||
{Style: Full, Pwd: homeDir, Expected: "~"},
|
||||
{Style: Full, Pwd: homeDir + abc, Expected: "~/abc"},
|
||||
{Style: Full, Pwd: homeDir + abc, Expected: homeDir + abc, DisableMappedLocations: true},
|
||||
{Style: Full, Pwd: abcd, Expected: abcd},
|
||||
}
|
||||
|
||||
var testFullPathCustomMappedLocationsCases = []testFullPathCustomMappedLocationsCase{
|
||||
{Pwd: homeDir + "/d", MappedLocations: map[string]string{"{{ .Env.HOME }}/d": "#"}, Expected: "#"},
|
||||
{Pwd: abcd, MappedLocations: map[string]string{abcd: "#"}, Expected: "#"},
|
||||
{Pwd: abcd, MappedLocations: map[string]string{"/a/b": "#"}, Expected: "#/c/d"},
|
||||
{Pwd: abcd, MappedLocations: map[string]string{"/a/b": "/e/f"}, Expected: "/e/f/c/d"},
|
||||
{Pwd: homeDir + abcd, MappedLocations: map[string]string{"~/a/b": "#"}, Expected: "#/c/d"},
|
||||
{Pwd: "/a" + homeDir + "/b/c/d", MappedLocations: map[string]string{"/a~": "#"}, Expected: "/a" + homeDir + "/b/c/d"},
|
||||
{Pwd: homeDir + abcd, MappedLocations: map[string]string{"/a/b": "#"}, Expected: homeDir + abcd},
|
||||
}
|
||||
|
||||
var testSplitPathCases = []testSplitPathCase{
|
||||
{Case: "Root directory", Root: "/", Expected: Folders{}},
|
||||
{
|
||||
Case: "Regular directory",
|
||||
Root: "/",
|
||||
Relative: "c/d",
|
||||
GOOS: runtime.DARWIN,
|
||||
Expected: Folders{
|
||||
{Name: "c", Path: "/c"},
|
||||
{Name: "d", Path: "/c/d"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Case: "Home directory - git folder",
|
||||
Root: "~",
|
||||
Relative: "c/d",
|
||||
GOOS: runtime.DARWIN,
|
||||
GitDir: &runtime.FileInfo{IsDir: true, ParentFolder: "/a/b/c"},
|
||||
GitDirFormat: "<b>%s</b>",
|
||||
Expected: Folders{
|
||||
{Name: "<b>c</b>", Path: "~/c", Display: true},
|
||||
{Name: "d", Path: "~/c/d"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var testNormalizePathCases = []testNormalizePathCase{
|
||||
{
|
||||
Case: "Linux: home prefix, backslash included",
|
||||
Input: "~/Bob\\Foo",
|
||||
HomeDir: homeDir,
|
||||
GOOS: runtime.LINUX,
|
||||
Expected: homeDir + "/Bob\\Foo",
|
||||
},
|
||||
{
|
||||
Case: "macOS: home prefix, backslash included",
|
||||
Input: "~/Bob\\Foo",
|
||||
HomeDir: homeDir,
|
||||
GOOS: runtime.DARWIN,
|
||||
Expected: homeDir + "/bob\\foo",
|
||||
},
|
||||
{
|
||||
Case: "Linux: absolute",
|
||||
Input: "/foo/~/bar",
|
||||
HomeDir: homeDir,
|
||||
GOOS: runtime.LINUX,
|
||||
Expected: "/foo/~/bar",
|
||||
},
|
||||
{
|
||||
Case: "Linux: home prefix",
|
||||
Input: "~/baz",
|
||||
HomeDir: homeDir,
|
||||
GOOS: runtime.LINUX,
|
||||
Expected: homeDir + "/baz",
|
||||
},
|
||||
}
|
||||
|
||||
func TestFolderPathCustomMappedLocations(t *testing.T) {
|
||||
pwd := abcd
|
||||
env := new(mock.Environment)
|
||||
env.On("PathSeparator").Return("/")
|
||||
env.On("Home").Return(homeDir)
|
||||
env.On("Pwd").Return(pwd)
|
||||
env.On("GOOS").Return("")
|
||||
args := &runtime.Flags{
|
||||
PSWD: pwd,
|
||||
}
|
||||
env.On("Flags").Return(args)
|
||||
env.On("Shell").Return(shell.GENERIC)
|
||||
|
||||
template.Cache = new(cache.Template)
|
||||
template.Init(env, nil)
|
||||
|
||||
props := properties.Map{
|
||||
properties.Style: FolderType,
|
||||
MappedLocations: map[string]string{
|
||||
abcd: "#",
|
||||
},
|
||||
}
|
||||
|
||||
path := &Path{}
|
||||
path.Init(props, env)
|
||||
|
||||
path.setPaths()
|
||||
path.setStyle()
|
||||
|
||||
got := renderTemplateNoTrimSpace(env, "{{ .Path }}", path)
|
||||
assert.Equal(t, "#", got)
|
||||
}
|
||||
|
||||
func TestReplaceMappedLocations(t *testing.T) {
|
||||
cases := []struct {
|
||||
Case string
|
||||
Pwd string
|
||||
Expected string
|
||||
MappedLocationsEnabled bool
|
||||
}{
|
||||
{Pwd: "/c/l/k/f", Expected: "f"},
|
||||
{Pwd: "/f/g/h", Expected: "/f/g/h"},
|
||||
{Pwd: "/f/g/h/e", Expected: "^/e"},
|
||||
{Pwd: abcd, Expected: "#"},
|
||||
{Pwd: "/a/b/c/d/e", Expected: "#/e"},
|
||||
{Pwd: "/a/b/c/D/e", Expected: "#/e"},
|
||||
{Pwd: "/a/b/k/j/e", Expected: "e"},
|
||||
{Pwd: "/a/b/k/l", Expected: "@/l"},
|
||||
{Pwd: "/a/b/k/l", MappedLocationsEnabled: true, Expected: "~/l"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
env := new(mock.Environment)
|
||||
env.On("PathSeparator").Return("/")
|
||||
env.On("Pwd").Return(tc.Pwd)
|
||||
env.On("Shell").Return(shell.FISH)
|
||||
env.On("GOOS").Return(runtime.DARWIN)
|
||||
env.On("Home").Return("/a/b/k")
|
||||
|
||||
template.Cache = new(cache.Template)
|
||||
template.Init(env, nil)
|
||||
|
||||
props := properties.Map{
|
||||
MappedLocationsEnabled: tc.MappedLocationsEnabled,
|
||||
MappedLocations: map[string]string{
|
||||
abcd: "#",
|
||||
"/f/g/h/*": "^",
|
||||
"/c/l/k/*": "",
|
||||
"~": "@",
|
||||
"~/j/*": "",
|
||||
},
|
||||
}
|
||||
|
||||
path := &Path{}
|
||||
path.Init(props, env)
|
||||
|
||||
path.setPaths()
|
||||
assert.Equal(t, tc.Expected, path.pwd)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPwd(t *testing.T) {
|
||||
cases := []struct {
|
||||
Pwd string
|
||||
Pswd string
|
||||
Expected string
|
||||
MappedLocationsEnabled bool
|
||||
}{
|
||||
{MappedLocationsEnabled: true, Pwd: homeDir, Expected: "~"},
|
||||
{MappedLocationsEnabled: true, Pwd: homeDir + "-test", Expected: homeDir + "-test"},
|
||||
{MappedLocationsEnabled: true},
|
||||
{MappedLocationsEnabled: true, Pwd: "/usr", Expected: "/usr"},
|
||||
{MappedLocationsEnabled: true, Pwd: homeDir + abc, Expected: "~/abc"},
|
||||
{MappedLocationsEnabled: true, Pwd: abcd, Expected: "#"},
|
||||
{MappedLocationsEnabled: true, Pwd: "/a/b/c/d/e/f/g", Expected: "#/e/f/g"},
|
||||
{MappedLocationsEnabled: true, Pwd: "/z/y/x/w", Expected: "/z/y/x/w"},
|
||||
|
||||
{MappedLocationsEnabled: false},
|
||||
{MappedLocationsEnabled: false, Pwd: homeDir + abc, Expected: homeDir + abc},
|
||||
{MappedLocationsEnabled: false, Pwd: "/a/b/c/d/e/f/g", Expected: "#/e/f/g"},
|
||||
{MappedLocationsEnabled: false, Pwd: homeDir + cdefg, Expected: homeDir + cdefg},
|
||||
{MappedLocationsEnabled: true, Pwd: homeDir + cdefg, Expected: "~/c/d/e/f/g"},
|
||||
|
||||
{MappedLocationsEnabled: true, Pwd: "/w/d/x/w", Pswd: "/z/y/x/w", Expected: "/z/y/x/w"},
|
||||
{MappedLocationsEnabled: false, Pwd: "/f/g/k/d/e/f/g", Pswd: "/a/b/c/d/e/f/g", Expected: "#/e/f/g"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
env := new(mock.Environment)
|
||||
env.On("PathSeparator").Return("/")
|
||||
env.On("Home").Return(homeDir)
|
||||
env.On("Pwd").Return(tc.Pwd)
|
||||
env.On("GOOS").Return("")
|
||||
args := &runtime.Flags{
|
||||
PSWD: tc.Pswd,
|
||||
}
|
||||
env.On("Flags").Return(args)
|
||||
env.On("Shell").Return(shell.PWSH)
|
||||
|
||||
template.Cache = new(cache.Template)
|
||||
template.Init(env, nil)
|
||||
|
||||
props := properties.Map{
|
||||
MappedLocationsEnabled: tc.MappedLocationsEnabled,
|
||||
MappedLocations: map[string]string{
|
||||
abcd: "#",
|
||||
},
|
||||
}
|
||||
|
||||
path := &Path{}
|
||||
path.Init(props, env)
|
||||
|
||||
path.setPaths()
|
||||
assert.Equal(t, tc.Expected, path.pwd)
|
||||
}
|
||||
}
|
524
src/segments/path_windows_test.go
Normal file
524
src/segments/path_windows_test.go
Normal file
|
@ -0,0 +1,524 @@
|
|||
package segments
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
)
|
||||
|
||||
var testParentCases = []testParentCase{
|
||||
{
|
||||
Case: "Windows Home folder",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows drive root",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows drive root with a trailing separator",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows drive root + 1",
|
||||
Expected: "C:\\",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\test",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "PSDrive root",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "HKLM:",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
}
|
||||
|
||||
var testAgnosterPathStyleCases = []testAgnosterPathStyleCase{
|
||||
{
|
||||
Style: Unique,
|
||||
Expected: "C > a > ab > abcd",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\ab\\ab\\abcd",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "C: > ",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "C > s > .w > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\something\\.whatever\\man",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Letter,
|
||||
Expected: "~ > s > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows + "\\something\\man",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Mixed,
|
||||
Expected: "C: > .. > foo > .. > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\Users\\foo\\foobar\\man",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Mixed,
|
||||
Expected: "c > .. > foo > .. > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\Users\\foo\\foobar\\man",
|
||||
GOOS: runtime.WINDOWS,
|
||||
Shell: shell.BASH,
|
||||
Cygwin: true,
|
||||
Cygpath: "/c/Users/foo/foobar/man",
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: Mixed,
|
||||
Expected: "C: > .. > foo > .. > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\Users\\foo\\foobar\\man",
|
||||
GOOS: runtime.WINDOWS,
|
||||
Shell: shell.BASH,
|
||||
CygpathError: errors.New("oh no"),
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "\\\\localhost\\c$ > some",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "\\\\localhost\\c$\\some",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "\\\\localhost\\c$",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "\\\\localhost\\c$",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: ".. > bar > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows + fooBarMan,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "C: > ",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "C: > .. > bar > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\usr\\foo\\bar\\man",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "C: > .. > foo > bar > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: "C:\\usr\\foo\\bar\\man",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 3,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > .. > bar > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows + fooBarMan,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > foo > bar > man",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows + fooBarMan,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 3,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 1,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: ".. > foo",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows + "\\foo",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 1,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
{
|
||||
Style: AgnosterShort,
|
||||
Expected: "~ > foo",
|
||||
HomePath: homeDirWindows,
|
||||
Pwd: homeDirWindows + "\\foo",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
FolderSeparatorIcon: " > ",
|
||||
MaxDepth: 2,
|
||||
HideRootLocation: true,
|
||||
},
|
||||
}
|
||||
|
||||
var testAgnosterPathCases = []testAgnosterPathCase{
|
||||
{
|
||||
Case: "Windows registry drive case sensitive",
|
||||
Expected: "\uf013 > f > magnetic:TOAST",
|
||||
Home: homeDirWindows,
|
||||
PWD: "HKLM:\\SOFTWARE\\magnetic:TOAST\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows outside home",
|
||||
Expected: "C: > f > f > location",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\Program Files\\Go\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows oustide home",
|
||||
Expected: "~ > f > f > location",
|
||||
Home: homeDirWindows,
|
||||
PWD: homeDirWindows + "\\Documents\\Bill\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows inside home zero levels",
|
||||
Expected: "C: > location",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows inside home one level",
|
||||
Expected: "C: > f > location",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\Program Files\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower case drive letter",
|
||||
Expected: "C: > Windows",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\Windows\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower case drive letter (other)",
|
||||
Expected: "P: > Other",
|
||||
Home: homeDirWindows,
|
||||
PWD: "P:\\Other\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower word drive",
|
||||
Expected: "some: > some",
|
||||
Home: homeDirWindows,
|
||||
PWD: "some:\\some\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower word drive (ending with c)",
|
||||
Expected: "src: > source",
|
||||
Home: homeDirWindows,
|
||||
PWD: "src:\\source\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower word drive (arbitrary cases)",
|
||||
Expected: "sRc: > source",
|
||||
Home: homeDirWindows,
|
||||
PWD: "sRc:\\source\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows registry drive",
|
||||
Expected: "\uf013 > f > magnetic:test",
|
||||
Home: homeDirWindows,
|
||||
PWD: "HKLM:\\SOFTWARE\\magnetic:test\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
}
|
||||
|
||||
var testAgnosterLeftPathCases = []testAgnosterLeftPathCase{
|
||||
{
|
||||
Case: "Windows inside home",
|
||||
Expected: "~ > Documents > f > f",
|
||||
Home: homeDirWindows,
|
||||
PWD: homeDirWindows + "\\Documents\\Bill\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows outside home",
|
||||
Expected: "C: > Program Files > f > f",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\Program Files\\Go\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows inside home zero levels",
|
||||
Expected: "C: > location",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows inside home one level",
|
||||
Expected: "C: > Program Files > f",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\Program Files\\location",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower case drive letter",
|
||||
Expected: "C: > Windows",
|
||||
Home: homeDirWindows,
|
||||
PWD: "C:\\Windows\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower case drive letter (other)",
|
||||
Expected: "P: > Other",
|
||||
Home: homeDirWindows,
|
||||
PWD: "P:\\Other\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower word drive",
|
||||
Expected: "some: > some",
|
||||
Home: homeDirWindows,
|
||||
PWD: "some:\\some\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower word drive (ending with c)",
|
||||
Expected: "src: > source",
|
||||
Home: homeDirWindows,
|
||||
PWD: "src:\\source\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows lower word drive (arbitrary cases)",
|
||||
Expected: "sRc: > source",
|
||||
Home: homeDirWindows,
|
||||
PWD: "sRc:\\source\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows registry drive",
|
||||
Expected: "\uf013 > SOFTWARE > f",
|
||||
Home: homeDirWindows,
|
||||
PWD: "HKLM:\\SOFTWARE\\magnetic:test\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
{
|
||||
Case: "Windows registry drive case sensitive",
|
||||
Expected: "\uf013 > SOFTWARE > f",
|
||||
Home: homeDirWindows,
|
||||
PWD: "HKLM:\\SOFTWARE\\magnetic:TOAST\\",
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: "\\",
|
||||
},
|
||||
}
|
||||
|
||||
var testFullAndFolderPathCases = []testFullAndFolderPathCase{
|
||||
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: "C:\\", Expected: "C:\\", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: "\\\\localhost\\d$", Expected: "\\\\localhost\\d$", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: homeDirWindows, Expected: "~", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||
{Style: Full, FolderSeparatorIcon: "\\", Pwd: homeDirWindows, Expected: "~", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||
{Style: Full, FolderSeparatorIcon: "\\", Pwd: homeDirWindows + "\\abc", Expected: "~\\abc", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||
{Style: Full, FolderSeparatorIcon: "\\", Pwd: "C:\\Users\\posh", Expected: "C:\\Users\\posh", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||
}
|
||||
|
||||
var testFullPathCustomMappedLocationsCases = []testFullPathCustomMappedLocationsCase{
|
||||
{Pwd: "\\a\\b\\c\\d", MappedLocations: map[string]string{"\\a\\b": "#"}, GOOS: runtime.WINDOWS, PathSeparator: "\\", Expected: "#\\c\\d"},
|
||||
}
|
||||
|
||||
var testSplitPathCases = []testSplitPathCase{
|
||||
{
|
||||
Case: "Home directory - git folder on Windows",
|
||||
Root: "C:",
|
||||
Relative: "a/b/c/d",
|
||||
GOOS: runtime.WINDOWS,
|
||||
GitDir: &runtime.FileInfo{IsDir: true, ParentFolder: "C:/a/b/c"},
|
||||
GitDirFormat: "<b>%s</b>",
|
||||
Expected: Folders{
|
||||
{Name: "a", Path: "C:/a"},
|
||||
{Name: "b", Path: "C:/a/b"},
|
||||
{Name: "<b>c</b>", Path: "C:/a/b/c", Display: true},
|
||||
{Name: "d", Path: "C:/a/b/c/d"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var testNormalizePathCases = []testNormalizePathCase{
|
||||
{
|
||||
Case: "Windows: absolute w/o drive letter, forward slash included",
|
||||
Input: "/foo/~/bar",
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "\\foo\\~\\bar",
|
||||
},
|
||||
{
|
||||
Case: "Windows: absolute",
|
||||
Input: homeDirWindows + "\\Foo",
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "c:\\users\\someone\\foo",
|
||||
},
|
||||
{
|
||||
Case: "Windows: home prefix",
|
||||
Input: "~\\Bob\\Foo",
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "c:\\users\\someone\\bob\\foo",
|
||||
},
|
||||
{
|
||||
Case: "Windows: home prefix",
|
||||
Input: "~/baz",
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "c:\\users\\someone\\baz",
|
||||
},
|
||||
{
|
||||
Case: "Windows: UNC root w/ prefix",
|
||||
Input: `\\.\UNC\localhost\c$`,
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "\\\\localhost\\c$",
|
||||
},
|
||||
{
|
||||
Case: "Windows: UNC root w/ prefix, forward slash included",
|
||||
Input: "//./UNC/localhost/c$",
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "\\\\localhost\\c$",
|
||||
},
|
||||
{
|
||||
Case: "Windows: UNC root",
|
||||
Input: `\\localhost\c$\`,
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "\\\\localhost\\c$",
|
||||
},
|
||||
{
|
||||
Case: "Windows: UNC root, forward slash included",
|
||||
Input: "//localhost/c$",
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "\\\\localhost\\c$",
|
||||
},
|
||||
{
|
||||
Case: "Windows: UNC",
|
||||
Input: `\\localhost\c$\some`,
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "\\\\localhost\\c$\\some",
|
||||
},
|
||||
{
|
||||
Case: "Windows: UNC, forward slash included",
|
||||
Input: "//localhost/c$/some",
|
||||
HomeDir: homeDirWindows,
|
||||
GOOS: runtime.WINDOWS,
|
||||
PathSeparator: `\`,
|
||||
Expected: "\\\\localhost\\c$\\some",
|
||||
},
|
||||
}
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
@ -135,23 +136,23 @@ func (p *Pulumi) getProjectName() error {
|
|||
|
||||
p.Name = pulumiFileSpec.Name
|
||||
|
||||
sha1HexString := func(value string) string {
|
||||
h := sha1.New()
|
||||
|
||||
_, err := h.Write([]byte(value))
|
||||
if err != nil {
|
||||
p.env.Error(err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
p.workspaceSHA1 = sha1HexString(p.env.Pwd() + p.env.PathSeparator() + fileName)
|
||||
p.workspaceSHA1 = p.sha1HexString(p.env.Pwd() + path.Separator() + fileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pulumi) sha1HexString(s string) string {
|
||||
h := sha1.New()
|
||||
|
||||
_, err := h.Write([]byte(s))
|
||||
if err != nil {
|
||||
p.env.Error(err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func (p *Pulumi) getPulumiAbout() {
|
||||
if len(p.Stack) == 0 {
|
||||
p.env.Error(fmt.Errorf("pulumi stack name is empty, use `fetch_stack` property to enable stack fetching"))
|
||||
|
|
|
@ -2,11 +2,13 @@ package segments
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
@ -161,7 +163,8 @@ description: A Console App
|
|||
env.On("RunCommand", "pulumi", []string{"stack", "ls", "--json"}).Return(tc.Stack, tc.StackError)
|
||||
env.On("RunCommand", "pulumi", []string{"about", "--json"}).Return(tc.About, tc.AboutError)
|
||||
|
||||
env.On("Pwd").Return("/home/foobar/Work/oh-my-posh/pulumi/projects/awesome-project")
|
||||
pwd := "/home/foobar/Work/oh-my-posh/pulumi/projects/awesome-project"
|
||||
env.On("Pwd").Return(pwd)
|
||||
env.On("Home").Return(filepath.Clean("/home/foobar"))
|
||||
env.On("Error", testify_.Anything)
|
||||
env.On("Debug", testify_.Anything)
|
||||
|
@ -173,11 +176,22 @@ description: A Console App
|
|||
env.On("HasFiles", pulumiJSON).Return(len(tc.JSONConfig) > 0)
|
||||
env.On("FileContent", pulumiJSON).Return(tc.JSONConfig, nil)
|
||||
|
||||
env.On("PathSeparator").Return("/")
|
||||
|
||||
env.On("HasFolder", filepath.Clean("/home/foobar/.pulumi/workspaces")).Return(tc.HasWorkspaceFolder)
|
||||
workspaceFile := "oh-my-posh-c62b7b6786c5c5a85896576e46a25d7c9f888e92-workspace.json"
|
||||
|
||||
pulumi := &Pulumi{}
|
||||
|
||||
var fileName string
|
||||
if len(tc.JSONConfig) > 0 {
|
||||
fileName = pulumiJSON
|
||||
} else {
|
||||
fileName = pulumiYAML
|
||||
}
|
||||
|
||||
sha1 := pulumi.sha1HexString(pwd + path.Separator() + fileName)
|
||||
workspaceFile := fmt.Sprintf("oh-my-posh-%s-workspace.json", sha1)
|
||||
|
||||
env.On("HasFilesInDir", filepath.Clean("/home/foobar/.pulumi/workspaces"), workspaceFile).Return(len(tc.WorkSpaceFile) > 0)
|
||||
|
||||
env.On("FileContent", filepath.Clean("/home/foobar/.pulumi/workspaces/"+workspaceFile)).Return(tc.WorkSpaceFile, nil)
|
||||
|
||||
props := properties.Map{
|
||||
|
@ -185,7 +199,6 @@ description: A Console App
|
|||
FetchAbout: tc.FetchAbout,
|
||||
}
|
||||
|
||||
pulumi := &Pulumi{}
|
||||
pulumi.Init(props, env)
|
||||
|
||||
assert.Equal(t, tc.ExpectedEnabled, pulumi.Enabled(), tc.Case)
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
)
|
||||
|
||||
type Python struct {
|
||||
|
@ -87,10 +87,10 @@ func (p *Python) loadContext() {
|
|||
continue
|
||||
}
|
||||
|
||||
name := runtime.Base(p.language.env, venv)
|
||||
name := path.Base(venv)
|
||||
if folderNameFallback && slices.Contains(defaultVenvNames, name) {
|
||||
venv = strings.TrimSuffix(venv, name)
|
||||
name = runtime.Base(p.language.env, venv)
|
||||
name = path.Base(venv)
|
||||
}
|
||||
|
||||
if p.canUseVenvName(name) {
|
||||
|
@ -121,23 +121,27 @@ func (p *Python) pyenvVersion() (string, error) {
|
|||
// Use `pyenv root` instead of $PYENV_ROOT?
|
||||
// Is our Python executable at $PYENV_ROOT/bin/python ?
|
||||
// Should p.env expose command paths?
|
||||
path := p.env.CommandPath("python")
|
||||
if len(path) == 0 {
|
||||
path = p.env.CommandPath("python3")
|
||||
cmdPath := p.env.CommandPath("python")
|
||||
if len(cmdPath) == 0 {
|
||||
cmdPath = p.env.CommandPath("python3")
|
||||
}
|
||||
if len(path) == 0 {
|
||||
|
||||
if len(cmdPath) == 0 {
|
||||
return "", errors.New("no python executable found")
|
||||
}
|
||||
|
||||
pyEnvRoot := p.env.Getenv("PYENV_ROOT")
|
||||
// TODO: pyenv-win has this at $PYENV_ROOT/pyenv-win/shims
|
||||
if path != filepath.Join(pyEnvRoot, "shims", "python") {
|
||||
return "", fmt.Errorf("executable at %s is not a pyenv shim", path)
|
||||
if cmdPath != filepath.Join(pyEnvRoot, "shims", "python") {
|
||||
return "", fmt.Errorf("executable at %s is not a pyenv shim", cmdPath)
|
||||
}
|
||||
|
||||
// pyenv version-name will return current version or virtualenv
|
||||
cmdOutput, err := p.env.RunCommand("pyenv", "version-name")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
versionString := strings.Split(cmdOutput, ":")[0]
|
||||
if len(versionString) == 0 {
|
||||
return "", errors.New("no pyenv version-name found")
|
||||
|
@ -148,34 +152,41 @@ func (p *Python) pyenvVersion() (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// ../versions/(version)[/envs/(virtualenv)]
|
||||
shortPath, err := filepath.Rel(filepath.Join(pyEnvRoot, "versions"), realPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// override virtualenv if pyenv set one
|
||||
parts := strings.Split(shortPath, string(filepath.Separator))
|
||||
if len(parts) > 2 && p.canUseVenvName(parts[2]) {
|
||||
p.Venv = parts[2]
|
||||
}
|
||||
|
||||
return parts[0], nil
|
||||
}
|
||||
|
||||
func (p *Python) pyvenvCfgPrompt() string {
|
||||
path := p.language.env.CommandPath("python")
|
||||
if len(path) == 0 {
|
||||
path = p.language.env.CommandPath("python3")
|
||||
cmdPath := p.language.env.CommandPath("python")
|
||||
if len(cmdPath) == 0 {
|
||||
cmdPath = p.language.env.CommandPath("python3")
|
||||
}
|
||||
if len(path) == 0 {
|
||||
|
||||
if len(cmdPath) == 0 {
|
||||
return ""
|
||||
}
|
||||
pyvenvDir := filepath.Dir(path)
|
||||
|
||||
pyvenvDir := filepath.Dir(cmdPath)
|
||||
if !p.language.env.HasFilesInDir(pyvenvDir, "pyvenv.cfg") {
|
||||
pyvenvDir = filepath.Dir(pyvenvDir)
|
||||
}
|
||||
|
||||
if !p.language.env.HasFilesInDir(pyvenvDir, "pyvenv.cfg") {
|
||||
return ""
|
||||
}
|
||||
|
||||
pyvenvCfg := p.env.FileContent(filepath.Join(pyvenvDir, "pyvenv.cfg"))
|
||||
for _, line := range strings.Split(pyvenvCfg, "\n") {
|
||||
lineSplit := strings.SplitN(line, "=", 2)
|
||||
|
@ -188,5 +199,6 @@ func (p *Python) pyvenvCfgPrompt() string {
|
|||
return value
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
)
|
||||
|
||||
// SaplingStatus represents part of the status of a Sapling repository
|
||||
|
@ -85,7 +86,7 @@ func (sl *Sapling) shouldDisplay() bool {
|
|||
sl.rootDir = slDir.Path
|
||||
// convert the worktree file path to a windows one when in a WSL shared folder
|
||||
sl.realDir = strings.TrimSuffix(sl.convertToWindowsPath(slDir.Path), "/.sl")
|
||||
sl.RepoName = runtime.Base(sl.env, sl.convertToLinuxPath(sl.realDir))
|
||||
sl.RepoName = path.Base(sl.convertToLinuxPath(sl.realDir))
|
||||
sl.setDir(slDir.Path)
|
||||
|
||||
return true
|
||||
|
@ -101,11 +102,13 @@ func (sl *Sapling) CacheKey() (string, bool) {
|
|||
}
|
||||
|
||||
func (sl *Sapling) setDir(dir string) {
|
||||
dir = runtime.ReplaceHomeDirPrefixWithTilde(sl.env, dir) // align with template PWD
|
||||
dir = path.ReplaceHomeDirPrefixWithTilde(dir) // align with template PWD
|
||||
|
||||
if sl.env.GOOS() == runtime.WINDOWS {
|
||||
sl.Dir = strings.TrimSuffix(dir, `\.sl`)
|
||||
return
|
||||
}
|
||||
|
||||
sl.Dir = strings.TrimSuffix(dir, "/.sl")
|
||||
}
|
||||
|
||||
|
|
|
@ -18,25 +18,13 @@ func TestSetDir(t *testing.T) {
|
|||
GOOS string
|
||||
}{
|
||||
{
|
||||
Case: "In home folder",
|
||||
Expected: "~/sapling",
|
||||
Path: "/usr/home/sapling/.sl",
|
||||
GOOS: runtime.LINUX,
|
||||
},
|
||||
{
|
||||
Case: "Outside home folder",
|
||||
Case: "Linux",
|
||||
Expected: "/usr/sapling/repo",
|
||||
Path: "/usr/sapling/repo/.sl",
|
||||
GOOS: runtime.LINUX,
|
||||
},
|
||||
{
|
||||
Case: "Windows home folder",
|
||||
Expected: "~\\sapling",
|
||||
Path: "\\usr\\home\\sapling\\.sl",
|
||||
GOOS: runtime.WINDOWS,
|
||||
},
|
||||
{
|
||||
Case: "Windows outside home folder",
|
||||
Case: "Windows",
|
||||
Expected: "\\usr\\sapling\\repo",
|
||||
Path: "\\usr\\sapling\\repo\\.sl",
|
||||
GOOS: runtime.WINDOWS,
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -127,12 +128,6 @@ func TestSessionSegmentTemplate(t *testing.T) {
|
|||
env.On("Getenv", "SSH_CLIENT").Return(SSHSession)
|
||||
env.On("Getenv", "POSH_SESSION_DEFAULT_USER").Return(tc.DefaultUserName)
|
||||
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
UserName: tc.UserName,
|
||||
HostName: tc.ComputerName,
|
||||
Root: tc.Root,
|
||||
})
|
||||
|
||||
env.On("Platform").Return(tc.Platform)
|
||||
|
||||
var whoAmIErr error
|
||||
|
@ -145,6 +140,12 @@ func TestSessionSegmentTemplate(t *testing.T) {
|
|||
session := &Session{}
|
||||
session.Init(properties.Map{}, env)
|
||||
|
||||
template.Cache = &cache.Template{
|
||||
UserName: tc.UserName,
|
||||
HostName: tc.ComputerName,
|
||||
Root: tc.Root,
|
||||
}
|
||||
|
||||
_ = session.Enabled()
|
||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, session), tc.Case)
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ import (
|
|||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestStatusWriterEnabled(t *testing.T) {
|
||||
|
@ -27,18 +27,18 @@ func TestStatusWriterEnabled(t *testing.T) {
|
|||
for _, tc := range cases {
|
||||
env := new(mock.Environment)
|
||||
env.On("StatusCodes").Return(tc.Status, "")
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
Code: 133,
|
||||
})
|
||||
env.On("Error", testify_.Anything).Return(nil)
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("Flags").Return(&runtime.Flags{})
|
||||
env.On("Shell").Return(shell.GENERIC)
|
||||
|
||||
props := properties.Map{}
|
||||
if len(tc.Template) > 0 {
|
||||
props[StatusTemplate] = tc.Template
|
||||
}
|
||||
|
||||
template.Cache = &cache.Template{
|
||||
Code: 133,
|
||||
}
|
||||
template.Init(env, nil)
|
||||
|
||||
s := &Status{}
|
||||
s.Init(props, env)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -29,19 +30,20 @@ func TestTextSegment(t *testing.T) {
|
|||
for _, tc := range cases {
|
||||
env := new(mock.Environment)
|
||||
env.On("PathSeparator").Return("/")
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
UserName: "Posh",
|
||||
HostName: "MyHost",
|
||||
Shell: "terminal",
|
||||
Root: true,
|
||||
Folder: "posh",
|
||||
})
|
||||
env.On("Getenv", "HELLO").Return("hello")
|
||||
env.On("Getenv", "WORLD").Return("")
|
||||
|
||||
txt := &Text{}
|
||||
txt.Init(properties.Map{}, env)
|
||||
|
||||
template.Cache = &cache.Template{
|
||||
UserName: "Posh",
|
||||
HostName: "MyHost",
|
||||
Shell: "terminal",
|
||||
Root: true,
|
||||
Folder: "posh",
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, txt), tc.Case)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -93,10 +92,10 @@ func TestUI5Tooling(t *testing.T) {
|
|||
tc.Template = ui5tooling.Template()
|
||||
}
|
||||
|
||||
// this is needed to build the version URL as before renderTemplate, the template is not initialized
|
||||
env.On("Shell").Return("foo")
|
||||
env.On("TemplateCache").Return(&cache.Template{})
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
template.Init(env)
|
||||
template.Cache = &cache.Template{}
|
||||
template.Init(env, nil)
|
||||
|
||||
failMsg := fmt.Sprintf("Failed in case: %s", tc.Case)
|
||||
assert.True(t, ui5tooling.Enabled(), failMsg)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -22,7 +23,7 @@ func getExecutablePath(env runtime.Environment) (string, error) {
|
|||
}
|
||||
|
||||
if env.Flags().Strict {
|
||||
return runtime.Base(env, executable), nil
|
||||
return path.Base(executable), nil
|
||||
}
|
||||
|
||||
// On Windows, it fails when the excutable is called in MSYS2 for example
|
||||
|
|
112
src/template/cache.go
Normal file
112
src/template/cache.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
package template
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/maps"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||
)
|
||||
|
||||
var (
|
||||
Cache *cache.Template
|
||||
)
|
||||
|
||||
func loadCache(vars maps.Simple) {
|
||||
if !env.Flags().IsPrimary {
|
||||
// Load the template cache for a non-primary prompt before rendering any templates.
|
||||
if OK := restoreCache(env); OK {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Cache = new(cache.Template)
|
||||
|
||||
Cache.Root = env.Root()
|
||||
Cache.Shell = env.Shell()
|
||||
Cache.ShellVersion = env.Flags().ShellVersion
|
||||
Cache.Code, _ = env.StatusCodes()
|
||||
Cache.WSL = env.IsWsl()
|
||||
Cache.Segments = maps.NewConcurrent()
|
||||
Cache.PromptCount = env.Flags().PromptCount
|
||||
Cache.Var = make(map[string]any)
|
||||
Cache.Jobs = env.Flags().JobCount
|
||||
|
||||
if vars != nil {
|
||||
Cache.Var = vars
|
||||
}
|
||||
|
||||
pwd := env.Pwd()
|
||||
Cache.PWD = path.ReplaceHomeDirPrefixWithTilde(pwd)
|
||||
|
||||
Cache.AbsolutePWD = pwd
|
||||
if env.IsWsl() {
|
||||
Cache.AbsolutePWD, _ = env.RunCommand("wslpath", "-m", pwd)
|
||||
}
|
||||
|
||||
env.Flags().AbsolutePWD = Cache.AbsolutePWD
|
||||
Cache.PSWD = env.Flags().PSWD
|
||||
|
||||
Cache.Folder = path.Base(pwd)
|
||||
if env.GOOS() == runtime.WINDOWS && strings.HasSuffix(Cache.Folder, ":") {
|
||||
Cache.Folder += `\`
|
||||
}
|
||||
|
||||
Cache.UserName = env.User()
|
||||
if host, err := env.Host(); err == nil {
|
||||
Cache.HostName = host
|
||||
}
|
||||
|
||||
goos := env.GOOS()
|
||||
Cache.OS = goos
|
||||
if goos == runtime.LINUX {
|
||||
Cache.OS = env.Platform()
|
||||
}
|
||||
|
||||
val := env.Getenv("SHLVL")
|
||||
if shlvl, err := strconv.Atoi(val); err == nil {
|
||||
Cache.SHLVL = shlvl
|
||||
}
|
||||
}
|
||||
|
||||
func restoreCache(env runtime.Environment) bool {
|
||||
defer log.Trace(time.Now())
|
||||
|
||||
val, OK := env.Session().Get(cache.TEMPLATECACHE)
|
||||
if !OK {
|
||||
return false
|
||||
}
|
||||
|
||||
var tmplCache cache.Template
|
||||
err := json.Unmarshal([]byte(val), &tmplCache)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
Cache = &tmplCache
|
||||
Cache.Segments = Cache.SegmentsCache.ToConcurrent()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func SaveCache() {
|
||||
// only store this when in a primary prompt
|
||||
// and when we have any extra prompt in the config
|
||||
canSave := env.Flags().IsPrimary && env.Flags().HasExtra
|
||||
if !canSave {
|
||||
return
|
||||
}
|
||||
|
||||
Cache.SegmentsCache = Cache.Segments.ToSimple()
|
||||
|
||||
templateCache, err := json.Marshal(Cache)
|
||||
if err == nil {
|
||||
env.Session().Set(cache.TEMPLATECACHE, string(templateCache), cache.ONEDAY)
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestGlob(t *testing.T) {
|
||||
|
@ -23,12 +22,10 @@ func TestGlob(t *testing.T) {
|
|||
}
|
||||
|
||||
env := &mock.Environment{}
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("TemplateCache").Return(&cache.Template{})
|
||||
env.On("Shell").Return("foo")
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
|
||||
Init(env)
|
||||
Cache = new(cache.Template)
|
||||
Init(env, nil)
|
||||
|
||||
for _, tc := range cases {
|
||||
tmpl := &Text{
|
||||
|
|
|
@ -3,6 +3,7 @@ package template
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/maps"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
)
|
||||
|
||||
|
@ -23,7 +24,7 @@ var (
|
|||
knownVariables []string
|
||||
)
|
||||
|
||||
func Init(environment runtime.Environment) {
|
||||
func Init(environment runtime.Environment, vars maps.Simple) {
|
||||
env = environment
|
||||
shell = env.Shell()
|
||||
|
||||
|
@ -55,4 +56,10 @@ func Init(environment runtime.Environment) {
|
|||
"Data",
|
||||
"Jobs",
|
||||
}
|
||||
|
||||
if Cache != nil {
|
||||
return
|
||||
}
|
||||
|
||||
loadCache(vars)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestUrl(t *testing.T) {
|
||||
|
@ -22,14 +21,11 @@ func TestUrl(t *testing.T) {
|
|||
}
|
||||
|
||||
env := &mock.Environment{}
|
||||
env.On("TemplateCache").Return(&cache.Template{})
|
||||
env.On("Error", testify_.Anything)
|
||||
env.On("Debug", testify_.Anything)
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("Shell").Return("foo")
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
|
||||
Init(env)
|
||||
Cache = new(cache.Template)
|
||||
|
||||
Init(env, nil)
|
||||
|
||||
for _, tc := range cases {
|
||||
tmpl := &Text{
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"text/template"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
)
|
||||
|
||||
type Data any
|
||||
|
@ -21,7 +22,7 @@ type context struct {
|
|||
func (c *context) init(t *Text) {
|
||||
c.Data = t.Context
|
||||
c.Getenv = env.Getenv
|
||||
c.Template = *env.TemplateCache()
|
||||
c.Template = *Cache
|
||||
}
|
||||
|
||||
var renderPool sync.Pool
|
||||
|
@ -49,7 +50,7 @@ func (t *renderer) release() {
|
|||
func (t *renderer) execute(text *Text) (string, error) {
|
||||
tmpl, err := t.template.Parse(text.Template)
|
||||
if err != nil {
|
||||
env.Error(err)
|
||||
log.Error(err)
|
||||
return "", errors.New(InvalidTemplate)
|
||||
}
|
||||
|
||||
|
@ -57,7 +58,7 @@ func (t *renderer) execute(text *Text) (string, error) {
|
|||
|
||||
err = tmpl.Execute(&t.buffer, t.context)
|
||||
if err != nil {
|
||||
env.Error(err)
|
||||
log.Error(err)
|
||||
return "", errors.New(IncorrectTemplate)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ type Text struct {
|
|||
}
|
||||
|
||||
func (t *Text) Render() (string, error) {
|
||||
defer env.Trace(time.Now(), t.Template)
|
||||
defer log.Trace(time.Now(), t.Template)
|
||||
|
||||
if !strings.Contains(t.Template, "{{") || !strings.Contains(t.Template, "}}") {
|
||||
return t.Template, nil
|
||||
|
|
|
@ -5,11 +5,9 @@ import (
|
|||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/maps"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
testify_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestRenderTemplate(t *testing.T) {
|
||||
|
@ -238,20 +236,16 @@ func TestRenderTemplateEnvVar(t *testing.T) {
|
|||
}
|
||||
for _, tc := range cases {
|
||||
env := &mock.Environment{}
|
||||
env.On("Error", testify_.Anything)
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("Flags").Return(&runtime.Flags{})
|
||||
env.On("Shell").Return("foo")
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
OS: "darwin",
|
||||
})
|
||||
|
||||
for k, v := range tc.Env {
|
||||
env.On("Getenv", k).Return(v)
|
||||
}
|
||||
|
||||
Init(env)
|
||||
Cache = &cache.Template{
|
||||
OS: "darwin",
|
||||
}
|
||||
Init(env, nil)
|
||||
|
||||
tmpl := &Text{
|
||||
Template: tc.Template,
|
||||
|
@ -344,7 +338,7 @@ func TestPatchTemplate(t *testing.T) {
|
|||
env := &mock.Environment{}
|
||||
env.On("Shell").Return("foo")
|
||||
|
||||
Init(env)
|
||||
Init(env, nil)
|
||||
|
||||
for _, tc := range cases {
|
||||
tmpl := &Text{
|
||||
|
@ -370,14 +364,12 @@ func TestSegmentContains(t *testing.T) {
|
|||
env := &mock.Environment{}
|
||||
segments := maps.NewConcurrent()
|
||||
segments.Set("Git", "foo")
|
||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
||||
env.On("TemplateCache").Return(&cache.Template{
|
||||
Segments: segments,
|
||||
})
|
||||
env.On("Shell").Return("foo")
|
||||
env.On("Trace", testify_.Anything, testify_.Anything).Return(nil)
|
||||
|
||||
Init(env)
|
||||
Cache = &cache.Template{
|
||||
Segments: segments,
|
||||
}
|
||||
Init(env, nil)
|
||||
|
||||
for _, tc := range cases {
|
||||
tmpl := &Text{
|
||||
|
|
Loading…
Reference in a new issue