refactor(init): enable features automatically

This commit is contained in:
Jan De Dobbeleer 2024-07-24 13:16:03 +02:00 committed by Jan De Dobbeleer
parent ef16b1cd3a
commit 4a1aa2a7b4
40 changed files with 921 additions and 479 deletions

View file

@ -22,6 +22,7 @@ type Template struct {
WSL bool WSL bool
PromptCount int PromptCount int
SHLVL int SHLVL int
Jobs int
Segments *maps.Concurrent Segments *maps.Concurrent
SegmentsCache maps.Simple SegmentsCache maps.Simple

View file

@ -6,7 +6,6 @@ import (
"github.com/jandedobbeleer/oh-my-posh/src/config" "github.com/jandedobbeleer/oh-my-posh/src/config"
"github.com/jandedobbeleer/oh-my-posh/src/runtime" "github.com/jandedobbeleer/oh-my-posh/src/runtime"
"github.com/jandedobbeleer/oh-my-posh/src/shell" "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/jandedobbeleer/oh-my-posh/src/upgrade"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -68,35 +67,20 @@ func runInit(shellName string) {
cfg := config.Load(env) cfg := config.Load(env)
shell.Transient = cfg.TransientPrompt != nil // TODO: this can be removed I think
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
}
}
// allow overriding the upgrade notice from the config // allow overriding the upgrade notice from the config
if cfg.DisableNotice || cfg.AutoUpgrade { if cfg.DisableNotice || cfg.AutoUpgrade {
env.Cache().Set(upgrade.CACHEKEY, "disabled", -1) env.Cache().Set(upgrade.CACHEKEY, "disabled", -1)
} }
feats := cfg.Features()
if printOutput { if printOutput {
init := shell.PrintInit(env) init := shell.PrintInit(env, feats)
fmt.Print(init) fmt.Print(init)
return return
} }
init := shell.Init(env) init := shell.Init(env, feats)
fmt.Print(init) fmt.Print(init)
} }

View file

@ -20,6 +20,7 @@ var (
eval bool eval bool
cleared bool cleared bool
cached bool cached bool
jobCount int
command string command string
shellVersion string shellVersion string
@ -68,6 +69,7 @@ var printCmd = &cobra.Command{
Cached: cached, Cached: cached,
NoExitCode: noStatus, NoExitCode: noStatus,
Column: column, Column: column,
JobCount: jobCount,
} }
eng := prompt.New(flags) 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(&cleared, "cleared", false, "do we have a clear terminal or not")
printCmd.Flags().BoolVar(&eval, "eval", false, "output the prompt for eval") 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(&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 // Deprecated flags, keep to not break CLI integration
printCmd.Flags().IntVarP(&status, "error", "e", 0, "last exit code") printCmd.Flags().IntVarP(&status, "error", "e", 0, "last exit code")

View file

@ -3,6 +3,8 @@ package config
import ( import (
"github.com/jandedobbeleer/oh-my-posh/src/color" "github.com/jandedobbeleer/oh-my-posh/src/color"
"github.com/jandedobbeleer/oh-my-posh/src/runtime" "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/template"
"github.com/jandedobbeleer/oh-my-posh/src/terminal" "github.com/jandedobbeleer/oh-my-posh/src/terminal"
) )
@ -74,3 +76,56 @@ func (cfg *Config) getPalette() color.Palette {
} }
return cfg.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
}

View file

@ -63,7 +63,7 @@ func loadConfig(env runtime.Environment) *Config {
data, err := stdOS.ReadFile(configFile) data, err := stdOS.ReadFile(configFile)
if err != nil { if err != nil {
env.DebugF("error reading config file: %s", err) env.Error(err)
return Default(env, true) return Default(env, true)
} }
@ -87,7 +87,7 @@ func loadConfig(env runtime.Environment) *Config {
} }
if err != nil { if err != nil {
env.DebugF("error decoding config file: %s", err) env.Error(err)
return Default(env, true) return Default(env, true)
} }

View file

