From 4a1aa2a7b43645b4e5bd4dc3f61c22ce3a75d514 Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Wed, 24 Jul 2024 13:16:03 +0200 Subject: [PATCH] refactor(init): enable features automatically --- src/cache/template.go | 1 + src/cli/init.go | 26 +---- src/cli/print.go | 3 + src/config/config.go | 55 +++++++++ src/config/load.go | 4 +- src/prompt/extra.go | 1 + src/runtime/os.go | 11 +- src/segments/az.go | 14 +-- src/segments/az_test.go | 12 +- src/shell/bash.go | 78 +++++++++++++ src/shell/bash_test.go | 19 ++++ src/shell/cmd.go | 38 +++++++ src/shell/cmd_test.go | 20 ++++ src/shell/code.go | 29 +++++ src/shell/elvish.go | 21 ++++ src/shell/elvish_test.go | 17 +++ src/shell/features.go | 55 +++++++++ src/shell/fish.go | 61 ++++++++++ src/shell/fish_test.go | 21 ++++ src/shell/init.go | 220 ++---------------------------------- src/shell/nu.go | 52 +++++++++ src/shell/nu_test.go | 19 ++++ src/shell/pwsh.go | 42 +++++++ src/shell/pwsh_test.go | 26 +++++ src/shell/scripts/omp.bash | 28 +++-- src/shell/scripts/omp.elv | 13 +-- src/shell/scripts/omp.fish | 53 +++++---- src/shell/scripts/omp.lua | 24 ++-- src/shell/scripts/omp.nu | 22 +--- src/shell/scripts/omp.ps1 | 224 +++++++++++++++++-------------------- src/shell/scripts/omp.py | 13 +-- src/shell/scripts/omp.tcsh | 13 +-- src/shell/scripts/omp.zsh | 38 +++---- src/shell/tcsh.go | 21 ++++ src/shell/tcsh_test.go | 17 +++ src/shell/xonsh.go | 21 ++++ src/shell/xonsh_test.go | 17 +++ src/shell/zsh.go | 29 +++++ src/shell/zsh_test.go | 21 ++++ src/template/text.go | 1 + 40 files changed, 921 insertions(+), 479 deletions(-) create mode 100644 src/shell/bash.go create mode 100644 src/shell/bash_test.go create mode 100644 src/shell/cmd.go create mode 100644 src/shell/cmd_test.go create mode 100644 src/shell/code.go create mode 100644 src/shell/elvish.go create mode 100644 src/shell/elvish_test.go create mode 100644 src/shell/features.go create mode 100644 src/shell/fish.go create mode 100644 src/shell/fish_test.go create mode 100644 src/shell/nu.go create mode 100644 src/shell/nu_test.go create mode 100644 src/shell/pwsh.go create mode 100644 src/shell/pwsh_test.go create mode 100644 src/shell/tcsh.go create mode 100644 src/shell/tcsh_test.go create mode 100644 src/shell/xonsh.go create mode 100644 src/shell/xonsh_test.go create mode 100644 src/shell/zsh.go create mode 100644 src/shell/zsh_test.go diff --git a/src/cache/template.go b/src/cache/template.go index 7efdff15..a7401fd0 100644 --- a/src/cache/template.go +++ b/src/cache/template.go @@ -22,6 +22,7 @@ type Template struct { WSL bool PromptCount int SHLVL int + Jobs int Segments *maps.Concurrent SegmentsCache maps.Simple diff --git a/src/cli/init.go b/src/cli/init.go index f7411d45..30091533 100644 --- a/src/cli/init.go +++ b/src/cli/init.go @@ -6,7 +6,6 @@ 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/jandedobbeleer/oh-my-posh/src/terminal" "github.com/jandedobbeleer/oh-my-posh/src/upgrade" "github.com/spf13/cobra" @@ -68,35 +67,20 @@ func runInit(shellName string) { cfg := config.Load(env) - shell.Transient = cfg.TransientPrompt != nil - shell.ErrorLine = cfg.ErrorLine != nil || cfg.ValidLine != nil - shell.Tooltips = len(cfg.Tooltips) > 0 - shell.ShellIntegration = cfg.ShellIntegration - shell.PromptMark = shellName == shell.FISH && cfg.ITermFeatures != nil && cfg.ITermFeatures.Contains(terminal.PromptMark) - shell.AutoUpgrade = cfg.AutoUpgrade - - for i, block := range cfg.Blocks { - // only fetch cursor position when relevant - if cfg.EnableCursorPositioning && (i == 0 && block.Newline) { - shell.CursorPositioning = true - } - - if block.Type == config.RPrompt { - shell.RPrompt = true - } - } - + // TODO: this can be removed I think // allow overriding the upgrade notice from the config if cfg.DisableNotice || cfg.AutoUpgrade { env.Cache().Set(upgrade.CACHEKEY, "disabled", -1) } + feats := cfg.Features() + if printOutput { - init := shell.PrintInit(env) + init := shell.PrintInit(env, feats) fmt.Print(init) return } - init := shell.Init(env) + init := shell.Init(env, feats) fmt.Print(init) } diff --git a/src/cli/print.go b/src/cli/print.go index b15ecd25..4eb31c4a 100644 --- a/src/cli/print.go +++ b/src/cli/print.go @@ -20,6 +20,7 @@ var ( eval bool cleared bool cached bool + jobCount int command string shellVersion string @@ -68,6 +69,7 @@ var printCmd = &cobra.Command{ Cached: cached, NoExitCode: noStatus, Column: column, + JobCount: jobCount, } eng := prompt.New(flags) @@ -112,6 +114,7 @@ func init() { printCmd.Flags().BoolVar(&cleared, "cleared", false, "do we have a clear terminal or not") printCmd.Flags().BoolVar(&eval, "eval", false, "output the prompt for eval") printCmd.Flags().IntVar(&column, "column", 0, "the column position of the cursor") + printCmd.Flags().IntVar(&jobCount, "job-count", 0, "number of background jobs") // Deprecated flags, keep to not break CLI integration printCmd.Flags().IntVarP(&status, "error", "e", 0, "last exit code") diff --git a/src/config/config.go b/src/config/config.go index 48fa5bf4..ceee9e6e 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -3,6 +3,8 @@ package config import ( "github.com/jandedobbeleer/oh-my-posh/src/color" "github.com/jandedobbeleer/oh-my-posh/src/runtime" + "github.com/jandedobbeleer/oh-my-posh/src/segments" + "github.com/jandedobbeleer/oh-my-posh/src/shell" "github.com/jandedobbeleer/oh-my-posh/src/template" "github.com/jandedobbeleer/oh-my-posh/src/terminal" ) @@ -74,3 +76,56 @@ func (cfg *Config) getPalette() color.Palette { } return cfg.Palette } + +func (cfg *Config) Features() shell.Features { + var feats shell.Features + + if cfg.TransientPrompt != nil { + feats = append(feats, shell.Transient) + } + + if cfg.ShellIntegration { + feats = append(feats, shell.FTCSMarks) + } + + if !cfg.AutoUpgrade && !cfg.DisableNotice { + feats = append(feats, shell.Notice) + } + + if cfg.AutoUpgrade { + feats = append(feats, shell.Upgrade) + } + + if cfg.ErrorLine != nil || cfg.ValidLine != nil { + feats = append(feats, shell.LineError) + } + + if len(cfg.Tooltips) > 0 { + feats = append(feats, shell.Tooltips) + } + + if cfg.env.Shell() == shell.FISH && cfg.ITermFeatures != nil && cfg.ITermFeatures.Contains(terminal.PromptMark) { + feats = append(feats, shell.PromptMark) + } + + for i, block := range cfg.Blocks { + if (i == 0 && block.Newline) && cfg.EnableCursorPositioning { + feats = append(feats, shell.CursorPositioning) + } + + if block.Type == RPrompt { + feats = append(feats, shell.RPrompt) + } + + for _, segment := range block.Segments { + if segment.Type == AZ { + source := segment.Properties.GetString(segments.Source, segments.FirstMatch) + if source == segments.Pwsh || source == segments.FirstMatch { + feats = append(feats, shell.Azure) + } + } + } + } + + return feats +} diff --git a/src/config/load.go b/src/config/load.go index 09ec9e88..fd752486 100644 --- a/src/config/load.go +++ b/src/config/load.go @@ -63,7 +63,7 @@ func loadConfig(env runtime.Environment) *Config { data, err := stdOS.ReadFile(configFile) if err != nil { - env.DebugF("error reading config file: %s", err) + env.Error(err) return Default(env, true) } @@ -87,7 +87,7 @@ func loadConfig(env runtime.Environment) *Config { } if err != nil { - env.DebugF("error decoding config file: %s", err) + env.Error(err) return Default(env, true) } diff --git a/src/prompt/extra.go b/src/prompt/extra.go index 7cef799b..7b8f6c67 100644 --- a/src/prompt/extra.go +++ b/src/prompt/extra.go @@ -25,6 +25,7 @@ func (e *Engine) ExtraPrompt(promptType ExtraPromptType) string { // populate env with latest context e.Env.LoadTemplateCache() var prompt *config.Segment + switch promptType { case Debug: prompt = e.Config.DebugPrompt diff --git a/src/runtime/os.go b/src/runtime/os.go index 213779f7..5dd46e9d 100644 --- a/src/runtime/os.go +++ b/src/runtime/os.go @@ -63,6 +63,7 @@ type Flags struct { Cached bool NoExitCode bool Column int + JobCount int } type CommandError struct { @@ -276,11 +277,14 @@ func (term *Terminal) resolveConfigPath() { configFile = filepath.Join(term.Home(), configFile) } - if !filepath.IsAbs(configFile) { - configFile = filepath.Join(term.Pwd(), configFile) + abs, err := filepath.Abs(configFile) + if err != nil { + term.Error(err) + term.CmdFlags.Config = filepath.Clean(configFile) + return } - term.CmdFlags.Config = filepath.Clean(configFile) + term.CmdFlags.Config = abs } func (term *Terminal) Trace(start time.Time, args ...string) { @@ -782,6 +786,7 @@ func (term *Terminal) TemplateCache() *cache.Template { tmplCache.PromptCount = term.CmdFlags.PromptCount tmplCache.Env = make(map[string]string) tmplCache.Var = make(map[string]any) + tmplCache.Jobs = term.CmdFlags.JobCount if term.Var != nil { tmplCache.Var = term.Var diff --git a/src/segments/az.go b/src/segments/az.go index 66c774ed..fde2480d 100644 --- a/src/segments/az.go +++ b/src/segments/az.go @@ -21,9 +21,9 @@ type Az struct { const ( Source properties.Property = "source" - pwsh = "pwsh" - cli = "cli" - firstMatch = "first_match" + Pwsh = "pwsh" + Cli = "cli" + FirstMatch = "first_match" azureEnv = "POSH_AZURE_SUBSCRIPTION" ) @@ -82,13 +82,13 @@ func (a *Az) Init(props properties.Properties, env runtime.Environment) { } func (a *Az) Enabled() bool { - source := a.props.GetString(Source, firstMatch) + source := a.props.GetString(Source, FirstMatch) switch source { - case firstMatch: + case FirstMatch: return a.getCLISubscription() || a.getModuleSubscription() - case pwsh: + case Pwsh: return a.getModuleSubscription() - case cli: + case Cli: return a.getCLISubscription() } return false diff --git a/src/segments/az_test.go b/src/segments/az_test.go index feb168f1..05a45c0e 100644 --- a/src/segments/az_test.go +++ b/src/segments/az_test.go @@ -74,14 +74,14 @@ func TestAzSegment(t *testing.T) { ExpectedString: "AzureCliCloud", Template: "{{ .EnvironmentName }}", HasCLI: true, - Source: cli, + Source: Cli, }, { Case: "Az CLI Profile only - disabled", ExpectedEnabled: false, Template: "{{ .EnvironmentName }}", HasCLI: false, - Source: cli, + Source: Cli, }, { Case: "PowerShell Profile only", @@ -89,13 +89,13 @@ func TestAzSegment(t *testing.T) { ExpectedString: "AzurePoshCloud", Template: "{{ .EnvironmentName }}", HasPowerShell: true, - Source: pwsh, + Source: Pwsh, }, { Case: "Az CLI Profile only - disabled", ExpectedEnabled: false, Template: "{{ .EnvironmentName }}", - Source: pwsh, + Source: Pwsh, }, { Case: "Az CLI account type", @@ -103,7 +103,7 @@ func TestAzSegment(t *testing.T) { ExpectedString: "user", Template: "{{ .User.Type }}", HasCLI: true, - Source: cli, + Source: Cli, }, } @@ -136,7 +136,7 @@ func TestAzSegment(t *testing.T) { } if tc.Source == "" { - tc.Source = firstMatch + tc.Source = FirstMatch } az := &Az{ diff --git a/src/shell/bash.go b/src/shell/bash.go new file mode 100644 index 00000000..d4bd44f6 --- /dev/null +++ b/src/shell/bash.go @@ -0,0 +1,78 @@ +package shell + +import ( + _ "embed" + + "fmt" + "strings" +) + +//go:embed scripts/omp.bash +var bashInit string + +const ( + unixUpgrade = "$_omp_executable upgrade" + unixNotice = "$_omp_executable notice" +) + +func (f Feature) Bash() Code { + switch f { + case CursorPositioning: + return "_omp_cursor_positioning=1" + case FTCSMarks: + return "_omp_ftcs_marks=1" + case Upgrade: + return unixUpgrade + case Notice: + return unixNotice + case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, Transient: + fallthrough + default: + return "" + } +} + +func quotePosixStr(str string) string { + if len(str) == 0 { + return "''" + } + + needQuoting := false + var b strings.Builder + for _, r := range str { + normal := false + switch r { + case '!', ';', '"', '(', ')', '[', ']', '{', '}', '$', '|', '&', '>', '<', '`', ' ', '#', '~', '*', '?', '=': + b.WriteRune(r) + case '\\', '\'': + b.WriteByte('\\') + b.WriteRune(r) + case '\a': + b.WriteString(`\a`) + case '\b': + b.WriteString(`\b`) + case '\f': + b.WriteString(`\f`) + case '\n': + b.WriteString(`\n`) + case '\r': + b.WriteString(`\r`) + case '\t': + b.WriteString(`\t`) + case '\v': + b.WriteString(`\v`) + default: + b.WriteRune(r) + normal = true + } + if !normal { + needQuoting = true + } + } + // the quoting form $'...' is used for a string contains any special characters + if needQuoting { + return fmt.Sprintf("$'%s'", b.String()) + } + + return b.String() +} diff --git a/src/shell/bash_test.go b/src/shell/bash_test.go new file mode 100644 index 00000000..913f476c --- /dev/null +++ b/src/shell/bash_test.go @@ -0,0 +1,19 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBashFeatures(t *testing.T) { + got := allFeatures.Lines(BASH).String("// these are the features") + + want := `// these are the features +_omp_ftcs_marks=1 +$_omp_executable upgrade +$_omp_executable notice +_omp_cursor_positioning=1` + + assert.Equal(t, want, got) +} diff --git a/src/shell/cmd.go b/src/shell/cmd.go new file mode 100644 index 00000000..e4dd5ed9 --- /dev/null +++ b/src/shell/cmd.go @@ -0,0 +1,38 @@ +package shell + +import ( + _ "embed" + + "fmt" + "strings" +) + +//go:embed scripts/omp.lua +var cmdInit string + +func (f Feature) Cmd() Code { + switch f { + case Transient: + return "transient_enabled = true" + case RPrompt: + return "rprompt_enabled = true" + case Tooltips: + return "enable_tooltips()" + case Upgrade: + return "os.execute(string.format('%s upgrade', omp_exe()))" + case Notice: + return "os.execute(string.format('%s notice', omp_exe()))" + case PromptMark, PoshGit, Azure, LineError, Jobs, FTCSMarks, CursorPositioning: + fallthrough + default: + return "" + } +} + +func quoteLuaStr(str string) string { + if len(str) == 0 { + return "''" + } + + return fmt.Sprintf("'%s'", strings.NewReplacer(`\`, `\\`, `'`, `\'`).Replace(str)) +} diff --git a/src/shell/cmd_test.go b/src/shell/cmd_test.go new file mode 100644 index 00000000..7a267467 --- /dev/null +++ b/src/shell/cmd_test.go @@ -0,0 +1,20 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCmdFeatures(t *testing.T) { + got := allFeatures.Lines(CMD).String("// these are the features") + + want := `// these are the features +enable_tooltips() +transient_enabled = true +os.execute(string.format('%s upgrade', omp_exe())) +os.execute(string.format('%s notice', omp_exe())) +rprompt_enabled = true` + + assert.Equal(t, want, got) +} diff --git a/src/shell/code.go b/src/shell/code.go new file mode 100644 index 00000000..2dd5c2f8 --- /dev/null +++ b/src/shell/code.go @@ -0,0 +1,29 @@ +package shell + +import "strings" + +type Code string + +func (c Code) Indent(spaces int) Code { + return Code(strings.Repeat(" ", spaces) + string(c)) +} + +type Lines []Code + +func (l Lines) String(script string) string { + var builder strings.Builder + + builder.WriteString(script) + builder.WriteString("\n") + + for i, line := range l { + builder.WriteString(string(line)) + + // add newline if not last line + if i < len(l)-1 { + builder.WriteString("\n") + } + } + + return builder.String() +} diff --git a/src/shell/elvish.go b/src/shell/elvish.go new file mode 100644 index 00000000..9a7b2198 --- /dev/null +++ b/src/shell/elvish.go @@ -0,0 +1,21 @@ +package shell + +import ( + _ "embed" +) + +//go:embed scripts/omp.elv +var elvishInit string + +func (f Feature) Elvish() Code { + switch f { + case Upgrade: + return unixUpgrade + case Notice: + return unixNotice + case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, CursorPositioning, Tooltips, Transient, FTCSMarks: + fallthrough + default: + return "" + } +} diff --git a/src/shell/elvish_test.go b/src/shell/elvish_test.go new file mode 100644 index 00000000..187d77bd --- /dev/null +++ b/src/shell/elvish_test.go @@ -0,0 +1,17 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestElvishFeatures(t *testing.T) { + got := allFeatures.Lines(ELVISH).String("// these are the features") + + want := `// these are the features +$_omp_executable upgrade +$_omp_executable notice` + + assert.Equal(t, want, got) +} diff --git a/src/shell/features.go b/src/shell/features.go new file mode 100644 index 00000000..fdb33400 --- /dev/null +++ b/src/shell/features.go @@ -0,0 +1,55 @@ +package shell + +type Feature byte + +const ( + Jobs Feature = iota + Azure + PoshGit + LineError + Tooltips + Transient + FTCSMarks + Upgrade + Notice + PromptMark + RPrompt + CursorPositioning +) + +type Features []Feature + +func (f Features) Lines(shell string) Lines { + var lines Lines + + for _, feature := range f { + var code Code + + switch shell { + case PWSH, PWSH5: + code = feature.Pwsh() + case ZSH: + code = feature.Zsh() + case BASH: + code = feature.Bash() + case ELVISH: + code = feature.Elvish() + case TCSH: + code = feature.Tcsh() + case FISH: + code = feature.Fish() + case CMD: + code = feature.Cmd() + case NU: + code = feature.Nu() + case XONSH: + code = feature.Xonsh() + } + + if len(code) > 0 { + lines = append(lines, code) + } + } + + return lines +} diff --git a/src/shell/fish.go b/src/shell/fish.go new file mode 100644 index 00000000..4c8e642d --- /dev/null +++ b/src/shell/fish.go @@ -0,0 +1,61 @@ +package shell + +import ( + _ "embed" + + "fmt" + "strings" +) + +//go:embed scripts/omp.fish +var fishInit string + +func (f Feature) Fish() Code { + switch f { + case Transient: + return "set --global _omp_transient_prompt 1" + case FTCSMarks: + return "set --global _omp_ftcs_marks 1" + case PromptMark: + return "set --global _omp_prompt_mark 1" + case Tooltips: + return "enable_poshtooltips" + case Upgrade: + return unixUpgrade + case Notice: + return unixNotice + case RPrompt, PoshGit, Azure, LineError, Jobs, CursorPositioning: + fallthrough + default: + return "" + } +} + +func quoteFishStr(str string) string { + if len(str) == 0 { + return "''" + } + needQuoting := false + var b strings.Builder + for _, r := range str { + normal := false + switch r { + case ';', '"', '(', ')', '[', ']', '{', '}', '$', '|', '&', '>', '<', ' ', '#', '~', '*', '?', '=': + b.WriteRune(r) + case '\\', '\'': + b.WriteByte('\\') + b.WriteRune(r) + default: + b.WriteRune(r) + normal = true + } + if !normal { + needQuoting = true + } + } + // single quotes are used when the string contains any special characters + if needQuoting { + return fmt.Sprintf("'%s'", b.String()) + } + return b.String() +} diff --git a/src/shell/fish_test.go b/src/shell/fish_test.go new file mode 100644 index 00000000..fcadce44 --- /dev/null +++ b/src/shell/fish_test.go @@ -0,0 +1,21 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFishFeatures(t *testing.T) { + got := allFeatures.Lines(FISH).String("// these are the features") + + want := `// these are the features +enable_poshtooltips +set --global _omp_transient_prompt 1 +set --global _omp_ftcs_marks 1 +$_omp_executable upgrade +$_omp_executable notice +set --global _omp_prompt_mark 1` + + assert.Equal(t, want, got) +} diff --git a/src/shell/init.go b/src/shell/init.go index 01e96af8..a0a01869 100644 --- a/src/shell/init.go +++ b/src/shell/init.go @@ -1,171 +1,38 @@ package shell import ( - _ "embed" - "path/filepath" - "strconv" - "fmt" "os" "strings" - "github.com/jandedobbeleer/oh-my-posh/src/color" "github.com/jandedobbeleer/oh-my-posh/src/runtime" - "github.com/jandedobbeleer/oh-my-posh/src/template" - "github.com/jandedobbeleer/oh-my-posh/src/upgrade" ) -//go:embed scripts/omp.ps1 -var pwshInit string - -//go:embed scripts/omp.fish -var fishInit string - -//go:embed scripts/omp.bash -var bashInit string - -//go:embed scripts/omp.zsh -var zshInit string - -//go:embed scripts/omp.lua -var cmdInit string - -//go:embed scripts/omp.nu -var nuInit string - -//go:embed scripts/omp.tcsh -var tcshInit string - -//go:embed scripts/omp.elv -var elvishInit string - -//go:embed scripts/omp.py -var xonshInit string - const ( noExe = "echo \"Unable to find Oh My Posh executable\"" ) -var ( - Transient bool - ErrorLine bool - Tooltips bool - ShellIntegration bool - RPrompt bool - CursorPositioning bool - PromptMark bool - AutoUpgrade bool -) - func getExecutablePath(env runtime.Environment) (string, error) { executable, err := os.Executable() if err != nil { return "", err } + if env.Flags().Strict { return runtime.Base(env, executable), nil } + // On Windows, it fails when the excutable is called in MSYS2 for example // which uses unix style paths to resolve the executable's location. // PowerShell knows how to resolve both, so we can swap this without any issue. if env.GOOS() == runtime.WINDOWS { executable = strings.ReplaceAll(executable, "\\", "/") } + return executable, nil } -func quotePwshStr(str string) string { - return fmt.Sprintf("'%s'", strings.ReplaceAll(str, "'", "''")) -} - -func quotePosixStr(str string) string { - if len(str) == 0 { - return "''" - } - - needQuoting := false - var b strings.Builder - for _, r := range str { - normal := false - switch r { - case '!', ';', '"', '(', ')', '[', ']', '{', '}', '$', '|', '&', '>', '<', '`', ' ', '#', '~', '*', '?', '=': - b.WriteRune(r) - case '\\', '\'': - b.WriteByte('\\') - b.WriteRune(r) - case '\a': - b.WriteString(`\a`) - case '\b': - b.WriteString(`\b`) - case '\f': - b.WriteString(`\f`) - case '\n': - b.WriteString(`\n`) - case '\r': - b.WriteString(`\r`) - case '\t': - b.WriteString(`\t`) - case '\v': - b.WriteString(`\v`) - default: - b.WriteRune(r) - normal = true - } - if !normal { - needQuoting = true - } - } - // the quoting form $'...' is used for a string contains any special characters - if needQuoting { - return fmt.Sprintf("$'%s'", b.String()) - } - return b.String() -} - -func quoteFishStr(str string) string { - if len(str) == 0 { - return "''" - } - needQuoting := false - var b strings.Builder - for _, r := range str { - normal := false - switch r { - case ';', '"', '(', ')', '[', ']', '{', '}', '$', '|', '&', '>', '<', ' ', '#', '~', '*', '?', '=': - b.WriteRune(r) - case '\\', '\'': - b.WriteByte('\\') - b.WriteRune(r) - default: - b.WriteRune(r) - normal = true - } - if !normal { - needQuoting = true - } - } - // single quotes are used when the string contains any special characters - if needQuoting { - return fmt.Sprintf("'%s'", b.String()) - } - return b.String() -} - -func quoteLuaStr(str string) string { - if len(str) == 0 { - return "''" - } - return fmt.Sprintf("'%s'", strings.NewReplacer(`\`, `\\`, `'`, `\'`).Replace(str)) -} - -func quoteNuStr(str string) string { - if len(str) == 0 { - return "''" - } - return fmt.Sprintf(`"%s"`, strings.NewReplacer(`\`, `\\`, `"`, `\"`).Replace(str)) -} - -func Init(env runtime.Environment) string { +func Init(env runtime.Environment, feats Features) string { shell := env.Flags().Shell switch shell { @@ -197,44 +64,25 @@ func Init(env runtime.Environment) string { return fmt.Sprintf(command, executable, shell, config, additionalParams) case ZSH, BASH, FISH, CMD, TCSH, XONSH: - return PrintInit(env) + return PrintInit(env, feats) case NU: - createNuInit(env) + createNuInit(env, feats) return "" default: return fmt.Sprintf("echo \"No initialization script available for %s\"", shell) } } -func PrintInit(env runtime.Environment) string { +func PrintInit(env runtime.Environment, features Features) string { executable, err := getExecutablePath(env) if err != nil { return noExe } - toggleSetting := func(setting bool) string { - if env.Flags().Manual { - return "false" - } - - return strconv.FormatBool(setting) - } - - promptMark := func() string { - if PromptMark { - return "iterm2_prompt_mark" - } - - return "" - } - shell := env.Flags().Shell configFile := env.Flags().Config - var ( - script, notice string - hasNotice bool - ) + var script string switch shell { case PWSH, PWSH5: @@ -273,57 +121,11 @@ func PrintInit(env runtime.Environment) string { return fmt.Sprintf("echo \"No initialization script available for %s\"", shell) } - // only run this for shells that support - // injecting the notice directly - if shell != PWSH && shell != PWSH5 { - notice, hasNotice = upgrade.Notice(env, false) - } - - return strings.NewReplacer( + init := strings.NewReplacer( "::OMP::", executable, "::CONFIG::", configFile, "::SHELL::", shell, - "::TRANSIENT::", toggleSetting(Transient), - "::ERROR_LINE::", toggleSetting(ErrorLine), - "::TOOLTIPS::", toggleSetting(Tooltips), - "::FTCS_MARKS::", toggleSetting(ShellIntegration), - "::RPROMPT::", strconv.FormatBool(RPrompt), - "::CURSOR::", strconv.FormatBool(CursorPositioning), - "::UPGRADE::", strconv.FormatBool(hasNotice), - "::UPGRADENOTICE::", notice, - "::AUTOUPGRADE::", strconv.FormatBool(AutoUpgrade), - "::PROMPT_MARK::", promptMark(), ).Replace(script) -} - -func createNuInit(env runtime.Environment) { - initPath := filepath.Join(env.Home(), ".oh-my-posh.nu") - f, err := os.OpenFile(initPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - return - } - _, err = f.WriteString(PrintInit(env)) - if err != nil { - return - } - _ = f.Close() -} - -func ConsoleBackgroundColor(env runtime.Environment, backgroundColorTemplate color.Ansi) color.Ansi { - if backgroundColorTemplate.IsEmpty() { - return backgroundColorTemplate - } - - tmpl := &template.Text{ - Template: string(backgroundColorTemplate), - Context: nil, - Env: env, - } - - text, err := tmpl.Render() - if err != nil { - return color.Transparent - } - - return color.Ansi(text) + + return features.Lines(shell).String(init) } diff --git a/src/shell/nu.go b/src/shell/nu.go new file mode 100644 index 00000000..32fe54c8 --- /dev/null +++ b/src/shell/nu.go @@ -0,0 +1,52 @@ +package shell + +import ( + _ "embed" + + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/jandedobbeleer/oh-my-posh/src/runtime" +) + +//go:embed scripts/omp.nu +var nuInit string + +func (f Feature) Nu() Code { + switch f { + case Transient: + return `$env.TRANSIENT_PROMPT_COMMAND = { ^$_omp_executable print transient $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)" }` //nolint: lll + case Upgrade: + return "^$_omp_executable upgrade" + case Notice: + return "^$_omp_executable notice" + case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, FTCSMarks, CursorPositioning: + fallthrough + default: + return "" + } +} + +func quoteNuStr(str string) string { + if len(str) == 0 { + return "''" + } + return fmt.Sprintf(`"%s"`, strings.NewReplacer(`\`, `\\`, `"`, `\"`).Replace(str)) +} + +func createNuInit(env runtime.Environment, features Features) { + initPath := filepath.Join(env.Home(), ".oh-my-posh.nu") + f, err := os.OpenFile(initPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + return + } + + _, err = f.WriteString(PrintInit(env, features)) + if err != nil { + return + } + + _ = f.Close() +} diff --git a/src/shell/nu_test.go b/src/shell/nu_test.go new file mode 100644 index 00000000..d4d3b786 --- /dev/null +++ b/src/shell/nu_test.go @@ -0,0 +1,19 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNuFeatures(t *testing.T) { + got := allFeatures.Lines(NU).String("// these are the features") + + //nolint: lll + want := `// these are the features +$env.TRANSIENT_PROMPT_COMMAND = { ^$_omp_executable print transient $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)" } +^$_omp_executable upgrade +^$_omp_executable notice` + + assert.Equal(t, want, got) +} diff --git a/src/shell/pwsh.go b/src/shell/pwsh.go new file mode 100644 index 00000000..6da220c1 --- /dev/null +++ b/src/shell/pwsh.go @@ -0,0 +1,42 @@ +package shell + +import ( + _ "embed" + + "fmt" + "strings" +) + +//go:embed scripts/omp.ps1 +var pwshInit string + +func (f Feature) Pwsh() Code { + switch f { + case Tooltips: + return "Enable-PoshTooltips" + case LineError: + return "Enable-PoshLineError" + case Transient: + return "Enable-PoshTransientPrompt" + case Jobs: + return "$global:_ompJobCount = $true" + case Azure: + return "$global:_ompAzure = $true" + case PoshGit: + return "$global:_ompPoshGit = $true" + case FTCSMarks: + return "$global:_ompFTCSMarks = $true" + case Upgrade: + return "& $global:_ompExecutable upgrade" + case Notice: + return "& $global:_ompExecutable notice" + case PromptMark, RPrompt, CursorPositioning: + fallthrough + default: + return "" + } +} + +func quotePwshStr(str string) string { + return fmt.Sprintf("'%s'", strings.ReplaceAll(str, "'", "''")) +} diff --git a/src/shell/pwsh_test.go b/src/shell/pwsh_test.go new file mode 100644 index 00000000..8b8cc77c --- /dev/null +++ b/src/shell/pwsh_test.go @@ -0,0 +1,26 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var allFeatures = Features{Tooltips, LineError, Transient, Jobs, Azure, PoshGit, FTCSMarks, Upgrade, Notice, PromptMark, RPrompt, CursorPositioning} + +func TestPwshFeatures(t *testing.T) { + got := allFeatures.Lines(PWSH).String("") + + want := ` +Enable-PoshTooltips +Enable-PoshLineError +Enable-PoshTransientPrompt +$global:_ompJobCount = $true +$global:_ompAzure = $true +$global:_ompPoshGit = $true +$global:_ompFTCSMarks = $true +& $global:_ompExecutable upgrade +& $global:_ompExecutable notice` + + assert.Equal(t, want, got) +} diff --git a/src/shell/scripts/omp.bash b/src/shell/scripts/omp.bash index 70bc90b5..13dcee5d 100644 --- a/src/shell/scripts/omp.bash +++ b/src/shell/scripts/omp.bash @@ -4,22 +4,28 @@ export POWERLINE_COMMAND="oh-my-posh" export POSH_PID=$$ export CONDA_PROMPT_MODIFIER=false +# global variables _omp_start_time="" _omp_stack_count=0 _omp_elapsed=-1 _omp_no_exit_code="true" _omp_status_cache=0 _omp_pipestatus_cache=0 +_omp_executable=::OMP:: + +# switches to enable/disable features +_omp_cursor_positioning=0 +_omp_ftcs_marks=0 # start timer on command start PS0='${_omp_start_time:0:$((_omp_start_time="$(_omp_start_timer)",0))}$(_omp_ftcs_command_start)' # set secondary prompt -PS2="$(::OMP:: print secondary --config="$POSH_THEME" --shell=bash --shell-version="$BASH_VERSION")" +PS2="$(${_omp_executable} print secondary --config="$POSH_THEME" --shell=bash --shell-version="$BASH_VERSION")" function _omp_set_cursor_position() { # not supported in Midnight Commander # see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3415 - if [[ "::CURSOR::" != "true" ]] || [[ -v MC_SID ]]; then + if [[ $_omp_cursor_positioning == 0 ]] || [[ -v MC_SID ]]; then return fi @@ -37,11 +43,11 @@ function _omp_set_cursor_position() { } function _omp_start_timer() { - ::OMP:: get millis + $_omp_executable get millis } function _omp_ftcs_command_start() { - if [[ "::FTCS_MARKS::" == "true" ]]; then + if [[ $_omp_ftcs_marks == 0 ]]; then printf "\e]133;C\a" fi } @@ -62,7 +68,7 @@ function _omp_hook() { _omp_stack_count=$((${#DIRSTACK[@]} - 1)) if [[ "$_omp_start_time" ]]; then - local omp_now=$(::OMP:: get millis --shell=bash) + local omp_now=$(${_omp_executable} get millis --shell=bash) _omp_elapsed=$((omp_now - _omp_start_time)) _omp_start_time="" _omp_no_exit_code="false" @@ -75,19 +81,11 @@ function _omp_hook() { set_poshcontext _omp_set_cursor_position - PS1="$(::OMP:: print primary --config="$POSH_THEME" --shell=bash --shell-version="$BASH_VERSION" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --no-status="$_omp_no_exit_code" --terminal-width="${COLUMNS-0}" | tr -d '\0')" + PS1="$(${_omp_executable} print primary --config="$POSH_THEME" --shell=bash --shell-version="$BASH_VERSION" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --no-status="$_omp_no_exit_code" --terminal-width="${COLUMNS-0}" | tr -d '\0')" return $_omp_status_cache } -if [[ "$TERM" != "linux" ]] && [[ -x "$(command -v ::OMP::)" ]] && ! [[ "$PROMPT_COMMAND" =~ "_omp_hook" ]]; then +if [[ "$TERM" != "linux" ]] && [[ -x "$(command -v $_omp_executable)" ]] && ! [[ "$PROMPT_COMMAND" =~ "_omp_hook" ]]; then PROMPT_COMMAND="_omp_hook; $PROMPT_COMMAND" fi - -if [[ "::UPGRADE::" == "true" ]]; then - echo "::UPGRADENOTICE::" -fi - -if [[ "::AUTOUPGRADE::" == "true" ]]; then - ::OMP:: upgrade -fi diff --git a/src/shell/scripts/omp.elv b/src/shell/scripts/omp.elv index daed6292..a9bfbe4b 100644 --- a/src/shell/scripts/omp.elv +++ b/src/shell/scripts/omp.elv @@ -4,6 +4,7 @@ set-env POSH_SHELL_VERSION (elvish --version) set-env POWERLINE_COMMAND 'oh-my-posh' var error-code = 0 +var _omp_executable = ::OMP:: fn posh-after-command-hook {|m| var error = $m[error] @@ -23,18 +24,10 @@ set edit:after-command = [ $@edit:after-command $posh-after-command-hook~ ] set edit:prompt = { var cmd-duration = (printf "%.0f" (* $edit:command-duration 1000)) - ::OMP:: print primary --config=$E:POSH_THEME --shell=elvish --execution-time=$cmd-duration --status=$error-code --pwd=$pwd --shell-version=$E:POSH_SHELL_VERSION + $_omp_executable print primary --config=$E:POSH_THEME --shell=elvish --execution-time=$cmd-duration --status=$error-code --pwd=$pwd --shell-version=$E:POSH_SHELL_VERSION } set edit:rprompt = { var cmd-duration = (printf "%.0f" (* $edit:command-duration 1000)) - ::OMP:: print right --config=$E:POSH_THEME --shell=elvish --execution-time=$cmd-duration --status=$error-code --pwd=$pwd --shell-version=$E:POSH_SHELL_VERSION -} - -if (eq '::UPGRADE::' 'true') { - echo '::UPGRADENOTICE::' -} - -if (eq '::AUTOUPGRADE::' 'true') { - ::OMP:: upgrade + $_omp_executable print right --config=$E:POSH_THEME --shell=elvish --execution-time=$cmd-duration --status=$error-code --pwd=$pwd --shell-version=$E:POSH_SHELL_VERSION } diff --git a/src/shell/scripts/omp.fish b/src/shell/scripts/omp.fish index 92b0f5b1..409e0a2b 100644 --- a/src/shell/scripts/omp.fish +++ b/src/shell/scripts/omp.fish @@ -7,6 +7,11 @@ set --global _omp_tooltip_command '' set --global _omp_current_rprompt '' set --global _omp_transient false +set --global _omp_executable ::OMP:: +set --global _omp_ftcs_marks 0 +set --global _omp_transient_prompt 0 +set --global _omp_prompt_mark 0 + # We use this to avoid unnecessary CLI calls for prompt repaint. set --global _omp_new_prompt true @@ -25,7 +30,7 @@ function fish_prompt # see https://github.com/fish-shell/fish-shell/issues/8418 printf \e\[0J if test "$_omp_transient" = true - ::OMP:: print transient --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --no-status=$_omp_no_exit_code + $_omp_executable print transient --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --no-status=$_omp_no_exit_code return end if test "$_omp_new_prompt" = false @@ -67,10 +72,12 @@ function fish_prompt set omp_cleared true end - ::PROMPT_MARK:: + if test $_omp_prompt_mark = 1 + iterm2_prompt_mark + end # The prompt is saved for possible reuse, typically a repaint after clearing the screen buffer. - set --global _omp_current_prompt (::OMP:: print primary --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --cleared=$omp_cleared --no-status=$_omp_no_exit_code | string collect) + set --global _omp_current_prompt ($_omp_executable print primary --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --cleared=$omp_cleared --no-status=$_omp_no_exit_code | string collect) echo -n "$_omp_current_prompt" end @@ -79,13 +86,16 @@ function fish_right_prompt set _omp_transient false return end + # Repaint an existing right prompt. if test "$_omp_new_prompt" = false echo -n "$_omp_current_rprompt" return end + set _omp_new_prompt false - set --global _omp_current_rprompt (::OMP:: print right --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --no-status=$_omp_no_exit_code | string join '') + set --global _omp_current_rprompt ($_omp_executable print right --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --no-status=$_omp_no_exit_code | string join '') + echo -n "$_omp_current_rprompt" end @@ -96,7 +106,7 @@ function _omp_postexec --on-event fish_postexec end function _omp_preexec --on-event fish_preexec - if test "::FTCS_MARKS::" = true + if test $_omp_ftcs_marks = 1 echo -ne "\e]133;C\a" end end @@ -107,16 +117,19 @@ if test -n (bind \r --user 2>/dev/null | string match -e _omp_enter_key_handler) bind -e \r -M insert bind -e \r -M visual end + if test -n (bind \n --user 2>/dev/null | string match -e _omp_enter_key_handler) bind -e \n -M default bind -e \n -M insert bind -e \n -M visual end + if test -n (bind \cc --user 2>/dev/null | string match -e _omp_ctrl_c_key_handler) bind -e \cc -M default bind -e \cc -M insert bind -e \cc -M visual end + if test -n (bind \x20 --user 2>/dev/null | string match -e _omp_space_key_handler) bind -e \x20 -M default bind -e \x20 -M insert @@ -127,23 +140,28 @@ end function _omp_space_key_handler commandline --function expand-abbr commandline --insert ' ' + # Get the first word of command line as tip. set --local tooltip_command (commandline --current-buffer | string trim -l | string split --allow-empty -f1 ' ' | string collect) + # Ignore an empty/repeated tooltip command. if test -z "$tooltip_command" || test "$tooltip_command" = "$_omp_tooltip_command" return end + set _omp_tooltip_command $tooltip_command - set --local tooltip_prompt (::OMP:: print tooltip --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --command $_omp_tooltip_command --no-status=$_omp_no_exit_code | string join '') + set --local tooltip_prompt ($_omp_executable print tooltip --config $POSH_THEME --shell fish --status $_omp_status_cache --pipestatus="$_omp_pipestatus_cache" --execution-time $_omp_duration --stack-count $_omp_stack_count --shell-version $FISH_VERSION --command $_omp_tooltip_command --no-status=$_omp_no_exit_code | string join '') + if test -z "$tooltip_prompt" return end + # Save the tooltip prompt to avoid unnecessary CLI calls. set _omp_current_rprompt $tooltip_prompt commandline --function repaint end -if test "::TOOLTIPS::" = true +function enable_poshtooltips bind \x20 _omp_space_key_handler -M default bind \x20 _omp_space_key_handler -M insert end @@ -155,14 +173,17 @@ function _omp_enter_key_handler commandline --function accept-autosuggestion return end + if commandline --is-valid || test -z (commandline --current-buffer | string trim -l | string collect) set _omp_new_prompt true set _omp_tooltip_command '' - if test "::TRANSIENT::" = true + + if test $_omp_transient_prompt = 1 set _omp_transient true commandline --function repaint end end + commandline --function execute end @@ -170,13 +191,16 @@ function _omp_ctrl_c_key_handler if test -z (commandline --current-buffer | string collect) return end + # Render a transient prompt on Ctrl-C with non-empty command line buffer. set _omp_new_prompt true set _omp_tooltip_command '' - if test "::TRANSIENT::" = true + + if test $_omp_transient_prompt = 1 set _omp_transient true commandline --function repaint end + commandline --function cancel-commandline commandline --function repaint end @@ -192,17 +216,6 @@ bind \cc _omp_ctrl_c_key_handler -M insert bind \cc _omp_ctrl_c_key_handler -M visual # legacy functions -function enable_poshtooltips - return -end function enable_poshtransientprompt return end - -if test "::UPGRADE::" = true - echo "::UPGRADENOTICE::" -end - -if test "::AUTOUPGRADE::" = true - ::OMP:: upgrade -end diff --git a/src/shell/scripts/omp.lua b/src/shell/scripts/omp.lua index 4de0af3d..12d09613 100644 --- a/src/shell/scripts/omp.lua +++ b/src/shell/scripts/omp.lua @@ -39,8 +39,8 @@ end local endedit_time = 0 local last_duration = 0 -local tooltips_enabled = ::TOOLTIPS:: -local rprompt_enabled = ::RPROMPT:: +local rprompt_enabled = false +local transient_enabled = false local no_exit_code = true local cached_prompt = {} @@ -260,20 +260,29 @@ function p:filter(prompt) return cached_prompt.left end + function p:rightfilter(prompt) -- Return cached tooltip if available, otherwise return cached rprompt. -- Returning false as the second return value halts further prompt -- filtering, to keep other things from overriding what we generated. return (cached_prompt.tooltip or cached_prompt.right), false end + function p:transientfilter(prompt) + if not transient_enabled then + return nil + end + local prompt_exe = string.format('%s print transient --shell=cmd --config=%s %s %s', omp_exe(), omp_config(), error_level_option(), no_exit_code_option()) prompt = run_posh_command(prompt_exe) + if prompt == "" then prompt = nil end + return prompt end + function p:transientrightfilter(prompt) return "", false end @@ -323,11 +332,10 @@ function ohmyposh_space(rl_buffer) end end -if tooltips_enabled and rl.setbinding then +local function enable_tooltips() + if not rl.setbinding then + return + end + rl.setbinding(' ', [["luafunc:ohmyposh_space"]], 'emacs') end - -if '::AUTOUPGRADE::' == 'true' then - local prompt_exe = string.format('%s upgrade', omp_exe()) - os.execute(prompt_exe) -end diff --git a/src/shell/scripts/omp.nu b/src/shell/scripts/omp.nu index b9a043d2..86327ad9 100644 --- a/src/shell/scripts/omp.nu +++ b/src/shell/scripts/omp.nu @@ -9,6 +9,8 @@ $env.PROMPT_INDICATOR = "" $env.POSH_PID = (random uuid) $env.POSH_SHELL_VERSION = (version | get version) +let _omp_executable: string = ::OMP:: + def posh_cmd_duration [] { # We have to do this because the initial value of `$env.CMD_DURATION_MS` is always `0823`, # which is an official setting. @@ -21,7 +23,7 @@ def posh_width [] { } # PROMPTS -$env.PROMPT_MULTILINE_INDICATOR = (^::OMP:: print secondary $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)") +$env.PROMPT_MULTILINE_INDICATOR = (^$_omp_executable print secondary $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)") $env.PROMPT_COMMAND = { || # hack to set the cursor line to 1 when the user clears the screen @@ -35,23 +37,9 @@ $env.PROMPT_COMMAND = { || do --env $env.SET_POSHCONTEXT } - ^::OMP:: print primary $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)" $"--cleared=($clear)" + ^$_omp_executable print primary $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)" $"--cleared=($clear)" } $env.PROMPT_COMMAND_RIGHT = { || - ^::OMP:: print right $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)" -} - -if "::TRANSIENT::" == "true" { - $env.TRANSIENT_PROMPT_COMMAND = { || - ^::OMP:: print transient $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)" - } -} - -if "::UPGRADE::" == "true" { - echo "::UPGRADENOTICE::" -} - -if "::AUTOUPGRADE::" == "true" { - ^::OMP:: upgrade + ^$_omp_executable print right $"--config=($env.POSH_THEME)" --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)" } diff --git a/src/shell/scripts/omp.ps1 b/src/shell/scripts/omp.ps1 index ff6796f2..6554d77a 100644 --- a/src/shell/scripts/omp.ps1 +++ b/src/shell/scripts/omp.ps1 @@ -13,6 +13,13 @@ function global:Get-PoshStackCount { return 0 } +# global enablers +$global:_ompJobCount = $false +$global:_ompFTCSMarks = $false +$global:_ompPoshGit = $false +$global:_ompAzure = $false +$global:_ompExecutable = ::OMP:: + New-Module -Name "oh-my-posh-core" -ScriptBlock { # Check `ConstrainedLanguage` mode. $script:ConstrainedLanguageMode = $ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage" @@ -25,11 +32,12 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { $script:NoExitCode = $true $script:ErrorCode = 0 $script:ExecutionTime = 0 - $script:OMPExecutable = ::OMP:: $script:ShellName = "::SHELL::" $script:PSVersion = $PSVersionTable.PSVersion.ToString() $script:TransientPrompt = $false $script:TooltipCommand = '' + $script:JobCount = 0 + $env:POWERLINE_COMMAND = "oh-my-posh" $env:POSH_SHELL_VERSION = $script:PSVersion $env:POSH_PID = $PID @@ -40,25 +48,6 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { $env:POSH_THEME = (Resolve-Path -Path ::CONFIG::).ProviderPath } - # specific module support (disabled by default) - if (($null -eq $env:POSH_GIT_ENABLED) -or ($null -eq (Get-Module 'posh-git'))) { - $env:POSH_GIT_ENABLED = $false - } - if (($null -eq $env:POSH_AZURE_ENABLED) -or ($null -eq (Get-Module 'az'))) { - $env:POSH_AZURE_ENABLED = $false - } - - function Initialize-ModuleSupport { - if ($env:POSH_GIT_ENABLED -eq $true) { - # We need to set the status so posh-git can facilitate autocomplete - $global:GitStatus = Get-GitStatus - $env:POSH_GIT_STATUS = $global:GitStatus | ConvertTo-Json - } - if ($env:POSH_AZURE_ENABLED -eq $true) { - $env:POSH_AZURE_SUBSCRIPTION = Get-AzContext | ConvertTo-Json - } - } - function Start-Utf8Process { param( [string]$FileName, @@ -94,6 +83,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { } $StartInfo.Arguments = $escapedArgs -join ' ' } + $StartInfo.StandardErrorEncoding = $StartInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8 $StartInfo.RedirectStandardError = $StartInfo.RedirectStandardInput = $StartInfo.RedirectStandardOutput = $true $StartInfo.UseShellExecute = $false @@ -106,6 +96,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { } $StartInfo.WorkingDirectory = $PWD.ProviderPath } + $StartInfo.CreateNoWindow = $true [void]$Process.Start() @@ -118,6 +109,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { if ($stderr) { $Host.UI.WriteErrorLine($stderr) } + $stdoutTask.Result } @@ -140,68 +132,61 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { $terminalWidth } - if (!$script:ConstrainedLanguageMode) { - if ('::TOOLTIPS::' -eq 'true') { - Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock { - param([ConsoleKeyInfo]$key) - [Microsoft.PowerShell.PSConsoleReadLine]::SelfInsert($key) - try { - $command = '' - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null) - # Get the first word of command line as tip. - $command = $command.TrimStart().Split(' ', 2) | Select-Object -First 1 - # Ignore an empty/repeated tooltip command. - if (!$command -or ($command -eq $script:TooltipCommand)) { - return - } - - $script:TooltipCommand = $command - $column = $Host.UI.RawUI.CursorPosition.X - $terminalWidth = Get-TerminalWidth - $cleanPSWD = Get-CleanPSWD - $stackCount = global:Get-PoshStackCount - - $arguments = @( - "print" - "tooltip" - "--status=$script:ErrorCode" - "--shell=$script:ShellName" - "--pswd=$cleanPSWD" - "--execution-time=$script:ExecutionTime" - "--stack-count=$stackCount" - "--config=$env:POSH_THEME" - "--command=$command" - "--shell-version=$script:PSVersion" - "--column=$column" - "--terminal-width=$terminalWidth" - "--no-status=$script:NoExitCode" - ) - - $standardOut = (Start-Utf8Process $script:OMPExecutable $arguments) -join '' - if (!$standardOut) { - return - } - - Write-Host $standardOut -NoNewline - - # Workaround to prevent the text after cursor from disappearing when the tooltip is printed. - [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ') - [Microsoft.PowerShell.PSConsoleReadLine]::Undo() - } - finally {} - } + function Enable-PoshTooltips { + if ($script:ConstrainedLanguageMode) { + return } - function Set-TransientPrompt { - $previousOutputEncoding = [Console]::OutputEncoding + Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock { + param([ConsoleKeyInfo]$key) + [Microsoft.PowerShell.PSConsoleReadLine]::SelfInsert($key) try { - $script:TransientPrompt = $true - [Console]::OutputEncoding = [Text.Encoding]::UTF8 - [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() - } - finally { - [Console]::OutputEncoding = $previousOutputEncoding + $command = '' + [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null) + # Get the first word of command line as tip. + $command = $command.TrimStart().Split(' ', 2) | Select-Object -First 1 + + # Ignore an empty/repeated tooltip command. + if (!$command -or ($command -eq $script:TooltipCommand)) { + return + } + + $script:TooltipCommand = $command + $column = $Host.UI.RawUI.CursorPosition.X + $terminalWidth = Get-TerminalWidth + $cleanPSWD = Get-CleanPSWD + $stackCount = global:Get-PoshStackCount + + $standardOut = (Start-Utf8Process $global:_ompExecutable @("print", "tooltip", "--status=$script:ErrorCode", "--shell=$script:ShellName", "--pswd=$cleanPSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--config=$env:POSH_THEME", "--command=$command", "--shell-version=$script:PSVersion", "--column=$column", "--terminal-width=$terminalWidth", "--no-status=$script:NoExitCode", "--job-count=$script:JobCount")) -join '' + if (!$standardOut) { + return + } + + Write-Host $standardOut -NoNewline + + # Workaround to prevent the text after cursor from disappearing when the tooltip is printed. + [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ') + [Microsoft.PowerShell.PSConsoleReadLine]::Undo() } + finally {} + } + } + + function Set-TransientPrompt { + $previousOutputEncoding = [Console]::OutputEncoding + try { + $script:TransientPrompt = $true + [Console]::OutputEncoding = [Text.Encoding]::UTF8 + [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() + } + finally { + [Console]::OutputEncoding = $previousOutputEncoding + } + } + + function Enable-PoshTransientPrompt { + if ($script:ConstrainedLanguageMode) { + return } Set-PSReadLineKeyHandler -Key Enter -BriefDescription 'OhMyPoshEnterKeyHandler' -ScriptBlock { @@ -212,19 +197,18 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { if ($executingCommand) { $script:newPrompt = $true $script:TooltipCommand = '' - if ('::TRANSIENT::' -eq 'true') { - Set-TransientPrompt - } + Set-TransientPrompt } } finally { [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() - if (('::FTCS_MARKS::' -eq 'true') -and $executingCommand) { + if ($global:_ompFTCSMarks -and $executingCommand) { # Write FTCS_COMMAND_EXECUTED after accepting the input - it should still happen before execution Write-Host "$([char]0x1b)]133;C`a" -NoNewline } } } + Set-PSReadLineKeyHandler -Key Ctrl+c -BriefDescription 'OhMyPoshCtrlCKeyHandler' -ScriptBlock { try { $start = $null @@ -233,9 +217,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { if ($start -eq -1) { $script:newPrompt = $true $script:TooltipCommand = '' - if ('::TRANSIENT::' -eq 'true') { - Set-TransientPrompt - } + Set-TransientPrompt } } finally { @@ -244,9 +226,9 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { } } - if ("::ERROR_LINE::" -eq "true") { - $validLine = (Start-Utf8Process $script:OMPExecutable @("print", "valid", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n" - $errorLine = (Start-Utf8Process $script:OMPExecutable @("print", "error", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n" + function Enable-PoshLineError { + $validLine = (Start-Utf8Process $global:_ompExecutable @("print", "valid", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n" + $errorLine = (Start-Utf8Process $global:_ompExecutable @("print", "error", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n" Set-PSReadLineOption -PromptText $validLine, $errorLine } @@ -285,7 +267,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { $Format = 'json' ) - $configString = Start-Utf8Process $script:OMPExecutable @("config", "export", "--config=$env:POSH_THEME", "--format=$Format") + $configString = Start-Utf8Process $global:_ompExecutable @("config", "export", "--config=$env:POSH_THEME", "--format=$Format") # if no path, copy to clipboard by default if ($FilePath) { # https://stackoverflow.com/questions/3038337/powershell-resolve-path-that-might-not-exist @@ -305,15 +287,18 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { [Parameter(ValuefromPipeline = $True)] [string]$name ) + $esc = [char]27 if (!$name) { # if name not set, uri is used as the name of the hyperlink $name = $uri } + if ($null -ne $env:WSL_DISTRO_NAME) { # wsl conversion if needed $uri = &wslpath -m $uri } + # return an ANSI formatted hyperlink return "$esc]8;;file://$uri$esc\$name$esc]8;;$esc\" } @@ -353,7 +338,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock { $cleanPSWD = Get-CleanPSWD $themes | ForEach-Object -Process { Write-Host "Theme: $(Get-FileHyperlink -uri $_.FullName -Name ($_.BaseName -replace '\.omp$', ''))`n" - Start-Utf8Process $script:OMPExecutable @("print", "primary", "--config=$($_.FullName)", "--pswd=$cleanPSWD", "--shell=$script:ShellName") + Start-Utf8Process $global:_ompExecutable @("print", "primary", "--config=$($_.FullName)", "--pswd=$cleanPSWD", "--shell=$script:ShellName") Write-Host "`n" } } @@ -374,6 +359,7 @@ Example: $script:TransientPrompt = $false return } + # for details about the trick to detect a debugging context, see these comments: # 1) https://github.com/JanDeDobbeleer/oh-my-posh/issues/2483#issuecomment-1175761456 # 2) https://github.com/JanDeDobbeleer/oh-my-posh/issues/2502#issuecomment-1179968052 @@ -382,18 +368,35 @@ Example: $script:PromptType = "debug" return } + $script:PromptType = "primary" - Initialize-ModuleSupport + + if ($global:_ompJobCount) { + $script:JobCount = (Get-Job -State Running).Count + } + + if ($global:_ompAzure) { + $env:POSH_AZURE_SUBSCRIPTION = Get-AzContext | ConvertTo-Json + } + + if ($global:_ompPoshGit) { + $global:GitStatus = Get-GitStatus + $env:POSH_GIT_STATUS = $global:GitStatus | ConvertTo-Json + } + + Set-PoshContext } function Update-PoshErrorCode { $lastHistory = Get-History -ErrorAction Ignore -Count 1 + # error code should be updated only when a non-empty command is run if (($null -eq $lastHistory) -or ($script:LastHistoryId -eq $lastHistory.Id)) { $script:ExecutionTime = 0 $script:NoExitCode = $true return } + $script:NoExitCode = $false $script:LastHistoryId = $lastHistory.Id $script:ExecutionTime = ($lastHistory.EndExecutionTime - $lastHistory.StartExecutionTime).TotalMilliseconds @@ -401,16 +404,19 @@ Example: $script:ErrorCode = 0 return } + $invocationInfo = try { # retrieve info of the most recent error $global:Error[0] | Where-Object { $_ -ne $null } | Select-Object -ExpandProperty InvocationInfo } catch { $null } + # check if the last command caused the last error if ($null -ne $invocationInfo -and $lastHistory.CommandLine -eq $invocationInfo.Line) { $script:ErrorCode = 1 return } + if ($script:OriginalLastExitCode -is [int] -and $script:OriginalLastExitCode -ne 0) { # native app exit code $script:ErrorCode = $script:OriginalLastExitCode @@ -432,35 +438,19 @@ Example: Set-PoshPromptType - if ($script:PromptType -ne 'transient') { Update-PoshErrorCode } $cleanPSWD = Get-CleanPSWD $stackCount = global:Get-PoshStackCount - Set-PoshContext $terminalWidth = Get-TerminalWidth # set the cursor positions, they are zero based so align with other platforms $env:POSH_CURSOR_LINE = $Host.UI.RawUI.CursorPosition.Y + 1 $env:POSH_CURSOR_COLUMN = $Host.UI.RawUI.CursorPosition.X + 1 - $arguments = @( - "print" - $script:PromptType - "--status=$script:ErrorCode" - "--pswd=$cleanPSWD" - "--execution-time=$script:ExecutionTime" - "--stack-count=$stackCount" - "--config=$env:POSH_THEME" - "--shell-version=$script:PSVersion" - "--terminal-width=$terminalWidth" - "--shell=$script:ShellName" - "--no-status=$script:NoExitCode" - ) - - $standardOut = Start-Utf8Process $script:OMPExecutable $arguments + $standardOut = Start-Utf8Process $global:_ompExecutable @("print", $script:PromptType, "--status=$script:ErrorCode", "--pswd=$cleanPSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--config=$env:POSH_THEME", "--shell-version=$script:PSVersion", "--terminal-width=$terminalWidth", "--shell=$script:ShellName", "--no-status=$script:NoExitCode", "--job-count=$script:JobCount") # make sure PSReadLine knows if we have a multiline prompt Set-PSReadLineOption -ExtraPromptLineCount (($standardOut | Measure-Object -Line).Lines - 1) @@ -477,33 +467,32 @@ Example: $Function:prompt = $promptFunction # set secondary prompt - Set-PSReadLineOption -ContinuationPrompt ((Start-Utf8Process $script:OMPExecutable @("print", "secondary", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n") - - # legacy functions - function Enable-PoshTooltips {} - function Enable-PoshTransientPrompt {} - function Enable-PoshLineError {} + Set-PSReadLineOption -ContinuationPrompt ((Start-Utf8Process $global:_ompExecutable @("print", "secondary", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n") # perform cleanup on removal so a new initialization in current session works if (!$script:ConstrainedLanguageMode) { $ExecutionContext.SessionState.Module.OnRemove += { Remove-Item Function:Get-PoshStackCount $Function:prompt = $script:OriginalPromptFunction + (Get-PSReadLineOption).ContinuationPrompt = $script:OriginalContinuationPrompt (Get-PSReadLineOption).PromptText = $script:OriginalPromptText + if ((Get-PSReadLineKeyHandler Spacebar).Function -eq 'OhMyPoshSpaceKeyHandler') { Remove-PSReadLineKeyHandler Spacebar } + if ((Get-PSReadLineKeyHandler Enter).Function -eq 'OhMyPoshEnterKeyHandler') { Set-PSReadLineKeyHandler Enter -Function AcceptLine } + if ((Get-PSReadLineKeyHandler Ctrl+c).Function -eq 'OhMyPoshCtrlCKeyHandler') { Set-PSReadLineKeyHandler Ctrl+c -Function CopyOrCancelLine } } } - $notice = Start-Utf8Process $script:OMPExecutable @("notice") + $notice = Start-Utf8Process $global:_ompExecutable @("notice") if ($notice) { Write-Host $notice -NoNewline } @@ -519,8 +508,3 @@ Example: "prompt" ) } | Import-Module -Global - - -if ("::AUTOUPGRADE::" -eq "true") { - & ::OMP:: upgrade -} diff --git a/src/shell/scripts/omp.py b/src/shell/scripts/omp.py index 4c33f3e5..1801aa74 100644 --- a/src/shell/scripts/omp.py +++ b/src/shell/scripts/omp.py @@ -4,6 +4,7 @@ $POWERLINE_COMMAND = "oh-my-posh" $POSH_THEME = r"::CONFIG::" $POSH_PID = uuid.uuid4().hex $POSH_SHELL_VERSION = $XONSH_VERSION +$POSH_EXECUTABLE = r"::OMP::" def get_command_context(): last_cmd = __xonsh__.history[-1] if __xonsh__.history else None @@ -13,20 +14,12 @@ def get_command_context(): def posh_primary(): status, duration = get_command_context() - return $(::OMP:: print primary --config=@($POSH_THEME) --shell=xonsh --status=@(status) --execution-time=@(duration) --shell-version=@($POSH_SHELL_VERSION)) + return $(@($POSH_EXECUTABLE) print primary --config=@($POSH_THEME) --shell=xonsh --status=@(status) --execution-time=@(duration) --shell-version=@($POSH_SHELL_VERSION)) def posh_right(): status, duration = get_command_context() - return $(::OMP:: print right --config=@($POSH_THEME) --shell=xonsh --status=@(status) --execution-time=@(duration) --shell-version=@($POSH_SHELL_VERSION)) + return $(@($POSH_EXECUTABLE) print right --config=@($POSH_THEME) --shell=xonsh --status=@(status) --execution-time=@(duration) --shell-version=@($POSH_SHELL_VERSION)) $PROMPT = posh_primary $RIGHT_PROMPT = posh_right - -notice = """::UPGRADENOTICE::""" - -if "::UPGRADE::" == "true": - print(notice) - -if "::AUTOUPGRADE::" == "true": - ::OMP:: upgrade diff --git a/src/shell/scripts/omp.tcsh b/src/shell/scripts/omp.tcsh index 881c22a6..531bda43 100644 --- a/src/shell/scripts/omp.tcsh +++ b/src/shell/scripts/omp.tcsh @@ -1,15 +1,14 @@ setenv POWERLINE_COMMAND "oh-my-posh"; -setenv POSH_THEME "::CONFIG::"; +setenv POSH_THEME ::CONFIG::; setenv POSH_SHELL_VERSION ""; +set POSH_COMMAND = ::OMP::; set USER_PRECMD = "`alias precmd`"; set USER_POSTCMD = "`alias postcmd`"; -set POSH_PRECMD = 'set POSH_CMD_STATUS = $status;set POSH_PATH = ::OMP::;set POSH_END_TIME = `$POSH_PATH get millis`;set POSH_DURATION = 0;if ( $POSH_START_TIME != -1 ) @ POSH_DURATION = $POSH_END_TIME - $POSH_START_TIME;set prompt = "`$POSH_PATH print primary --shell=tcsh --config=$POSH_THEME --status=$POSH_CMD_STATUS --execution-time=$POSH_DURATION`";set POSH_START_TIME = -1'; -set POSH_POSTCMD = 'set POSH_START_TIME = `::OMP:: get millis`'; +set POSH_PRECMD = 'set POSH_CMD_STATUS = $status;set POSH_END_TIME = `$POSH_COMMAND get millis`;set POSH_DURATION = 0;if ( $POSH_START_TIME != -1 ) @ POSH_DURATION = $POSH_END_TIME - $POSH_START_TIME;set prompt = "`$POSH_COMMAND print primary --shell=tcsh --config=$POSH_THEME --status=$POSH_CMD_STATUS --execution-time=$POSH_DURATION`";set POSH_START_TIME = -1'; +set POSH_POSTCMD = 'set POSH_START_TIME = `$POSH_COMMAND get millis`'; + alias precmd "$POSH_PRECMD;$USER_PRECMD"; alias postcmd "$POSH_POSTCMD;$USER_POSTCMD"; -set POSH_START_TIME = `::OMP:: get millis`; -if ("::UPGRADE::" == "true") echo "::UPGRADENOTICE::"; - -if ("::AUTOUPGRADE::" == "true") ::OMP:: upgrade; +set POSH_START_TIME = `$POSH_COMMAND get millis`; diff --git a/src/shell/scripts/omp.zsh b/src/shell/scripts/omp.zsh index d883ca17..f0fbb61b 100644 --- a/src/shell/scripts/omp.zsh +++ b/src/shell/scripts/omp.zsh @@ -6,13 +6,19 @@ export CONDA_PROMPT_MODIFIER=false export POSH_PROMPT_COUNT=0 export ZLE_RPROMPT_INDENT=0 +_omp_executable=::OMP:: + +# switches to enable/disable features +_omp_cursor_positioning=0 +_omp_ftcs_marks=0 + # set secondary prompt -PS2="$(::OMP:: print secondary --config="$POSH_THEME" --shell=zsh)" +PS2="$(${_omp_executable} print secondary --config="$POSH_THEME" --shell=zsh)" function _omp_set_cursor_position() { # not supported in Midnight Commander # see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3415 - if [[ "::CURSOR::" != "true" ]] || [[ -v MC_SID ]]; then + if [[ $_omp_cursor_positioning == 0 ]] || [[ -v MC_SID ]]; then return fi @@ -37,11 +43,11 @@ function set_poshcontext() { } function _omp_preexec() { - if [[ "::FTCS_MARKS::" = "true" ]]; then + if [[ $_omp_ftcs_marks == 0 ]]; then printf "\033]133;C\007" fi - _omp_start_time=$(::OMP:: get millis) + _omp_start_time=$(${_omp_executable} get millis) } function _omp_precmd() { @@ -52,7 +58,7 @@ function _omp_precmd() { _omp_no_exit_code="true" if [ $_omp_start_time ]; then - local omp_now=$(::OMP:: get millis --shell=zsh) + local omp_now=$(${_omp_executable} get millis --shell=zsh) _omp_elapsed=$(($omp_now - $_omp_start_time)) _omp_no_exit_code="false" fi @@ -67,7 +73,7 @@ function _omp_precmd() { set_poshcontext _omp_set_cursor_position - eval "$(::OMP:: print primary --config="$POSH_THEME" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$_omp_no_exit_code")" + eval "$(${_omp_executable} print primary --config="$POSH_THEME" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$_omp_no_exit_code")" unset _omp_start_time } @@ -110,7 +116,7 @@ function _omp_render_tooltip() { fi _omp_tooltip_command="$tooltip_command" - local tooltip=$(::OMP:: print tooltip --config="$POSH_THEME" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --command="$tooltip_command" --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$_omp_no_exit_code") + local tooltip=$(${_omp_executable} print tooltip --config="$POSH_THEME" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --command="$tooltip_command" --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$_omp_no_exit_code") if [[ -z "$tooltip" ]]; then return fi @@ -129,7 +135,7 @@ function _omp_zle-line-init() { (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2] _omp_tooltip_command='' - eval "$(::OMP:: print transient --config="$POSH_THEME" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$_omp_no_exit_code")" + eval "$(${_omp_executable} print transient --config="$POSH_THEME" --status="$_omp_status_cache" --pipestatus="${_omp_pipestatus_cache[*]}" --execution-time="$_omp_elapsed" --stack-count="$_omp_stack_count" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$_omp_no_exit_code")" zle .reset-prompt # Exit the shell if we receive EOT. @@ -187,19 +193,3 @@ function _omp_create_widget() { # legacy functions function enable_poshtooltips() {} function enable_poshtransientprompt() {} - -if [[ "::TOOLTIPS::" = "true" ]]; then - _omp_create_widget self-insert _omp_render_tooltip -fi - -if [[ "::TRANSIENT::" = "true" ]]; then - _omp_create_widget zle-line-init _omp_zle-line-init -fi - -if [[ "::UPGRADE::" = "true" ]]; then - echo "::UPGRADENOTICE::" -fi - -if [[ "::AUTOUPGRADE::" = "true" ]]; then - ::OMP:: upgrade -fi diff --git a/src/shell/tcsh.go b/src/shell/tcsh.go new file mode 100644 index 00000000..a6eac334 --- /dev/null +++ b/src/shell/tcsh.go @@ -0,0 +1,21 @@ +package shell + +import ( + _ "embed" +) + +//go:embed scripts/omp.tcsh +var tcshInit string + +func (f Feature) Tcsh() Code { + switch f { + case Upgrade: + return "$POSH_COMMAND upgrade;" + case Notice: + return "$POSH_COMMAND notice;" + case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, Transient, FTCSMarks, CursorPositioning: + fallthrough + default: + return "" + } +} diff --git a/src/shell/tcsh_test.go b/src/shell/tcsh_test.go new file mode 100644 index 00000000..292b2c64 --- /dev/null +++ b/src/shell/tcsh_test.go @@ -0,0 +1,17 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTcshFeatures(t *testing.T) { + got := allFeatures.Lines(TCSH).String("// these are the features") + + want := `// these are the features +$POSH_COMMAND upgrade; +$POSH_COMMAND notice;` + + assert.Equal(t, want, got) +} diff --git a/src/shell/xonsh.go b/src/shell/xonsh.go new file mode 100644 index 00000000..6aaabfd4 --- /dev/null +++ b/src/shell/xonsh.go @@ -0,0 +1,21 @@ +package shell + +import ( + _ "embed" +) + +//go:embed scripts/omp.py +var xonshInit string + +func (f Feature) Xonsh() Code { + switch f { + case Upgrade: + return "@($POSH_EXECUTABLE) upgrade" + case Notice: + return "@($POSH_EXECUTABLE) notice" + case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, Transient, CursorPositioning, FTCSMarks: + fallthrough + default: + return "" + } +} diff --git a/src/shell/xonsh_test.go b/src/shell/xonsh_test.go new file mode 100644 index 00000000..321f3fcc --- /dev/null +++ b/src/shell/xonsh_test.go @@ -0,0 +1,17 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestXonshFeatures(t *testing.T) { + got := allFeatures.Lines(XONSH).String("// these are the features") + + want := `// these are the features +@($POSH_EXECUTABLE) upgrade +@($POSH_EXECUTABLE) notice` + + assert.Equal(t, want, got) +} diff --git a/src/shell/zsh.go b/src/shell/zsh.go new file mode 100644 index 00000000..53727e4c --- /dev/null +++ b/src/shell/zsh.go @@ -0,0 +1,29 @@ +package shell + +import ( + _ "embed" +) + +//go:embed scripts/omp.zsh +var zshInit string + +func (f Feature) Zsh() Code { + switch f { + case CursorPositioning: + return "_omp_cursor_positioning=1" + case Tooltips: + return "_omp_create_widget self-insert _omp_render_tooltip" + case Transient: + return "_omp_create_widget zle-line-init _omp_zle-line-init" + case FTCSMarks: + return "_omp_ftcs_marks=1" + case Upgrade: + return unixUpgrade + case Notice: + return unixNotice + case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs: + fallthrough + default: + return "" + } +} diff --git a/src/shell/zsh_test.go b/src/shell/zsh_test.go new file mode 100644 index 00000000..592b6250 --- /dev/null +++ b/src/shell/zsh_test.go @@ -0,0 +1,21 @@ +package shell + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestZshFeatures(t *testing.T) { + got := allFeatures.Lines(ZSH).String("// these are the features") + + want := `// these are the features +enable_poshtooltips +_omp_create_widget zle-line-init _omp_zle-line-init +_omp_ftcs_marks=1 +$_omp_executable upgrade +$_omp_executable notice +_omp_cursor_positioning=1` + + assert.Equal(t, want, got) +} diff --git a/src/template/text.go b/src/template/text.go index 51e6db3c..ce119d2a 100644 --- a/src/template/text.go +++ b/src/template/text.go @@ -43,6 +43,7 @@ var ( "Templates", "Var", "Data", + "Jobs", } shell string