@ -25,6 +25,7 @@ func (e *Engine) ExtraPrompt(promptType ExtraPromptType) string {
// populate env with latest context // populate env with latest context
e.Env.LoadTemplateCache() e.Env.LoadTemplateCache()
var prompt *config.Segment var prompt *config.Segment
switch promptType { switch promptType {
case Debug: case Debug:
prompt = e.Config.DebugPrompt prompt = e.Config.DebugPrompt

View file

@ -63,6 +63,7 @@ type Flags struct {
Cached bool Cached bool
NoExitCode bool NoExitCode bool
Column int Column int
JobCount int
} }
type CommandError struct { type CommandError struct {
@ -276,11 +277,14 @@ func (term *Terminal) resolveConfigPath() {
configFile = filepath.Join(term.Home(), configFile) configFile = filepath.Join(term.Home(), configFile)
} }
if !filepath.IsAbs(configFile) { abs, err := filepath.Abs(configFile)
configFile = filepath.Join(term.Pwd(), 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) { 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.PromptCount = term.CmdFlags.PromptCount
tmplCache.Env = make(map[string]string) tmplCache.Env = make(map[string]string)
tmplCache.Var = make(map[string]any) tmplCache.Var = make(map[string]any)
tmplCache.Jobs = term.CmdFlags.JobCount
if term.Var != nil { if term.Var != nil {
tmplCache.Var = term.Var tmplCache.Var = term.Var

View file

@ -21,9 +21,9 @@ type Az struct {
const ( const (
Source properties.Property = "source" Source properties.Property = "source"
pwsh = "pwsh" Pwsh = "pwsh"
cli = "cli" Cli = "cli"
firstMatch = "first_match" FirstMatch = "first_match"
azureEnv = "POSH_AZURE_SUBSCRIPTION" azureEnv = "POSH_AZURE_SUBSCRIPTION"
) )
@ -82,13 +82,13 @@ func (a *Az) Init(props properties.Properties, env runtime.Environment) {
} }
func (a *Az) Enabled() bool { func (a *Az) Enabled() bool {
source := a.props.GetString(Source, firstMatch) source := a.props.GetString(Source, FirstMatch)
switch source { switch source {
case firstMatch: case FirstMatch:
return a.getCLISubscription() || a.getModuleSubscription() return a.getCLISubscription() || a.getModuleSubscription()
case pwsh: case Pwsh:
return a.getModuleSubscription() return a.getModuleSubscription()
case cli: case Cli:
return a.getCLISubscription() return a.getCLISubscription()
} }
return false return false

View file

@ -74,14 +74,14 @@ func TestAzSegment(t *testing.T) {
ExpectedString: "AzureCliCloud", ExpectedString: "AzureCliCloud",
Template: "{{ .EnvironmentName }}", Template: "{{ .EnvironmentName }}",
HasCLI: true, HasCLI: true,
Source: cli, Source: Cli,
}, },
{ {
Case: "Az CLI Profile only - disabled", Case: "Az CLI Profile only - disabled",
ExpectedEnabled: false, ExpectedEnabled: false,
Template: "{{ .EnvironmentName }}", Template: "{{ .EnvironmentName }}",
HasCLI: false, HasCLI: false,
Source: cli, Source: Cli,
}, },
{ {
Case: "PowerShell Profile only", Case: "PowerShell Profile only",
@ -89,13 +89,13 @@ func TestAzSegment(t *testing.T) {
ExpectedString: "AzurePoshCloud", ExpectedString: "AzurePoshCloud",
Template: "{{ .EnvironmentName }}", Template: "{{ .EnvironmentName }}",
HasPowerShell: true, HasPowerShell: true,
Source: pwsh, Source: Pwsh,
}, },
{ {
Case: "Az CLI Profile only - disabled", Case: "Az CLI Profile only - disabled",
ExpectedEnabled: false, ExpectedEnabled: false,
Template: "{{ .EnvironmentName }}", Template: "{{ .EnvironmentName }}",
Source: pwsh, Source: Pwsh,
}, },
{ {
Case: "Az CLI account type", Case: "Az CLI account type",
@ -103,7 +103,7 @@ func TestAzSegment(t *testing.T) {
ExpectedString: "user", ExpectedString: "user",
Template: "{{ .User.Type }}", Template: "{{ .User.Type }}",
HasCLI: true, HasCLI: true,
Source: cli, Source: Cli,
}, },
} }
@ -136,7 +136,7 @@ func TestAzSegment(t *testing.T) {
} }
if tc.Source == "" { if tc.Source == "" {
tc.Source = firstMatch tc.Source = FirstMatch
} }
az := &Az{ az := &Az{

78
src/shell/bash.go Normal file
View file

@ -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()
}

19
src/shell/bash_test.go Normal file
View file

@ -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)
}

38
src/shell/cmd.go Normal file
View file

@ -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))
}

20
src/shell/cmd_test.go Normal file
View file

@ -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)
}

29
src/shell/code.go Normal file
View file

@ -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()
}

21
src/shell/elvish.go Normal file
View file

@ -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 ""
}
}

17
src/shell/elvish_test.go Normal file
View file

@ -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)
}

55
src/shell/features.go Normal file
View file

@ -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
}

61
src/shell/fish.go Normal file
View file

@ -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()
}

21
src/shell/fish_test.go Normal file
View file

@ -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)
}

View file

@ -1,171 +1,38 @@
package shell package shell
import ( import (
_ "embed"
"path/filepath"
"strconv"
"fmt" "fmt"
"os" "os"
"strings" "strings"
"github.com/jandedobbeleer/oh-my-posh/src/color"
"github.com/jandedobbeleer/oh-my-posh/src/runtime" "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 ( const (
noExe = "echo \"Unable to find Oh My Posh executable\"" 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) { func getExecutablePath(env runtime.Environment) (string, error) {
executable, err := os.Executable() executable, err := os.Executable()
if err != nil { if err != nil {
return "", err return "", err
} }
if env.Flags().Strict { if env.Flags().Strict {
return runtime.Base(env, executable), nil return runtime.Base(env, executable), nil
} }
// On Windows, it fails when the excutable is called in MSYS2 for example // On Windows, it fails when the excutable is called in MSYS2 for example
// which uses unix style paths to resolve the executable's location. // 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. // PowerShell knows how to resolve both, so we can swap this without any issue.
if env.GOOS() == runtime.WINDOWS { if env.GOOS() == runtime.WINDOWS {
executable = strings.ReplaceAll(executable, "\\", "/") executable = strings.ReplaceAll(executable, "\\", "/")
} }
return executable, nil return executable, nil
} }
func quotePwshStr(str string) string { func Init(env runtime.Environment, feats Features) 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 {
shell := env.Flags().Shell shell := env.Flags().Shell
switch shell { switch shell {
@ -197,44 +64,25 @@ func Init(env runtime.Environment) string {
return fmt.Sprintf(command, executable, shell, config, additionalParams) return fmt.Sprintf(command, executable, shell, config, additionalParams)
case ZSH, BASH, FISH, CMD, TCSH, XONSH: case ZSH, BASH, FISH, CMD, TCSH, XONSH:
return PrintInit(env) return PrintInit(env, feats)
case NU: case NU:
createNuInit(env) createNuInit(env, feats)
return "" return ""
default: default:
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell) 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) executable, err := getExecutablePath(env)
if err != nil { if err != nil {
return noExe 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 shell := env.Flags().Shell
configFile := env.Flags().Config configFile := env.Flags().Config
var ( var script string
script, notice string
hasNotice bool
)
switch shell { switch shell {
case PWSH, PWSH5: case PWSH, PWSH5:
@ -273,57 +121,11 @@ func PrintInit(env runtime.Environment) string {
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell) return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
} }
// only run this for shells that support init := strings.NewReplacer(
// injecting the notice directly
if shell != PWSH && shell != PWSH5 {
notice, hasNotice = upgrade.Notice(env, false)
}
return strings.NewReplacer(
"::OMP::", executable, "::OMP::", executable,
"::CONFIG::", configFile, "::CONFIG::", configFile,
"::SHELL::", shell, "::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) ).Replace(script)
}
return features.Lines(shell).String(init)
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)
} }

52
src/shell/nu.go Normal file
View file

@ -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()
}

19
src/shell/nu_test.go Normal file
View file

@ -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)
}

42
src/shell/pwsh.go Normal file
View file

@ -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, "'", "''"))
}

26
src/shell/pwsh_test.go Normal file
View file

@ -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)
}

View file

@ -4,22 +4,28 @@ export POWERLINE_COMMAND="oh-my-posh"
export POSH_PID=$$ export POSH_PID=$$
export CONDA_PROMPT_MODIFIER=false export CONDA_PROMPT_MODIFIER=false
# global variables
_omp_start_time="" _omp_start_time=""
_omp_stack_count=0 _omp_stack_count=0
_omp_elapsed=-1 _omp_elapsed=-1
_omp_no_exit_code="true" _omp_no_exit_code="true"
_omp_status_cache=0 _omp_status_cache=0
_omp_pipestatus_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 # start timer on command start
PS0='${_omp_start_time:0:$((_omp_start_time="$(_omp_start_timer)",0))}$(_omp_ftcs_command_start)' PS0='${_omp_start_time:0:$((_omp_start_time="$(_omp_start_timer)",0))}$(_omp_ftcs_command_start)'
# set secondary prompt # 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() { function _omp_set_cursor_position() {
# not supported in Midnight Commander # not supported in Midnight Commander
# see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3415 # 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 return
fi fi
@ -37,11 +43,11 @@ function _omp_set_cursor_position() {
} }
function _omp_start_timer() { function _omp_start_timer() {
::OMP:: get millis $_omp_executable get millis
} }
function _omp_ftcs_command_start() { function _omp_ftcs_command_start() {
if [[ "::FTCS_MARKS::" == "true" ]]; then if [[ $_omp_ftcs_marks == 0 ]]; then
printf "\e]133;C\a" printf "\e]133;C\a"
fi fi
} }
@ -62,7 +68,7 @@ function _omp_hook() {
_omp_stack_count=$((${#DIRSTACK[@]} - 1)) _omp_stack_count=$((${#DIRSTACK[@]} - 1))
if [[ "$_omp_start_time" ]]; then 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_elapsed=$((omp_now - _omp_start_time))
_omp_start_time="" _omp_start_time=""
_omp_no_exit_code="false" _omp_no_exit_code="false"
@ -75,19 +81,11 @@ function _omp_hook() {
set_poshcontext set_poshcontext
_omp_set_cursor_position _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 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" PROMPT_COMMAND="_omp_hook; $PROMPT_COMMAND"
fi fi
if [[ "::UPGRADE::" == "true" ]]; then
echo "::UPGRADENOTICE::"
fi
if [[ "::AUTOUPGRADE::" == "true" ]]; then
::OMP:: upgrade
fi

View file

@ -4,6 +4,7 @@ set-env POSH_SHELL_VERSION (elvish --version)
set-env POWERLINE_COMMAND 'oh-my-posh' set-env POWERLINE_COMMAND 'oh-my-posh'
var error-code = 0 var error-code = 0
var _omp_executable = ::OMP::
fn posh-after-command-hook {|m| fn posh-after-command-hook {|m|
var error = $m[error] var error = $m[error]
@ -23,18 +24,10 @@ set edit:after-command = [ $@edit:after-command $posh-after-command-hook~ ]
set edit:prompt = { set edit:prompt = {
var cmd-duration = (printf "%.0f" (* $edit:command-duration 1000)) 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 = { set edit:rprompt = {
var cmd-duration = (printf "%.0f" (* $edit:command-duration 1000)) 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 $_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
}
if (eq '::UPGRADE::' 'true') {
echo '::UPGRADENOTICE::'
}
if (eq '::AUTOUPGRADE::' 'true') {
::OMP:: upgrade
} }

View file

@ -7,6 +7,11 @@ set --global _omp_tooltip_command ''
set --global _omp_current_rprompt '' set --global _omp_current_rprompt ''
set --global _omp_transient false 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. # We use this to avoid unnecessary CLI calls for prompt repaint.
set --global _omp_new_prompt true set --global _omp_new_prompt true
@ -25,7 +30,7 @@ function fish_prompt
# see https://github.com/fish-shell/fish-shell/issues/8418 # see https://github.com/fish-shell/fish-shell/issues/8418
printf \e\[0J printf \e\[0J
if test "$_omp_transient" = true 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 return
end end
if test "$_omp_new_prompt" = false if test "$_omp_new_prompt" = false
@ -67,10 +72,12 @@ function fish_prompt
set omp_cleared true set omp_cleared true
end 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. # 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" echo -n "$_omp_current_prompt"
end end
@ -79,13 +86,16 @@ function fish_right_prompt
set _omp_transient false set _omp_transient false
return return
end end
# Repaint an existing right prompt. # Repaint an existing right prompt.
if test "$_omp_new_prompt" = false if test "$_omp_new_prompt" = false
echo -n "$_omp_current_rprompt" echo -n "$_omp_current_rprompt"
return return
end end
set _omp_new_prompt false 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" echo -n "$_omp_current_rprompt"
end end
@ -96,7 +106,7 @@ function _omp_postexec --on-event fish_postexec
end end
function _omp_preexec --on-event fish_preexec function _omp_preexec --on-event fish_preexec
if test "::FTCS_MARKS::" = true if test $_omp_ftcs_marks = 1
echo -ne "\e]133;C\a" echo -ne "\e]133;C\a"
end end
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 insert
bind -e \r -M visual bind -e \r -M visual
end end
if test -n (bind \n --user 2>/dev/null | string match -e _omp_enter_key_handler) 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 default
bind -e \n -M insert bind -e \n -M insert
bind -e \n -M visual bind -e \n -M visual
end end
if test -n (bind \cc --user 2>/dev/null | string match -e _omp_ctrl_c_key_handler) 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 default
bind -e \cc -M insert bind -e \cc -M insert
bind -e \cc -M visual bind -e \cc -M visual
end end
if test -n (bind \x20 --user 2>/dev/null | string match -e _omp_space_key_handler) 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 default
bind -e \x20 -M insert bind -e \x20 -M insert
@ -127,23 +140,28 @@ end
function _omp_space_key_handler function _omp_space_key_handler
commandline --function expand-abbr commandline --function expand-abbr
commandline --insert ' ' commandline --insert ' '
# Get the first word of command line as tip. # 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) set --local tooltip_command (commandline --current-buffer | string trim -l | string split --allow-empty -f1 ' ' | string collect)
# Ignore an empty/repeated tooltip command. # Ignore an empty/repeated tooltip command.
if test -z "$tooltip_command" || test "$tooltip_command" = "$_omp_tooltip_command" if test -z "$tooltip_command" || test "$tooltip_command" = "$_omp_tooltip_command"
return return
end end
set _omp_tooltip_command $tooltip_command 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" if test -z "$tooltip_prompt"
return return
end end
# Save the tooltip prompt to avoid unnecessary CLI calls. # Save the tooltip prompt to avoid unnecessary CLI calls.
set _omp_current_rprompt $tooltip_prompt set _omp_current_rprompt $tooltip_prompt
commandline --function repaint commandline --function repaint
end end
if test "::TOOLTIPS::" = true function enable_poshtooltips
bind \x20 _omp_space_key_handler -M default bind \x20 _omp_space_key_handler -M default
bind \x20 _omp_space_key_handler -M insert bind \x20 _omp_space_key_handler -M insert
end end
@ -155,14 +173,17 @@ function _omp_enter_key_handler
commandline --function accept-autosuggestion commandline --function accept-autosuggestion
return return
end end
if commandline --is-valid || test -z (commandline --current-buffer | string trim -l | string collect) if commandline --is-valid || test -z (commandline --current-buffer | string trim -l | string collect)
set _omp_new_prompt true set _omp_new_prompt true
set _omp_tooltip_command '' set _omp_tooltip_command ''
if test "::TRANSIENT::" = true
if test $_omp_transient_prompt = 1
set _omp_transient true set _omp_transient true
commandline --function repaint commandline --function repaint
end end
end end
commandline --function execute commandline --function execute
end end
@ -170,13 +191,16 @@ function _omp_ctrl_c_key_handler
if test -z (commandline --current-buffer | string collect) if test -z (commandline --current-buffer | string collect)
return return
end end
# Render a transient prompt on Ctrl-C with non-empty command line buffer. # Render a transient prompt on Ctrl-C with non-empty command line buffer.
set _omp_new_prompt true set _omp_new_prompt true
set _omp_tooltip_command '' set _omp_tooltip_command ''
if test "::TRANSIENT::" = true
if test $_omp_transient_prompt = 1
set _omp_transient true set _omp_transient true
commandline --function repaint commandline --function repaint
end end
commandline --function cancel-commandline commandline --function cancel-commandline
commandline --function repaint commandline --function repaint
end end
@ -192,17 +216,6 @@ bind \cc _omp_ctrl_c_key_handler -M insert
bind \cc _omp_ctrl_c_key_handler -M visual bind \cc _omp_ctrl_c_key_handler -M visual
# legacy functions # legacy functions
function enable_poshtooltips
return
end
function enable_poshtransientprompt function enable_poshtransientprompt
return return
end end
if test "::UPGRADE::" = true
echo "::UPGRADENOTICE::"
end
if test "::AUTOUPGRADE::" = true
::OMP:: upgrade
end

View file

@ -39,8 +39,8 @@ end
local endedit_time = 0 local endedit_time = 0
local last_duration = 0 local last_duration = 0
local tooltips_enabled = ::TOOLTIPS:: local rprompt_enabled = false
local rprompt_enabled = ::RPROMPT:: local transient_enabled = false
local no_exit_code = true local no_exit_code = true
local cached_prompt = {} local cached_prompt = {}
@ -260,20 +260,29 @@ function p:filter(prompt)
return cached_prompt.left return cached_prompt.left
end end
function p:rightfilter(prompt) function p:rightfilter(prompt)
-- Return cached tooltip if available, otherwise return cached rprompt. -- Return cached tooltip if available, otherwise return cached rprompt.
-- Returning false as the second return value halts further prompt -- Returning false as the second return value halts further prompt
-- filtering, to keep other things from overriding what we generated. -- filtering, to keep other things from overriding what we generated.
return (cached_prompt.tooltip or cached_prompt.right), false return (cached_prompt.tooltip or cached_prompt.right), false
end end
function p:transientfilter(prompt) 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()) 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) prompt = run_posh_command(prompt_exe)
if prompt == "" then if prompt == "" then
prompt = nil prompt = nil
end end
return prompt return prompt
end end
function p:transientrightfilter(prompt) function p:transientrightfilter(prompt)
return "", false return "", false
end end
@ -323,11 +332,10 @@ function ohmyposh_space(rl_buffer)
end end
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') rl.setbinding(' ', [["luafunc:ohmyposh_space"]], 'emacs')
end end
if '::AUTOUPGRADE::' == 'true' then
local prompt_exe = string.format('%s upgrade', omp_exe())
os.execute(prompt_exe)
end

View file

@ -9,6 +9,8 @@ $env.PROMPT_INDICATOR = ""
$env.POSH_PID = (random uuid) $env.POSH_PID = (random uuid)
$env.POSH_SHELL_VERSION = (version | get version) $env.POSH_SHELL_VERSION = (version | get version)
let _omp_executable: string = ::OMP::
def posh_cmd_duration [] { def posh_cmd_duration [] {
# We have to do this because the initial value of `$env.CMD_DURATION_MS` is always `0823`, # We have to do this because the initial value of `$env.CMD_DURATION_MS` is always `0823`,
# which is an official setting. # which is an official setting.
@ -21,7 +23,7 @@ def posh_width [] {
} }
# PROMPTS # 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 = { || $env.PROMPT_COMMAND = { ||
# hack to set the cursor line to 1 when the user clears the screen # 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 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 = { || $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)" ^$_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)"
}
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
} }

View file

@ -13,6 +13,13 @@ function global:Get-PoshStackCount {
return 0 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 { New-Module -Name "oh-my-posh-core" -ScriptBlock {
# Check `ConstrainedLanguage` mode. # Check `ConstrainedLanguage` mode.
$script:ConstrainedLanguageMode = $ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage" $script:ConstrainedLanguageMode = $ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage"
@ -25,11 +32,12 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
$script:NoExitCode = $true $script:NoExitCode = $true
$script:ErrorCode = 0 $script:ErrorCode = 0
$script:ExecutionTime = 0 $script:ExecutionTime = 0
$script:OMPExecutable = ::OMP::
$script:ShellName = "::SHELL::" $script:ShellName = "::SHELL::"
$script:PSVersion = $PSVersionTable.PSVersion.ToString() $script:PSVersion = $PSVersionTable.PSVersion.ToString()
$script:TransientPrompt = $false $script:TransientPrompt = $false
$script:TooltipCommand = '' $script:TooltipCommand = ''
$script:JobCount = 0
$env:POWERLINE_COMMAND = "oh-my-posh" $env:POWERLINE_COMMAND = "oh-my-posh"
$env:POSH_SHELL_VERSION = $script:PSVersion $env:POSH_SHELL_VERSION = $script:PSVersion
$env:POSH_PID = $PID $env:POSH_PID = $PID
@ -40,25 +48,6 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
$env:POSH_THEME = (Resolve-Path -Path ::CONFIG::).ProviderPath $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 { function Start-Utf8Process {
param( param(
[string]$FileName, [string]$FileName,
@ -94,6 +83,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
} }
$StartInfo.Arguments = $escapedArgs -join ' ' $StartInfo.Arguments = $escapedArgs -join ' '
} }
$StartInfo.StandardErrorEncoding = $StartInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8 $StartInfo.StandardErrorEncoding = $StartInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8
$StartInfo.RedirectStandardError = $StartInfo.RedirectStandardInput = $StartInfo.RedirectStandardOutput = $true $StartInfo.RedirectStandardError = $StartInfo.RedirectStandardInput = $StartInfo.RedirectStandardOutput = $true
$StartInfo.UseShellExecute = $false $StartInfo.UseShellExecute = $false
@ -106,6 +96,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
} }
$StartInfo.WorkingDirectory = $PWD.ProviderPath $StartInfo.WorkingDirectory = $PWD.ProviderPath
} }
$StartInfo.CreateNoWindow = $true $StartInfo.CreateNoWindow = $true
[void]$Process.Start() [void]$Process.Start()
@ -118,6 +109,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
if ($stderr) { if ($stderr) {
$Host.UI.WriteErrorLine($stderr) $Host.UI.WriteErrorLine($stderr)
} }
$stdoutTask.Result $stdoutTask.Result
} }
@ -140,68 +132,61 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
$terminalWidth $terminalWidth
} }
if (!$script:ConstrainedLanguageMode) { function Enable-PoshTooltips {
if ('::TOOLTIPS::' -eq 'true') { if ($script:ConstrainedLanguageMode) {
Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock { return
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 Set-TransientPrompt { Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock {
$previousOutputEncoding = [Console]::OutputEncoding param([ConsoleKeyInfo]$key)
[Microsoft.PowerShell.PSConsoleReadLine]::SelfInsert($key)
try { try {
$script:TransientPrompt = $true $command = ''
[Console]::OutputEncoding = [Text.Encoding]::UTF8 [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)
[Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() # Get the first word of command line as tip.
} $command = $command.TrimStart().Split(' ', 2) | Select-Object -First 1
finally {
[Console]::OutputEncoding = $previousOutputEncoding # 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 { Set-PSReadLineKeyHandler -Key Enter -BriefDescription 'OhMyPoshEnterKeyHandler' -ScriptBlock {
@ -212,19 +197,18 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
if ($executingCommand) { if ($executingCommand) {
$script:newPrompt = $true $script:newPrompt = $true
$script:TooltipCommand = '' $script:TooltipCommand = ''
if ('::TRANSIENT::' -eq 'true') { Set-TransientPrompt
Set-TransientPrompt
}
} }
} }
finally { finally {
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() [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 FTCS_COMMAND_EXECUTED after accepting the input - it should still happen before execution
Write-Host "$([char]0x1b)]133;C`a" -NoNewline Write-Host "$([char]0x1b)]133;C`a" -NoNewline
} }
} }
} }
Set-PSReadLineKeyHandler -Key Ctrl+c -BriefDescription 'OhMyPoshCtrlCKeyHandler' -ScriptBlock { Set-PSReadLineKeyHandler -Key Ctrl+c -BriefDescription 'OhMyPoshCtrlCKeyHandler' -ScriptBlock {
try { try {
$start = $null $start = $null
@ -233,9 +217,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
if ($start -eq -1) { if ($start -eq -1) {
$script:newPrompt = $true $script:newPrompt = $true
$script:TooltipCommand = '' $script:TooltipCommand = ''
if ('::TRANSIENT::' -eq 'true') { Set-TransientPrompt
Set-TransientPrompt
}
} }
} }
finally { finally {
@ -244,9 +226,9 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
} }
} }
if ("::ERROR_LINE::" -eq "true") { function Enable-PoshLineError {
$validLine = (Start-Utf8Process $script:OMPExecutable @("print", "valid", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n" $validLine = (Start-Utf8Process $global:_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" $errorLine = (Start-Utf8Process $global:_ompExecutable @("print", "error", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n"
Set-PSReadLineOption -PromptText $validLine, $errorLine Set-PSReadLineOption -PromptText $validLine, $errorLine
} }
@ -285,7 +267,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
$Format = 'json' $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 no path, copy to clipboard by default
if ($FilePath) { if ($FilePath) {
# https://stackoverflow.com/questions/3038337/powershell-resolve-path-that-might-not-exist # 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)] [Parameter(ValuefromPipeline = $True)]
[string]$name [string]$name
) )
$esc = [char]27 $esc = [char]27
if (!$name) { if (!$name) {
# if name not set, uri is used as the name of the hyperlink # if name not set, uri is used as the name of the hyperlink
$name = $uri $name = $uri
} }
if ($null -ne $env:WSL_DISTRO_NAME) { if ($null -ne $env:WSL_DISTRO_NAME) {
# wsl conversion if needed # wsl conversion if needed
$uri = &wslpath -m $uri $uri = &wslpath -m $uri
} }
# return an ANSI formatted hyperlink # return an ANSI formatted hyperlink
return "$esc]8;;file://$uri$esc\$name$esc]8;;$esc\" 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 $cleanPSWD = Get-CleanPSWD
$themes | ForEach-Object -Process { $themes | ForEach-Object -Process {
Write-Host "Theme: $(Get-FileHyperlink -uri $_.FullName -Name ($_.BaseName -replace '\.omp$', ''))`n" 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" Write-Host "`n"
} }
} }
@ -374,6 +359,7 @@ Example:
$script:TransientPrompt = $false $script:TransientPrompt = $false
return return
} }
# for details about the trick to detect a debugging context, see these comments: # 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 # 1) https://github.com/JanDeDobbeleer/oh-my-posh/issues/2483#issuecomment-1175761456
# 2) https://github.com/JanDeDobbeleer/oh-my-posh/issues/2502#issuecomment-1179968052 # 2) https://github.com/JanDeDobbeleer/oh-my-posh/issues/2502#issuecomment-1179968052
@ -382,18 +368,35 @@ Example:
$script:PromptType = "debug" $script:PromptType = "debug"
return return
} }
$script:PromptType = "primary" $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 { function Update-PoshErrorCode {
$lastHistory = Get-History -ErrorAction Ignore -Count 1 $lastHistory = Get-History -ErrorAction Ignore -Count 1
# error code should be updated only when a non-empty command is run # error code should be updated only when a non-empty command is run
if (($null -eq $lastHistory) -or ($script:LastHistoryId -eq $lastHistory.Id)) { if (($null -eq $lastHistory) -or ($script:LastHistoryId -eq $lastHistory.Id)) {
$script:ExecutionTime = 0 $script:ExecutionTime = 0
$script:NoExitCode = $true $script:NoExitCode = $true
return return
} }
$script:NoExitCode = $false $script:NoExitCode = $false
$script:LastHistoryId = $lastHistory.Id $script:LastHistoryId = $lastHistory.Id
$script:ExecutionTime = ($lastHistory.EndExecutionTime - $lastHistory.StartExecutionTime).TotalMilliseconds $script:ExecutionTime = ($lastHistory.EndExecutionTime - $lastHistory.StartExecutionTime).TotalMilliseconds
@ -401,16 +404,19 @@ Example:
$script:ErrorCode = 0 $script:ErrorCode = 0
return return
} }
$invocationInfo = try { $invocationInfo = try {
# retrieve info of the most recent error # retrieve info of the most recent error
$global:Error[0] | Where-Object { $_ -ne $null } | Select-Object -ExpandProperty InvocationInfo $global:Error[0] | Where-Object { $_ -ne $null } | Select-Object -ExpandProperty InvocationInfo
} }
catch { $null } catch { $null }
# check if the last command caused the last error # check if the last command caused the last error
if ($null -ne $invocationInfo -and $lastHistory.CommandLine -eq $invocationInfo.Line) { if ($null -ne $invocationInfo -and $lastHistory.CommandLine -eq $invocationInfo.Line) {
$script:ErrorCode = 1 $script:ErrorCode = 1
return return
} }
if ($script:OriginalLastExitCode -is [int] -and $script:OriginalLastExitCode -ne 0) { if ($script:OriginalLastExitCode -is [int] -and $script:OriginalLastExitCode -ne 0) {
# native app exit code # native app exit code
$script:ErrorCode = $script:OriginalLastExitCode $script:ErrorCode = $script:OriginalLastExitCode
@ -432,35 +438,19 @@ Example:
Set-PoshPromptType Set-PoshPromptType
if ($script:PromptType -ne 'transient') { if ($script:PromptType -ne 'transient') {
Update-PoshErrorCode Update-PoshErrorCode
} }
$cleanPSWD = Get-CleanPSWD $cleanPSWD = Get-CleanPSWD
$stackCount = global:Get-PoshStackCount $stackCount = global:Get-PoshStackCount
Set-PoshContext
$terminalWidth = Get-TerminalWidth $terminalWidth = Get-TerminalWidth
# set the cursor positions, they are zero based so align with other platforms # 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_LINE = $Host.UI.RawUI.CursorPosition.Y + 1
$env:POSH_CURSOR_COLUMN = $Host.UI.RawUI.CursorPosition.X + 1 $env:POSH_CURSOR_COLUMN = $Host.UI.RawUI.CursorPosition.X + 1
$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")
"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
# make sure PSReadLine knows if we have a multiline prompt # make sure PSReadLine knows if we have a multiline prompt
Set-PSReadLineOption -ExtraPromptLineCount (($standardOut | Measure-Object -Line).Lines - 1) Set-PSReadLineOption -ExtraPromptLineCount (($standardOut | Measure-Object -Line).Lines - 1)
@ -477,33 +467,32 @@ Example:
$Function:prompt = $promptFunction $Function:prompt = $promptFunction
# set secondary prompt # set secondary prompt
Set-PSReadLineOption -ContinuationPrompt ((Start-Utf8Process $script:OMPExecutable @("print", "secondary", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n") Set-PSReadLineOption -ContinuationPrompt ((Start-Utf8Process $global:_ompExecutable @("print", "secondary", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n")
# legacy functions
function Enable-PoshTooltips {}
function Enable-PoshTransientPrompt {}
function Enable-PoshLineError {}
# perform cleanup on removal so a new initialization in current session works # perform cleanup on removal so a new initialization in current session works
if (!$script:ConstrainedLanguageMode) { if (!$script:ConstrainedLanguageMode) {
$ExecutionContext.SessionState.Module.OnRemove += { $ExecutionContext.SessionState.Module.OnRemove += {
Remove-Item Function:Get-PoshStackCount Remove-Item Function:Get-PoshStackCount
$Function:prompt = $script:OriginalPromptFunction $Function:prompt = $script:OriginalPromptFunction
(Get-PSReadLineOption).ContinuationPrompt = $script:OriginalContinuationPrompt (Get-PSReadLineOption).ContinuationPrompt = $script:OriginalContinuationPrompt
(Get-PSReadLineOption).PromptText = $script:OriginalPromptText (Get-PSReadLineOption).PromptText = $script:OriginalPromptText
if ((Get-PSReadLineKeyHandler Spacebar).Function -eq 'OhMyPoshSpaceKeyHandler') { if ((Get-PSReadLineKeyHandler Spacebar).Function -eq 'OhMyPoshSpaceKeyHandler') {
Remove-PSReadLineKeyHandler Spacebar Remove-PSReadLineKeyHandler Spacebar
} }
if ((Get-PSReadLineKeyHandler Enter).Function -eq 'OhMyPoshEnterKeyHandler') { if ((Get-PSReadLineKeyHandler Enter).Function -eq 'OhMyPoshEnterKeyHandler') {
Set-PSReadLineKeyHandler Enter -Function AcceptLine Set-PSReadLineKeyHandler Enter -Function AcceptLine
} }
if ((Get-PSReadLineKeyHandler Ctrl+c).Function -eq 'OhMyPoshCtrlCKeyHandler') { if ((Get-PSReadLineKeyHandler Ctrl+c).Function -eq 'OhMyPoshCtrlCKeyHandler') {
Set-PSReadLineKeyHandler Ctrl+c -Function CopyOrCancelLine Set-PSReadLineKeyHandler Ctrl+c -Function CopyOrCancelLine
} }
} }
} }
$notice = Start-Utf8Process $script:OMPExecutable @("notice") $notice = Start-Utf8Process $global:_ompExecutable @("notice")
if ($notice) { if ($notice) {
Write-Host $notice -NoNewline Write-Host $notice -NoNewline
} }
@ -519,8 +508,3 @@ Example:
"prompt" "prompt"
) )
} | Import-Module -Global } | Import-Module -Global
if ("::AUTOUPGRADE::" -eq "true") {
& ::OMP:: upgrade
}

View file

@ -4,6 +4,7 @@ $POWERLINE_COMMAND = "oh-my-posh"
$POSH_THEME = r"::CONFIG::" $POSH_THEME = r"::CONFIG::"
$POSH_PID = uuid.uuid4().hex $POSH_PID = uuid.uuid4().hex
$POSH_SHELL_VERSION = $XONSH_VERSION $POSH_SHELL_VERSION = $XONSH_VERSION
$POSH_EXECUTABLE = r"::OMP::"
def get_command_context(): def get_command_context():
last_cmd = __xonsh__.history[-1] if __xonsh__.history else None last_cmd = __xonsh__.history[-1] if __xonsh__.history else None
@ -13,20 +14,12 @@ def get_command_context():
def posh_primary(): def posh_primary():
status, duration = get_command_context() 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(): def posh_right():
status, duration = get_command_context() 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 $PROMPT = posh_primary
$RIGHT_PROMPT = posh_right $RIGHT_PROMPT = posh_right
notice = """::UPGRADENOTICE::"""
if "::UPGRADE::" == "true":
print(notice)
if "::AUTOUPGRADE::" == "true":
::OMP:: upgrade

View file

@ -1,15 +1,14 @@
setenv POWERLINE_COMMAND "oh-my-posh"; setenv POWERLINE_COMMAND "oh-my-posh";
setenv POSH_THEME "::CONFIG::"; setenv POSH_THEME ::CONFIG::;
setenv POSH_SHELL_VERSION ""; setenv POSH_SHELL_VERSION "";
set POSH_COMMAND = ::OMP::;
set USER_PRECMD = "`alias precmd`"; set USER_PRECMD = "`alias precmd`";
set USER_POSTCMD = "`alias postcmd`"; 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_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 = `::OMP:: get millis`'; set POSH_POSTCMD = 'set POSH_START_TIME = `$POSH_COMMAND get millis`';
alias precmd "$POSH_PRECMD;$USER_PRECMD"; alias precmd "$POSH_PRECMD;$USER_PRECMD";
alias postcmd "$POSH_POSTCMD;$USER_POSTCMD"; alias postcmd "$POSH_POSTCMD;$USER_POSTCMD";
set POSH_START_TIME = `::OMP:: get millis`;
if ("::UPGRADE::" == "true") echo "::UPGRADENOTICE::"; set POSH_START_TIME = `$POSH_COMMAND get millis`;
if ("::AUTOUPGRADE::" == "true") ::OMP:: upgrade;

View file

@ -6,13 +6,19 @@ export CONDA_PROMPT_MODIFIER=false
export POSH_PROMPT_COUNT=0 export POSH_PROMPT_COUNT=0
export ZLE_RPROMPT_INDENT=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 # 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() { function _omp_set_cursor_position() {
# not supported in Midnight Commander # not supported in Midnight Commander
# see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3415 # 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 return
fi fi
@ -37,11 +43,11 @@ function set_poshcontext() {
} }
function _omp_preexec() { function _omp_preexec() {
if [[ "::FTCS_MARKS::" = "true" ]]; then if [[ $_omp_ftcs_marks == 0 ]]; then
printf "\033]133;C\007" printf "\033]133;C\007"
fi fi
_omp_start_time=$(::OMP:: get millis) _omp_start_time=$(${_omp_executable} get millis)
} }
function _omp_precmd() { function _omp_precmd() {
@ -52,7 +58,7 @@ function _omp_precmd() {
_omp_no_exit_code="true" _omp_no_exit_code="true"
if [ $_omp_start_time ]; then 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_elapsed=$(($omp_now - $_omp_start_time))
_omp_no_exit_code="false" _omp_no_exit_code="false"
fi fi
@ -67,7 +73,7 @@ function _omp_precmd() {
set_poshcontext set_poshcontext
_omp_set_cursor_position _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 unset _omp_start_time
} }
@ -110,7 +116,7 @@ function _omp_render_tooltip() {
fi fi
_omp_tooltip_command="$tooltip_command" _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 if [[ -z "$tooltip" ]]; then
return return
fi fi
@ -129,7 +135,7 @@ function _omp_zle-line-init() {
(( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2] (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2]
_omp_tooltip_command='' _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 zle .reset-prompt
# Exit the shell if we receive EOT. # Exit the shell if we receive EOT.
@ -187,19 +193,3 @@ function _omp_create_widget() {
# legacy functions # legacy functions
function enable_poshtooltips() {} function enable_poshtooltips() {}
function enable_poshtransientprompt() {} 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

21
src/shell/tcsh.go Normal file
View file

@ -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 ""
}
}

17
src/shell/tcsh_test.go Normal file
View file

@ -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)
}

21
src/shell/xonsh.go Normal file
View file

@ -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 ""
}
}

17
src/shell/xonsh_test.go Normal file
View file

@ -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)
}

29
src/shell/zsh.go Normal file
View file

@ -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 ""
}
}

21
src/shell/zsh_test.go Normal file
View file

@ -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)
}

View file

@ -43,6 +43,7 @@ var (
"Templates", "Templates",
"Var", "Var",
"Data", "Data",
"Jobs",
} }
shell string shell string