Repository: JanDeDobbeleer/oh-my-posh
Pull request #5614 (2024-09-14 08:46:19)

Bug fixes, refactoring and documentation revision for supported shells
### Prerequisites

- [x] I have read and understood the [contributing guide][CONTRIBUTING.md].
- [x] The commit message follows the [conventional commits][cc] guidelines.
- [x] Tests for the changes have been added (for bug fixes or features).
- [x] Docs have been added or updated (for bug fixes or features).

### Description

@JanDeDobbeleer Really a bunch of changes. Appreciate your patience in reviewing. :)

- Add quotes to the Tcsh `eval` commands mentioned in the documentation since they are required for the initialization to work.
- Add coding styles for Lua (basically just for the *omp.lua* file) to EditorConfig.
- Improve initialization for all supported shells by correcting string quoting and reorganizing initialization scripts (which also improves maintainability).
- Escape special characters correctly for a prompt in Tcsh.
- Hide deprecated/internal CLI subcommands and flags from help text. (Related: #2204)
- Pass a CLI flag (`--save-cache`) explicitly to tell the OMP engine to save updated cache to file.

About the change for cache saving: this is to eliminate any underlying side effects caused by unwanted cache update. Say, when running `oh-my-posh print primary` command manually for testing purposes during development, it's unnecessary and inappropriate to update the session cache. A case can be that the prompt count gets an unwanted (extra) increment of 1, and the update is saved to the cache file. That way the prompt count in the session is messed up.

[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md
[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary

JanDeDobbeleer: @lewis-yeung can you do me a favour and split this one commit into multiple? There's a lot going on here :-)
lewis-yeung: @JanDeDobbeleer I don't have a macOS environment to test some changes. Could you please do me a favor on macOS and check whether the right prompt in Elvish reaches the rightmost cell on the terminal screen?
JanDeDobbeleer: @lewis-yeung it does

Patch:
diff --git a/.editorconfig b/.editorconfig
index 3ec5e57c..6cde72b1 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -32,3 +32,17 @@ trim_trailing_whitespace = false
 [*.{ps1,psd1,psm1}]
 indent_size = 4
 charset = utf-8-bom
+
+; Lua
+[*.lua]
+line_space_after_comment = max(2)
+line_space_after_do_statement = max(2)
+line_space_after_expression_statement = max(2)
+line_space_after_for_statement = max(2)
+line_space_after_function_statement = fixed(2)
+line_space_after_if_statement = max(2)
+line_space_after_local_or_assign_statement = max(2)
+line_space_after_repeat_statement = max(2)
+line_space_after_while_statement = max(2)
+max_line_length = unset
+quote_style = single
diff --git a/src/cache/cache.go b/src/cache/cache.go
index 9eaf5c9c..e558247b 100644
--- a/src/cache/cache.go
+++ b/src/cache/cache.go
@@ -10,7 +10,7 @@ import (
 )
 
 type Cache interface {
-	Init(home string)
+	Init(filePath string, persist bool)
 	Close()
 	// Gets the value for a given key.
 	// Returns the value and a boolean indicating if the key was found.
@@ -27,9 +27,9 @@ const (
 	FileName = "omp.cache"
 )
 
-var SessionFileName = fmt.Sprintf("%s.%s", FileName, pid())
+var SessionFileName = fmt.Sprintf("%s.%s", FileName, sessionID())
 
-func pid() string {
+func sessionID() string {
 	pid := os.Getenv("POSH_PID")
 	if len(pid) == 0 {
 		log.Debug("POSH_PID not set, using process pid")
diff --git a/src/cache/file.go b/src/cache/file.go
index 8f66f7a7..fe64185c 100644
--- a/src/cache/file.go
+++ b/src/cache/file.go
@@ -13,13 +13,15 @@ type File struct {
 	cache         *maps.Concurrent
 	cacheFilePath string
 	dirty         bool
+	persist       bool
 }
 
-func (fc *File) Init(cacheFilePath string) {
+func (fc *File) Init(cacheFilePath string, persist bool) {
 	defer log.Trace(time.Now(), cacheFilePath)
 
 	fc.cache = maps.NewConcurrent()
 	fc.cacheFilePath = cacheFilePath
+	fc.persist = persist
 
 	log.Debug("loading cache file:", fc.cacheFilePath)
 
@@ -47,14 +49,14 @@ func (fc *File) Init(cacheFilePath string) {
 }
 
 func (fc *File) Close() {
-	if !fc.dirty {
+	if !fc.persist || !fc.dirty {
 		return
 	}
 
 	cache := fc.cache.ToSimple()
 
 	if dump, err := json.MarshalIndent(cache, "", "    "); err == nil {
-		_ = os.WriteFile(fc.cacheFilePath, dump, 0644)
+		_ = os.WriteFile(fc.cacheFilePath, dump, 0o644)
 	}
 }
 
diff --git a/src/cache/mock/cache.go b/src/cache/mock/cache.go
index 774cf194..1f8fdaca 100644
--- a/src/cache/mock/cache.go
+++ b/src/cache/mock/cache.go
@@ -2,17 +2,18 @@ package mock
 
 import mock "github.com/stretchr/testify/mock"
 
-// Cache is an autogenerated mock type for the cache type
 type Cache struct {
 	mock.Mock
 }
 
-// close provides a mock function with given fields:
+func (_m *Cache) Init(filePath string, persist bool) {
+	_m.Called(filePath, persist)
+}
+
 func (_m *Cache) Close() {
 	_m.Called()
 }
 
-// get provides a mock function with given fields: key
 func (_m *Cache) Get(key string) (string, bool) {
 	ret := _m.Called(key)
 
@@ -33,17 +34,10 @@ func (_m *Cache) Get(key string) (string, bool) {
 	return r0, r1
 }
 
-// init provides a mock function with given fields: home
-func (_m *Cache) Init(home string) {
-	_m.Called(home)
-}
-
-// set provides a mock function with given fields: key, value, ttl
 func (_m *Cache) Set(key, value string, ttl int) {
 	_m.Called(key, value, ttl)
 }
 
-// delete provides a mock function with given fields: key
 func (_m *Cache) Delete(key string) {
 	_m.Called(key)
 }
diff --git a/src/cli/debug.go b/src/cli/debug.go
index 85789484..aa514676 100644
--- a/src/cli/debug.go
+++ b/src/cli/debug.go
@@ -15,56 +15,68 @@ import (
 )
 
 // debugCmd represents the prompt command
-var debugCmd = &cobra.Command{
-	Use:       "debug [bash|zsh|fish|powershell|pwsh|cmd|nu|tcsh|elvish|xonsh]",
-	Short:     "Print the prompt in debug mode",
-	Long:      "Print the prompt in debug mode.",
-	ValidArgs: supportedShells,
-	Args:      NoArgsOrOneValidArg,
-	Run: func(cmd *cobra.Command, args []string) {
-		startTime := time.Now()
-
-		if len(args) == 0 {
-			_ = cmd.Help()
-			return
-		}
-
-		env := &runtime.Terminal{
-			CmdFlags: &runtime.Flags{
-				Config: configFlag,
-				Debug:  true,
-				PWD:    pwd,
-				Shell:  args[0],
-				Plain:  plain,
-			},
-		}
+var debugCmd = createDebugCmd()
 
-		env.Init()
-		defer env.Close()
+func init() {
+	RootCmd.AddCommand(debugCmd)
+}
 
-		cfg := config.Load(env)
+func createDebugCmd() *cobra.Command {
+	debugCmd := &cobra.Command{
+		Use:       "debug [bash|zsh|fish|powershell|pwsh|cmd|nu|tcsh|elvish|xonsh]",
+		Short:     "Print the prompt in debug mode",
+		Long:      "Print the prompt in debug mode.",
+		ValidArgs: supportedShells,
+		Args:      NoArgsOrOneValidArg,
+		Run: func(cmd *cobra.Command, args []string) {
+			startTime := time.Now()
 
-		// add variables to the environment
-		env.Var = cfg.Var
+			if len(args) == 0 {
+				_ = cmd.Help()
+				return
+			}
 
-		terminal.Init(shell.GENERIC)
-		terminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate(env)
-		terminal.Colors = cfg.MakeColors()
-		terminal.Plain = plain
+			env := &runtime.Terminal{
+				CmdFlags: &runtime.Flags{
+					Config: configFlag,
+					Debug:  true,
+					PWD:    pwd,
+					Shell:  args[0],
+					Plain:  plain,
+				},
+			}
 
-		eng := &prompt.Engine{
-			Config: cfg,
-			Env:    env,
-			Plain:  plain,
-		}
+			env.Init()
+			defer env.Close()
 
-		fmt.Print(eng.PrintDebug(startTime, build.Version))
-	},
-}
+			cfg := config.Load(env)
+
+			// add variables to the environment
+			env.Var = cfg.Var
+
+			terminal.Init(shell.GENERIC)
+			terminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate(env)
+			terminal.Colors = cfg.MakeColors()
+			terminal.Plain = plain
+
+			eng := &prompt.Engine{
+				Config: cfg,
+				Env:    env,
+				Plain:  plain,
+			}
+
+			fmt.Print(eng.PrintDebug(startTime, build.Version))
+		},
+	}
 
-func init() {
 	debugCmd.Flags().StringVar(&pwd, "pwd", "", "current working directory")
-	debugCmd.Flags().StringVar(&shellName, "shell", "", "the shell to print for")
 	debugCmd.Flags().BoolVarP(&plain, "plain", "p", false, "plain text output (no ANSI)")
-	RootCmd.AddCommand(debugCmd)
+
+	// Deprecated flags, should be kept to avoid breaking CLI integration.
+	debugCmd.Flags().StringVar(&shellName, "shell", "", "the shell to print for")
+
+	// Hide flags that are deprecated or for internal use only.
+	_ = debugCmd.Flags().MarkHidden("shell")
+
+	return debugCmd
 }
diff --git a/src/cli/init.go b/src/cli/init.go
index 8d465676..e8754ea8 100644
--- a/src/cli/init.go
+++ b/src/cli/init.go
@@ -30,7 +30,15 @@ var (
 		"xonsh",
 	}
 
-	initCmd = &cobra.Command{
+	initCmd = createInitCmd()
+)
+
+func init() {
+	RootCmd.AddCommand(initCmd)
+}
+
+func createInitCmd() *cobra.Command {
+	initCmd := &cobra.Command{
 		Use:   "init [bash|zsh|fish|powershell|pwsh|cmd|nu|tcsh|elvish|xonsh]",
 		Short: "Initialize your shell and config",
 		Long: `Initialize your shell and config.
@@ -46,15 +54,20 @@ See the documentation to initialize your shell: https://ohmyposh.dev/docs/instal
 			runInit(args[0])
 		},
 	}
-)
 
-func init() {
 	initCmd.Flags().BoolVarP(&printOutput, "print", "p", false, "print the init script")
 	initCmd.Flags().BoolVarP(&strict, "strict", "s", false, "run in strict mode")
-	initCmd.Flags().BoolVarP(&manual, "manual", "m", false, "enable/disable manual mode")
 	initCmd.Flags().BoolVar(&debug, "debug", false, "enable/disable debug mode")
+
+	// Deprecated flags, should be kept to avoid breaking CLI integration.
+	initCmd.Flags().BoolVarP(&manual, "manual", "m", false, "enable/disable manual mode")
+
+	// Hide flags that are deprecated or for internal use only.
+	_ = initCmd.Flags().MarkHidden("manual")
+
 	_ = initCmd.MarkPersistentFlagRequired("config")
-	RootCmd.AddCommand(initCmd)
+
+	return initCmd
 }
 
 func runInit(shellName string) {
@@ -68,7 +81,6 @@ func runInit(shellName string) {
 			Shell:  shellName,
 			Config: configFlag,
 			Strict: strict,
-			Manual: manual,
 			Debug:  debug,
 		},
 	}
diff --git a/src/cli/print.go b/src/cli/print.go
index c1e118e5..9dcdafad 100644
--- a/src/cli/print.go
+++ b/src/cli/print.go
@@ -21,6 +21,7 @@ var (
 	cleared       bool
 	cached        bool
 	jobCount      int
+	saveCache     bool
 
 	command      string
 	shellVersion string
@@ -30,74 +31,81 @@ var (
 )
 
 // printCmd represents the prompt command
-var printCmd = &cobra.Command{
-	Use:   "print [debug|primary|secondary|transient|right|tooltip|valid|error]",
-	Short: "Print the prompt/context",
-	Long:  "Print one of the prompts based on the location/use-case.",
-	ValidArgs: []string{
-		"debug",
-		"primary",
-		"secondary",
-		"transient",
-		"right",
-		"tooltip",
-		"valid",
-		"error",
-	},
-	Args: NoArgsOrOneValidArg,
-	Run: func(cmd *cobra.Command, args []string) {
-		if len(args) == 0 {
-			_ = cmd.Help()
-			return
-		}
+var printCmd = createPrintCmd()
 
-		flags := &runtime.Flags{
-			Config:        configFlag,
-			PWD:           pwd,
-			PSWD:          pswd,
-			ErrorCode:     status,
-			PipeStatus:    pipestatus,
-			ExecutionTime: timing,
-			StackCount:    stackCount,
-			TerminalWidth: terminalWidth,
-			Eval:          eval,
-			Shell:         shellName,
-			ShellVersion:  shellVersion,
-			Plain:         plain,
-			Primary:       args[0] == "primary",
-			Cleared:       cleared,
-			NoExitCode:    noStatus,
-			Column:        column,
-			JobCount:      jobCount,
-		}
+func init() {
+	RootCmd.AddCommand(printCmd)
+}
 
-		eng := prompt.New(flags)
-		defer eng.Env.Close()
+func createPrintCmd() *cobra.Command {
+	printCmd := &cobra.Command{
+		Use:   "print [debug|primary|secondary|transient|right|tooltip|valid|error]",
+		Short: "Print the prompt/context",
+		Long:  "Print one of the prompts based on the location/use-case.",
+		ValidArgs: []string{
+			"debug",
+			"primary",
+			"secondary",
+			"transient",
+			"right",
+			"tooltip",
+			"valid",
+			"error",
+		},
+		Args: NoArgsOrOneValidArg,
+		Run: func(cmd *cobra.Command, args []string) {
+			if len(args) == 0 {
+				_ = cmd.Help()
+				return
+			}
 
-		switch args[0] {
-		case "debug":
-			fmt.Print(eng.ExtraPrompt(prompt.Debug))
-		case "primary":
-			fmt.Print(eng.Primary())
-		case "secondary":
-			fmt.Print(eng.ExtraPrompt(prompt.Secondary))
-		case "transient":
-			fmt.Print(eng.ExtraPrompt(prompt.Transient))
-		case "right":
-			fmt.Print(eng.RPrompt())
-		case "tooltip":
-			fmt.Print(eng.Tooltip(command))
-		case "valid":
-			fmt.Print(eng.ExtraPrompt(prompt.Valid))
-		case "error":
-			fmt.Print(eng.ExtraPrompt(prompt.Error))
-		default:
-			_ = cmd.Help()
-		}
-	},
-}
+			flags := &runtime.Flags{
+				Config:        configFlag,
+				PWD:           pwd,
+				PSWD:          pswd,
+				ErrorCode:     status,
+				PipeStatus:    pipestatus,
+				ExecutionTime: timing,
+				StackCount:    stackCount,
+				TerminalWidth: terminalWidth,
+				Eval:          eval,
+				Shell:         shellName,
+				ShellVersion:  shellVersion,
+				Plain:         plain,
+				Primary:       args[0] == "primary",
+				Cleared:       cleared,
+				NoExitCode:    noStatus,
+				Column:        column,
+				JobCount:      jobCount,
+				SaveCache:     saveCache,
+			}
+
+			eng := prompt.New(flags)
+			defer eng.Env.Close()
+
+			switch args[0] {
+			case "debug":
+				fmt.Print(eng.ExtraPrompt(prompt.Debug))
+			case "primary":
+				fmt.Print(eng.Primary())
+			case "secondary":
+				fmt.Print(eng.ExtraPrompt(prompt.Secondary))
+			case "transient":
+				fmt.Print(eng.ExtraPrompt(prompt.Transient))
+			case "right":
+				fmt.Print(eng.RPrompt())
+			case "tooltip":
+				fmt.Print(eng.Tooltip(command))
+			case "valid":
+				fmt.Print(eng.ExtraPrompt(prompt.Valid))
+			case "error":
+				fmt.Print(eng.ExtraPrompt(prompt.Error))
+			default:
+				_ = cmd.Help()
+			}
+		},
+	}
 
-func init() {
 	printCmd.Flags().StringVar(&pwd, "pwd", "", "current working directory")
 	printCmd.Flags().StringVar(&pswd, "pswd", "", "current working directory (according to pwsh)")
 	printCmd.Flags().StringVar(&shellName, "shell", "", "the shell to print for")
@@ -114,11 +122,18 @@ func init() {
 	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")
+	printCmd.Flags().BoolVar(&saveCache, "save-cache", false, "save updated cache to file")
 
-	// Deprecated flags, keep to not break CLI integration
+	// Deprecated flags, should be kept to avoid breaking CLI integration.
 	printCmd.Flags().IntVarP(&status, "error", "e", 0, "last exit code")
 	printCmd.Flags().BoolVar(&noStatus, "no-exit-code", false, "no valid exit code (cancelled or no command yet)")
 	printCmd.Flags().BoolVar(&cached, "cached", false, "use a cached prompt")
 
-	RootCmd.AddCommand(printCmd)
+	// Hide flags that are deprecated or for internal use only.
+	_ = printCmd.Flags().MarkHidden("error")
+	_ = printCmd.Flags().MarkHidden("no-exit-code")
+	_ = printCmd.Flags().MarkHidden("cached")
+	_ = printCmd.Flags().MarkHidden("save-cache")
+
+	return printCmd
 }
diff --git a/src/cli/prompt.go b/src/cli/prompt.go
index e4c8c34e..a4b71486 100644
--- a/src/cli/prompt.go
+++ b/src/cli/prompt.go
@@ -6,10 +6,11 @@ import (
 
 // promptCmd represents the prompt command
 var promptCmd = &cobra.Command{
-	Use:   "prompt",
-	Short: "Set up the prompt for your shell (deprecated)",
-	Long:  `Set up the prompt for your shell. (deprecated)`,
-	Args:  cobra.NoArgs,
+	Use:    "prompt",
+	Short:  "Set up the prompt for your shell (deprecated)",
+	Long:   `Set up the prompt for your shell. (deprecated)`,
+	Hidden: true,
+	Args:   cobra.NoArgs,
 	Run: func(cmd *cobra.Command, _ []string) {
 		_ = cmd.Help()
 	},
@@ -17,8 +18,8 @@ var promptCmd = &cobra.Command{
 
 func init() {
 	// legacy support
-	promptCmd.AddCommand(initCmd)
-	promptCmd.AddCommand(debugCmd)
-	promptCmd.AddCommand(printCmd)
+	promptCmd.AddCommand(createInitCmd())
+	promptCmd.AddCommand(createDebugCmd())
+	promptCmd.AddCommand(createPrintCmd())
 	RootCmd.AddCommand(promptCmd)
 }
diff --git a/src/cli/root.go b/src/cli/root.go
index 7eb48899..4d4c8242 100644
--- a/src/cli/root.go
+++ b/src/cli/root.go
@@ -49,7 +49,13 @@ var (
 
 func init() {
 	RootCmd.PersistentFlags().StringVarP(&configFlag, "config", "c", "", "config file path")
-	RootCmd.Flags().BoolVarP(&initialize, "init", "i", false, "init (deprecated)")
 	RootCmd.Flags().BoolVar(&displayVersion, "version", false, "version")
-	RootCmd.Flags().StringVarP(&shellName, "shell", "s", "", "shell (deprecated)")
+
+	// Deprecated flags, should be kept to avoid breaking CLI integration.
+	RootCmd.Flags().BoolVarP(&initialize, "init", "i", false, "init")
+	RootCmd.Flags().StringVarP(&shellName, "shell", "s", "", "shell")
+
+	// Hide flags that are deprecated or for internal use only.
+	_ = RootCmd.Flags().MarkHidden("init")
+	_ = RootCmd.Flags().MarkHidden("shell")
 }
diff --git a/src/prompt/engine.go b/src/prompt/engine.go
index 01754626..9ee62ff0 100644
--- a/src/prompt/engine.go
+++ b/src/prompt/engine.go
@@ -108,17 +108,19 @@ func (e *Engine) pwd() {
 }
 
 func (e *Engine) getNewline() string {
-	// WARP terminal will remove \n from the prompt, so we hack a newline in.
+	if e.Plain || e.Env.Flags().Debug {
+		return "\n"
+	}
+
+	// Warp terminal will remove a newline character ('\n') from the prompt, so we hack it in.
 	// For Elvish, we do this to prevent cutting off a right-aligned block.
 	if e.isWarp() || e.Env.Shell() == shell.ELVISH {
 		return terminal.LineBreak()
 	}
 
-	// TCSH needs a space before the LITERAL newline character or it will not render correctly
-	// don't ask why, it be like that sometimes.
-	// https://unix.stackexchange.com/questions/99101/properly-defining-a-multi-line-prompt-in-tcsh#comment1342462_322189
+	// To avoid improper translations in Tcsh, we use an invisible word joiner character (U+2060) to separate a newline from possible preceding escape sequences.
 	if e.Env.Shell() == shell.TCSH {
-		return ` \n`
+		return "\u2060\\n"
 	}
 
 	return "\n"
@@ -506,6 +508,17 @@ func (e *Engine) adjustTrailingDiamondColorOverrides() {
 	}
 }
 
+func (e *Engine) rectifyTerminalWidth(diff int) {
+	// Since the terminal width may not be given by the CLI flag, we should always call this here.
+	_, err := e.Env.TerminalWidth()
+	if err != nil {
+		// Skip when we're unable to determine the terminal width.
+		return
+	}
+
+	e.Env.Flags().TerminalWidth += diff
+}
+
 // New returns a prompt engine initialized with the
 // given configuration options, and is ready to print any
 // of the prompt components.
@@ -532,10 +545,16 @@ func New(flags *runtime.Flags) *Engine {
 	}
 
 	switch env.Shell() {
-	case shell.ELVISH:
-		// In Elvish, a prompt line will always wrap when the cursor reaches the rightmost cell on the terminal screen.
-		// We have to reduce the terminal width by 1 so a right-aligned block will not be broken.
+	case shell.TCSH:
+		// In Tcsh, newlines in a prompt are badly translated.
+		// No silver bullet here. We have to reduce the terminal width by 1 so a right-aligned block will not be broken.
 		eng.rectifyTerminalWidth(-1)
+	case shell.ELVISH, shell.XONSH:
+		// In these shells, the behavior of wrapping at the end of a prompt line is inconsistent across platforms.
+		// On Windows, it wraps before the rightmost cell on the terminal screen, that is, the rightmost cell is never available for a prompt line.
+		if eng.Env.GOOS() == runtime.WINDOWS {
+			eng.rectifyTerminalWidth(-1)
+		}
 	case shell.PWSH, shell.PWSH5:
 		// when in PowerShell, and force patching the bleed bug
 		// we need to reduce the terminal width by 1 so the last
@@ -548,14 +567,3 @@ func New(flags *runtime.Flags) *Engine {
 
 	return eng
 }
-
-func (e *Engine) rectifyTerminalWidth(diff int) {
-	// Since the terminal width may not be given by the CLI flag, we should always call this here.
-	_, err := e.Env.TerminalWidth()
-	if err != nil {
-		// Skip when we're unable to determine the terminal width.
-		return
-	}
-
-	e.Env.Flags().TerminalWidth += diff
-}
diff --git a/src/prompt/extra.go b/src/prompt/extra.go
index 3efd077f..8dc8e984 100644
--- a/src/prompt/extra.go
+++ b/src/prompt/extra.go
@@ -101,23 +101,22 @@ func (e *Engine) ExtraPrompt(promptType ExtraPromptType) string {
 	switch e.Env.Shell() {
 	case shell.ZSH:
 		if promptType == Transient {
+			if !e.Env.Flags().Eval {
+				break
+			}
+
 			prompt := fmt.Sprintf("PS1=%s", shell.QuotePosixStr(str))
 			// empty RPROMPT
 			prompt += "\nRPROMPT=''"
 			return prompt
 		}
-		return str
 	case shell.PWSH, shell.PWSH5:
 		if promptType == Transient {
 			// clear the line afterwards to prevent text from being written on the same line
 			// see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3628
 			return str + terminal.ClearAfter()
 		}
-
-		return str
-	case shell.CMD, shell.BASH, shell.FISH, shell.NU, shell.GENERIC:
-		return str
 	}
 
-	return ""
+	return str
 }
diff --git a/src/runtime/environment.go b/src/runtime/environment.go
index 408382b1..d1e6e79c 100644
--- a/src/runtime/environment.go
+++ b/src/runtime/environment.go
@@ -68,7 +68,6 @@ type Environment interface {
 	Connection(connectionType ConnectionType) (*Connection, error)
 	TemplateCache() *cache.Template
 	LoadTemplateCache()
-	SetPromptCount()
 	CursorPosition() (row, col int)
 	SystemInfo() (*SystemInfo, error)
 	Debug(message string)
@@ -92,7 +91,6 @@ type Flags struct {
 	TerminalWidth int
 	Strict        bool
 	Debug         bool
-	Manual        bool
 	Plain         bool
 	Primary       bool
 	HasTransient  bool
@@ -101,6 +99,7 @@ type Flags struct {
 	NoExitCode    bool
 	Column        int
 	JobCount      int
+	SaveCache     bool
 }
 
 type CommandError struct {
diff --git a/src/runtime/mock/environment.go b/src/runtime/mock/environment.go
index 49458a16..50f7d63e 100644
--- a/src/runtime/mock/environment.go
+++ b/src/runtime/mock/environment.go
@@ -281,10 +281,6 @@ func (env *Environment) DirIsWritable(path string) bool {
 	return args.Bool(0)
 }
 
-func (env *Environment) SetPromptCount() {
-	_ = env.Called()
-}
-
 func (env *Environment) CursorPosition() (int, int) {
 	args := env.Called()
 	return args.Int(0), args.Int(1)
diff --git a/src/runtime/terminal.go b/src/runtime/terminal.go
index 2c1513a0..f37cbabc 100644
--- a/src/runtime/terminal.go
+++ b/src/runtime/terminal.go
@@ -67,12 +67,13 @@ func (term *Terminal) Init() {
 
 	initCache := func(fileName string) *cache.File {
 		cache := &cache.File{}
-		cache.Init(filepath.Join(term.CachePath(), fileName))
+		cache.Init(filepath.Join(term.CachePath(), fileName), term.CmdFlags.SaveCache)
 		return cache
 	}
 
 	term.deviceCache = initCache(cache.FileName)
 	term.sessionCache = initCache(cache.SessionFileName)
+	term.setPromptCount()
 
 	term.ResolveConfigPath()
 
@@ -81,8 +82,6 @@ func (term *Terminal) Init() {
 	}
 
 	term.tmplCache = &cache.Template{}
-
-	term.SetPromptCount()
 }
 
 func (term *Terminal) ResolveConfigPath() {
@@ -737,27 +736,20 @@ func dirMatchesOneOf(dir, home, goos string, regexes []string) bool {
 	return false
 }
 
-func (term *Terminal) SetPromptCount() {
+func (term *Terminal) setPromptCount() {
 	defer term.Trace(time.Now())
 
-	countStr := os.Getenv("POSH_PROMPT_COUNT")
-	if len(countStr) > 0 {
-		// this counter is incremented by the shell
-		count, err := strconv.Atoi(countStr)
-		if err == nil {
-			term.CmdFlags.PromptCount = count
-			return
-		}
-	}
 	var count int
 	if val, found := term.Session().Get(cache.PROMPTCOUNTCACHE); found {
 		count, _ = strconv.Atoi(val)
 	}
-	// only write to cache if we're the primary prompt
+
+	// Only update the count if we're generating a primary prompt.
 	if term.CmdFlags.Primary {
 		count++
 		term.Session().Set(cache.PROMPTCOUNTCACHE, strconv.Itoa(count), 1440)
 	}
+
 	term.CmdFlags.PromptCount = count
 }
 
diff --git a/src/shell/bash.go b/src/shell/bash.go
index 48dc55cc..7c8088b2 100644
--- a/src/shell/bash.go
+++ b/src/shell/bash.go
@@ -2,7 +2,6 @@ package shell
 
 import (
 	_ "embed"
-
 	"fmt"
 	"strings"
 )
@@ -13,13 +12,13 @@ var bashInit string
 func (f Feature) Bash() Code {
 	switch f {
 	case CursorPositioning:
-		return "_omp_cursor_positioning=1"
+		return unixCursorPositioning
 	case FTCSMarks:
-		return "_omp_ftcs_marks=1"
+		return unixFTCSMarks
 	case Upgrade:
-		return `"$_omp_executable" upgrade`
+		return unixUpgrade
 	case Notice:
-		return `"$_omp_executable" notice`
+		return unixNotice
 	case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, Transient:
 		fallthrough
 	default:
@@ -32,42 +31,5 @@ func QuotePosixStr(str string) string {
 		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()
+	return fmt.Sprintf("$'%s'", strings.NewReplacer(`\`, `\\`, "'", `\'`).Replace(str))
 }
diff --git a/src/shell/cmd.go b/src/shell/cmd.go
index e4dd5ed9..359d0cd8 100644
--- a/src/shell/cmd.go
+++ b/src/shell/cmd.go
@@ -2,8 +2,6 @@ package shell
 
 import (
 	_ "embed"
-
-	"fmt"
 	"strings"
 )
 
@@ -16,23 +14,32 @@ func (f Feature) Cmd() Code {
 		return "transient_enabled = true"
 	case RPrompt:
 		return "rprompt_enabled = true"
+	case FTCSMarks:
+		return "ftcs_marks_enabled = true"
 	case Tooltips:
 		return "enable_tooltips()"
 	case Upgrade:
-		return "os.execute(string.format('%s upgrade', omp_exe()))"
+		return `os.execute(string.format('"%s" upgrade', omp_executable))`
 	case Notice:
-		return "os.execute(string.format('%s notice', omp_exe()))"
-	case PromptMark, PoshGit, Azure, LineError, Jobs, FTCSMarks, CursorPositioning:
+		return `os.execute(string.format('"%s" notice', omp_executable))`
+	case PromptMark, PoshGit, Azure, LineError, Jobs, CursorPositioning:
 		fallthrough
 	default:
 		return ""
 	}
 }
 
-func quoteLuaStr(str string) string {
+func escapeLuaStr(str string) string {
 	if len(str) == 0 {
-		return "''"
+		return str
 	}
-
-	return fmt.Sprintf("'%s'", strings.NewReplacer(`\`, `\\`, `'`, `\'`).Replace(str))
+	// We only replace a minimal set of special characters with corresponding escape sequences, without adding surrounding quotes.
+	// That way the result can be later quoted with either single or double quotes in a Lua script.
+	return strings.NewReplacer(
+		`\`, `\\`,
+		"'", `\'`,
+		`"`, `\"`,
+		"\n", `\n`,
+		"\r", `\r`,
+	).Replace(str)
 }
diff --git a/src/shell/code.go b/src/shell/code.go
index 2dd5c2f8..e907dd8b 100644
--- a/src/shell/code.go
+++ b/src/shell/code.go
@@ -4,6 +4,13 @@ import "strings"
 
 type Code string
 
+const (
+	unixFTCSMarks         Code = "_omp_ftcs_marks=1"
+	unixCursorPositioning Code = "_omp_cursor_positioning=1"
+	unixUpgrade           Code = `"$_omp_executable" upgrade`
+	unixNotice            Code = `"$_omp_executable" notice`
+)
+
 func (c Code) Indent(spaces int) Code {
 	return Code(strings.Repeat(" ", spaces) + string(c))
 }
diff --git a/src/shell/elvish.go b/src/shell/elvish.go
index 9a7b2198..ab23ff5f 100644
--- a/src/shell/elvish.go
+++ b/src/shell/elvish.go
@@ -10,9 +10,9 @@ var elvishInit string
 func (f Feature) Elvish() Code {
 	switch f {
 	case Upgrade:
-		return unixUpgrade
+		return "$_omp_executable upgrade"
 	case Notice:
-		return unixNotice
+		return "$_omp_executable notice"
 	case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, CursorPositioning, Tooltips, Transient, FTCSMarks:
 		fallthrough
 	default:
diff --git a/src/shell/fish.go b/src/shell/fish.go
index 4c8e642d..5212848c 100644
--- a/src/shell/fish.go
+++ b/src/shell/fish.go
@@ -2,7 +2,6 @@ package shell
 
 import (
 	_ "embed"
-
 	"fmt"
 	"strings"
 )
@@ -35,27 +34,6 @@ 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()
+
+	return fmt.Sprintf("'%s'", strings.NewReplacer(`\`, `\\`, "'", `\'`).Replace(str))
 }
diff --git a/src/shell/formats.go b/src/shell/formats.go
index ced0e68c..756798d5 100644
--- a/src/shell/formats.go
+++ b/src/shell/formats.go
@@ -73,6 +73,9 @@ func GetFormats(shell string) *Formats {
 			ITermPromptMark:       "%{$(iterm2_prompt_mark)%}",
 			ITermCurrentDir:       "%%{\x1b]1337;CurrentDir=%s\x07%%}",
 			ITermRemoteHost:       "%%{\x1b]1337;RemoteHost=%s@%s\x07%%}",
+			EscapeSequences: map[rune]string{
+				'%': "%%",
+			},
 		}
 	default:
 		formats = &Formats{
@@ -98,10 +101,9 @@ func GetFormats(shell string) *Formats {
 		}
 	}
 
-	if shell == ZSH {
-		formats.EscapeSequences = map[rune]string{
-			'%': "%%",
-		}
+	if shell == TCSH {
+		formats.EscapeSequences['\\'] = `\\`
+		formats.EscapeSequences['!'] = `\!`
 	}
 
 	return formats
diff --git a/src/shell/init.go b/src/shell/init.go
index 79d342d6..5338a125 100644
--- a/src/shell/init.go
+++ b/src/shell/init.go
@@ -49,10 +49,6 @@ func Init(env runtime.Environment, feats Features) string {
 			additionalParams += " --strict"
 		}
 
-		if env.Flags().Manual {
-			additionalParams += " --manual"
-		}
-
 		var command, config string
 
 		switch shell {
@@ -72,7 +68,7 @@ func Init(env runtime.Environment, feats Features) string {
 		createNuInit(env, feats)
 		return ""
 	default:
-		return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
+		return fmt.Sprintf(`echo "%s is not supported by Oh My Posh"`, shell)
 	}
 }
 
@@ -105,22 +101,24 @@ func PrintInit(env runtime.Environment, features Features, startTime *time.Time)
 		configFile = quoteFishStr(configFile)
 		script = fishInit
 	case CMD:
-		executable = quoteLuaStr(executable)
-		configFile = quoteLuaStr(configFile)
+		executable = escapeLuaStr(executable)
+		configFile = escapeLuaStr(configFile)
 		script = cmdInit
 	case NU:
 		executable = quoteNuStr(executable)
 		configFile = quoteNuStr(configFile)
 		script = nuInit
 	case TCSH:
-		executable = QuotePosixStr(executable)
-		configFile = QuotePosixStr(configFile)
+		executable = quoteCshStr(executable)
+		configFile = quoteCshStr(configFile)
 		script = tcshInit
 	case ELVISH:
 		executable = quotePwshOrElvishStr(executable)
 		configFile = quotePwshOrElvishStr(configFile)
 		script = elvishInit
 	case XONSH:
+		executable = quotePythonStr(executable)
+		configFile = quotePythonStr(configFile)
 		script = xonshInit
 	default:
 		return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
diff --git a/src/shell/nu.go b/src/shell/nu.go
index 40a5191a..7f84e261 100644
--- a/src/shell/nu.go
+++ b/src/shell/nu.go
@@ -2,7 +2,6 @@ package shell
 
 import (
 	_ "embed"
-
 	"fmt"
 	"os"
 	"path/filepath"
@@ -17,7 +16,7 @@ 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
+		return `$env.TRANSIENT_PROMPT_COMMAND = {|| _omp_get_prompt transient }`
 	case Upgrade:
 		return "^$_omp_executable upgrade"
 	case Notice:
@@ -33,12 +32,13 @@ 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)
+	f, err := os.OpenFile(initPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o755)
 	if err != nil {
 		return
 	}
diff --git a/src/shell/pwsh.go b/src/shell/pwsh.go
index 13d578c8..a3d618ed 100644
--- a/src/shell/pwsh.go
+++ b/src/shell/pwsh.go
@@ -2,7 +2,6 @@ package shell
 
 import (
 	_ "embed"
-
 	"fmt"
 	"strings"
 )
@@ -38,5 +37,9 @@ func (f Feature) Pwsh() Code {
 }
 
 func quotePwshOrElvishStr(str string) string {
+	if len(str) == 0 {
+		return "''"
+	}
+
 	return fmt.Sprintf("'%s'", strings.ReplaceAll(str, "'", "''"))
 }
diff --git a/src/shell/scripts/omp.bash b/src/shell/scripts/omp.bash
index f80379a3..dcc04b5c 100644
--- a/src/shell/scripts/omp.bash
+++ b/src/shell/scripts/omp.bash
@@ -1,6 +1,6 @@
 export POSH_THEME=::CONFIG::
 export POSH_SHELL_VERSION=$BASH_VERSION
-export POWERLINE_COMMAND="oh-my-posh"
+export POWERLINE_COMMAND='oh-my-posh'
 export POSH_PID=$$
 export CONDA_PROMPT_MODIFIER=false
 export OSTYPE=$OSTYPE
@@ -10,12 +10,12 @@ if [[ $OSTYPE =~ ^(msys|cygwin) ]]; then
 fi
 
 # global variables
-_omp_start_time=""
+_omp_start_time=''
 _omp_stack_count=0
-_omp_elapsed=-1
-_omp_no_exit_code="true"
-_omp_status_cache=0
-_omp_pipestatus_cache=0
+_omp_execution_time=-1
+_omp_no_status=true
+_omp_status=0
+_omp_pipestatus=0
 _omp_executable=::OMP::
 
 # switches to enable/disable features
@@ -26,7 +26,11 @@ _omp_ftcs_marks=0
 PS0='${_omp_start_time:0:$((_omp_start_time="$(_omp_start_timer)",0))}$(_omp_ftcs_command_start)'
 
 # set secondary prompt
-_omp_secondary_prompt=$("$_omp_executable" print secondary --shell=bash --shell-version="$BASH_VERSION")
+_omp_secondary_prompt=$(
+    "$_omp_executable" print secondary \
+        --shell=bash \
+        --shell-version="$BASH_VERSION"
+)
 
 function _omp_set_cursor_position() {
     # not supported in Midnight Commander
@@ -54,7 +58,7 @@ function _omp_start_timer() {
 
 function _omp_ftcs_command_start() {
     if [[ $_omp_ftcs_marks == 1 ]]; then
-        printf "\e]133;C\a"
+        printf '\e]133;C\a'
     fi
 }
 
@@ -63,26 +67,37 @@ function set_poshcontext() {
     return
 }
 
-function _omp_print_primary() {
-    # Avoid unexpected expansions.
+function _omp_get_primary() {
+    # Avoid unexpected expansions when we're generating the prompt below.
     shopt -u promptvars
+    trap 'shopt -s promptvars' RETURN
 
     local prompt
     if shopt -oq posix; then
         # Disable in POSIX mode.
         prompt='[NOTICE: Oh My Posh prompt is not supported in POSIX mode]\n\u@\h:\w\$ '
     else
-        prompt=$("$_omp_executable" print primary --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')
+        prompt=$(
+            "$_omp_executable" print primary \
+                --save-cache \
+                --shell=bash \
+                --shell-version="$BASH_VERSION" \
+                --status="$_omp_status" \
+                --pipestatus="${_omp_pipestatus[*]}" \
+                --no-status="$_omp_no_status" \
+                --execution-time="$_omp_execution_time" \
+                --stack-count="$_omp_stack_count" \
+                --terminal-width="${COLUMNS-0}" |
+                tr -d '\0'
+        )
     fi
     echo "${prompt@P}"
-
-    # Allow command substitution in PS0.
-    shopt -s promptvars
 }
 
-function _omp_print_secondary() {
-    # Avoid unexpected expansions.
+function _omp_get_secondary() {
+    # Avoid unexpected expansions when we're generating the prompt below.
     shopt -u promptvars
+    trap 'shopt -s promptvars' RETURN
 
     if shopt -oq posix; then
         # Disable in POSIX mode.
@@ -90,38 +105,39 @@ function _omp_print_secondary() {
     else
         echo "${_omp_secondary_prompt@P}"
     fi
-
-    # Allow command substitution in PS0.
-    shopt -s promptvars
 }
 
 function _omp_hook() {
-    _omp_status_cache=$? _omp_pipestatus_cache=("${PIPESTATUS[@]}")
+    _omp_status=$? _omp_pipestatus=("${PIPESTATUS[@]}")
 
-    if [[ ${#BP_PIPESTATUS[@]} -ge ${#_omp_pipestatus_cache[@]} ]]; then
-        _omp_pipestatus_cache=("${BP_PIPESTATUS[@]}")
+    if [[ ${#BP_PIPESTATUS[@]} -ge ${#_omp_pipestatus[@]} ]]; then
+        _omp_pipestatus=("${BP_PIPESTATUS[@]}")
     fi
 
     _omp_stack_count=$((${#DIRSTACK[@]} - 1))
 
+    _omp_execution_time=-1
     if [[ $_omp_start_time ]]; then
-        local omp_now=$("$_omp_executable" get millis --shell=bash)
-        _omp_elapsed=$((omp_now - _omp_start_time))
-        _omp_start_time=""
-        _omp_no_exit_code="false"
+        local omp_now=$("$_omp_executable" get millis)
+        _omp_execution_time=$((omp_now - _omp_start_time))
+        _omp_no_status=false
     fi
+    _omp_start_time=''
 
-    if [[ ${_omp_pipestatus_cache[-1]} != "$_omp_status_cache" ]]; then
-        _omp_pipestatus_cache=("$_omp_status_cache")
+    if [[ ${_omp_pipestatus[-1]} != "$_omp_status" ]]; then
+        _omp_pipestatus=("$_omp_status")
     fi
 
     set_poshcontext
     _omp_set_cursor_position
 
-    PS1='$(_omp_print_primary)'
-    PS2='$(_omp_print_secondary)'
+    PS1='$(_omp_get_primary)'
+    PS2='$(_omp_get_secondary)'
+
+    # Ensure that command substitution works in a prompt string.
+    shopt -s promptvars
 
-    return $_omp_status_cache
+    return $_omp_status
 }
 
 function _omp_install_hook() {
@@ -129,7 +145,7 @@ function _omp_install_hook() {
 
     local cmd
     for cmd in "${PROMPT_COMMAND[@]}"; do
-        if [[ $cmd = "_omp_hook" ]]; then
+        if [[ $cmd = _omp_hook ]]; then
             return
         fi
     done
diff --git a/src/shell/scripts/omp.elv b/src/shell/scripts/omp.elv
index cba32dcf..fa8ee776 100644
--- a/src/shell/scripts/omp.elv
+++ b/src/shell/scripts/omp.elv
@@ -1,33 +1,55 @@
 set-env POSH_PID (to-string (randint 10000000000000 10000000000000000))
 set-env POSH_THEME ::CONFIG::
-set-env POSH_SHELL_VERSION (elvish --version)
-set-env POWERLINE_COMMAND 'oh-my-posh'
+set-env POSH_SHELL_VERSION $version
+set-env POWERLINE_COMMAND oh-my-posh
 
-var _omp_error_code = 0
-var _omp_executable = ::OMP::
+var _omp_executable = (external ::OMP::)
+var _omp_status = 0
+var _omp_no_status = 1
+var _omp_execution_time = -1
+var _omp_terminal_width = ($_omp_executable get width)
+
+fn _omp-after-readline-hook {|_|
+    set _omp_execution_time = -1
+
+    # Getting the terminal width can fail inside a prompt function, so we do this here.
+    set _omp_terminal_width = ($_omp_executable get width)
+}
+
+fn _omp-after-command-hook {|m|
+    # The command execution time should not be available in the first prompt.
+    if (== $_omp_no_status 0) {
+        set _omp_execution_time = (printf %.0f (* $m[duration] 1000))
+    }
+
+    set _omp_no_status = 0
 
-fn posh-after-command-hook {|m|
     var error = $m[error]
     if (is $error $nil) {
-        set _omp_error_code = 0
+        set _omp_status = 0
     } else {
         try {
-            set _omp_error_code = $error[reason][exit-status]
+            set _omp_status = $error[reason][exit-status]
         } catch {
             # built-in commands don't have a status code.
-            set _omp_error_code = 1
+            set _omp_status = 1
         }
     }
 }
 
-set edit:after-command = [ $@edit:after-command $posh-after-command-hook~ ]
-
-set edit:prompt = {
-    var cmd-duration = (printf "%.0f" (* $edit:command-duration 1000))
-    (external $_omp_executable) print primary --shell=elvish --execution-time=$cmd-duration --status=$_omp_error_code --pwd=$pwd --shell-version=$E:POSH_SHELL_VERSION
+fn _omp_get_prompt {|type @arguments|
+    $_omp_executable print $type ^
+        --save-cache ^
+        --shell=elvish ^
+        --shell-version=$E:POSH_SHELL_VERSION ^
+        --status=$_omp_status ^
+        --no-status=$_omp_no_status ^
+        --execution-time=$_omp_execution_time ^
+        --terminal-width=$_omp_terminal_width ^
+        $@arguments
 }
 
-set edit:rprompt = {
-    var cmd-duration = (printf "%.0f" (* $edit:command-duration 1000))
-    (external $_omp_executable) print right --shell=elvish --execution-time=$cmd-duration --status=$_omp_error_code --pwd=$pwd --shell-version=$E:POSH_SHELL_VERSION
-}
+set edit:after-readline = [ $@edit:after-readline $_omp-after-readline-hook~ ]
+set edit:after-command = [ $@edit:after-command $_omp-after-command-hook~ ]
+set edit:prompt = {|| _omp_get_prompt primary }
+set edit:rprompt = {|| _omp_get_prompt right }
diff --git a/src/shell/scripts/omp.fish b/src/shell/scripts/omp.fish
index ce64f6e5..b4709cca 100644
--- a/src/shell/scripts/omp.fish
+++ b/src/shell/scripts/omp.fish
@@ -24,42 +24,58 @@ function set_poshcontext
     return
 end
 
+function _omp_get_prompt
+    if test (count $argv) -eq 0
+        return
+    end
+    $_omp_executable print $argv[1] \
+        --save-cache \
+        --shell=fish \
+        --shell-version=$FISH_VERSION \
+        --status=$_omp_status \
+        --pipestatus="$_omp_pipestatus" \
+        --no-status=$_omp_no_status \
+        --execution-time=$_omp_execution_time \
+        --stack-count=$_omp_stack_count \
+        $argv[2..]
+end
+
 # NOTE: Input function calls via `commandline --function` are put into a queue and will not be executed until an outer regular function returns. See https://fishshell.com/docs/current/cmds/commandline.html.
 
 function fish_prompt
-    set --local omp_status_cache_temp $status
-    set --local omp_pipestatus_cache_temp $pipestatus
+    set --local omp_status_temp $status
+    set --local omp_pipestatus_temp $pipestatus
     # clear from cursor to end of screen as
     # commandline --function repaint does not do this
     # see https://github.com/fish-shell/fish-shell/issues/8418
     printf \e\[0J
     if test "$_omp_transient" = 1
-        $_omp_executable print transient --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_get_prompt transient
         return
     end
     if test "$_omp_new_prompt" = 0
         echo -n "$_omp_current_prompt"
         return
     end
-    set --global _omp_status_cache $omp_status_cache_temp
-    set --global _omp_pipestatus_cache $omp_pipestatus_cache_temp
+    set --global _omp_status $omp_status_temp
+    set --global _omp_pipestatus $omp_pipestatus_temp
+    set --global _omp_no_status false
+    set --global _omp_execution_time "$CMD_DURATION$cmd_duration"
     set --global _omp_stack_count (count $dirstack)
-    set --global _omp_duration "$CMD_DURATION$cmd_duration"
-    set --global _omp_no_exit_code false
 
     # check if variable set, < 3.2 case
     if set --query _omp_last_command && test -z "$_omp_last_command"
-        set _omp_duration 0
-        set _omp_no_exit_code true
+        set _omp_execution_time 0
+        set _omp_no_status true
     end
 
     # works with fish >=3.2
     if set --query _omp_last_status_generation && test "$_omp_last_status_generation" = "$status_generation"
-        set _omp_duration 0
-        set _omp_no_exit_code true
+        set _omp_execution_time 0
+        set _omp_no_status true
     else if test -z "$_omp_last_status_generation"
         # first execution - $status_generation is 0, $_omp_last_status_generation is empty
-        set _omp_no_exit_code true
+        set _omp_no_status true
     end
 
     if set --query status_generation
@@ -81,7 +97,8 @@ function fish_prompt
     end
 
     # The prompt is saved for possible reuse, typically a repaint after clearing the screen buffer.
-    set --global _omp_current_prompt ($_omp_executable print primary --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_get_prompt primary --cleared=$omp_cleared | string join \n | string collect)
+
     echo -n "$_omp_current_prompt"
 end
 
@@ -98,7 +115,7 @@ function fish_right_prompt
     end
 
     set _omp_new_prompt 0
-    set --global _omp_current_rprompt ($_omp_executable print right --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_get_prompt right | string join '')
 
     echo -n "$_omp_current_rprompt"
 end
@@ -154,7 +171,7 @@ function _omp_space_key_handler
     end
 
     set _omp_tooltip_command $tooltip_command
-    set --local tooltip_prompt ($_omp_executable print tooltip --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_get_prompt tooltip --command=$_omp_tooltip_command | string join '')
 
     if test -z "$tooltip_prompt"
         return
diff --git a/src/shell/scripts/omp.lua b/src/shell/scripts/omp.lua
index 3cbea2f3..cd245be6 100644
--- a/src/shell/scripts/omp.lua
+++ b/src/shell/scripts/omp.lua
@@ -1,34 +1,24 @@
--- Upgrade notice
-
-local notice = [[::UPGRADENOTICE::]]
-
-if '::UPGRADE::' == 'true' then
-    print(notice)
-end
+---@diagnostic disable: undefined-global
+---@diagnostic disable: undefined-field
+---@diagnostic disable: lowercase-global
 
 -- Cache PID
-os.setenv("POSH_PID", os.getpid())
+os.setenv('POSH_PID', os.getpid())
 
 -- Helper functions
 
 local function get_priority_number(name, default)
-	local value = os.getenv(name)
-	if os.envmap ~= nil and type(os.envmap) == 'table' then
-		local t = os.envmap[name]
-		value = (t ~= nil and type(t) == 'string') and t or value
-	end
-	if type(default) == 'number' then
-		value = tonumber(value)
-		if value == nil then
-			return default
-		else
-			return value
-		end
-	else
-        return default
-	end
+    local value = os.getenv(name)
+    if value == nil and os.envmap ~= nil and type(os.envmap) == 'table' then
+        value = os.envmap[name]
+    end
+    local num = tonumber(value)
+    if num ~= nil then
+        return num
+    end
+    return default
 end
-os.setenv("POSH_CURSOR_LINE", console.getnumlines())
+
 -- Environment variables
 
 local function environment_onbeginedit()
@@ -41,6 +31,7 @@ local endedit_time = 0
 local last_duration = 0
 local rprompt_enabled = false
 local transient_enabled = false
+local ftcs_marks_enabled = false
 local no_exit_code = true
 
 local cached_prompt = {}
@@ -57,7 +48,7 @@ local function cache_onbeginedit()
     local old_cache = cached_prompt
 
     -- Start a new table for the new edit/prompt session.
-    cached_prompt = { cwd=cwd }
+    cached_prompt = { cwd = cwd }
 
     -- Copy the cached left/right prompt strings if the cwd hasn't changed.
     -- IMPORTANT OPTIMIZATION:  This keeps the prompt highly responsive, except
@@ -68,33 +59,30 @@ local function cache_onbeginedit()
     end
 end
 
--- Configuration
+-- Executable
 
-local function omp_exe()
-    return '"'..::OMP::..'"'
-end
+local omp_executable = '::OMP::'
+
+-- Configuration
 
-os.setenv("POSH_THEME", ::CONFIG::)
-os.setenv("POSH_SHELL_VERSION", string.format('clink v%s.%s.%s.%s', clink.version_major, clink.version_minor, clink.version_patch, clink.version_commit))
+os.setenv('POSH_THEME', '::CONFIG::')
+os.setenv('POSH_SHELL_VERSION', string.format('clink v%s.%s.%s.%s', clink.version_major, clink.version_minor, clink.version_patch, clink.version_commit))
 
 -- Execution helpers
 
 local function can_async()
     if (clink.version_encoded or 0) >= 10030001 then
-        return settings.get("prompt.async")
+        return settings.get('prompt.async')
     end
 end
 
 local function run_posh_command(command)
-    command = '"'..command..'"'
-    local _, ismain = coroutine.running()
-    local output
-    if ismain then
-        output = io.popen(command):read("*a")
-    else
-        output = io.popenyield(command):read("*a")
+    command = string.format('""%s" %s"', omp_executable, command)
+    local _, is_main = coroutine.running()
+    if is_main then
+        return io.popen(command):read('*a')
     end
-    return output
+    return io.popenyield(command):read('*a')
 end
 
 -- Duration functions
@@ -105,10 +93,8 @@ local function os_clock_millis()
     -- OMP to get the time in milliseconds.
     if (clink.version_encoded or 0) >= 10020030 then
         return math.floor(os.clock() * 1000)
-    else
-        local prompt_exe = string.format('%s get millis --shell=cmd', omp_exe())
-        return run_posh_command(prompt_exe)
     end
+    return run_posh_command('get millis')
 end
 
 local function duration_onbeginedit()
@@ -125,7 +111,7 @@ end
 local function duration_onendedit(input)
     endedit_time = 0
     -- For an empty command, the execution time should not be evaluated.
-    if string.gsub(input, "^%s*(.-)%s*$", "%1") ~= "" then
+    if string.gsub(input, '^%s*(.-)%s*$', '%1') ~= '' then
         endedit_time = os_clock_millis()
     end
 end
@@ -134,43 +120,48 @@ end
 
 local function execution_time_option()
     if last_duration ~= nil then
-        return "--execution-time "..last_duration
+        return '--execution-time=' .. last_duration
     end
-    return ""
+    return ''
 end
 
-local function error_level_option()
-    if os.geterrorlevel ~= nil and settings.get("cmd.get_errorlevel") then
-        return "--status "..os.geterrorlevel()
+local function status_option()
+    if os.geterrorlevel ~= nil and settings.get('cmd.get_errorlevel') then
+        return '--status=' .. os.geterrorlevel()
     end
-    return ""
+    return ''
 end
 
-local function no_exit_code_option()
+local function no_status_option()
     if no_exit_code then
-        return "--no-status"
+        return '--no-status'
     end
-    return ""
+    return ''
 end
 
-local function get_posh_prompt(rprompt)
-    local prompt = "primary"
-    if rprompt then
-        prompt = "right"
-    end
-    local prompt_exe = string.format('%s print %s --shell=cmd %s %s %s', omp_exe(), prompt, execution_time_option(), error_level_option(), no_exit_code_option())
-    return run_posh_command(prompt_exe)
+local function get_posh_prompt(prompt_type, ...)
+    os.setenv('POSH_CURSOR_LINE', console.getnumlines())
+    local command = table.concat({
+        'print',
+        prompt_type,
+        '--save-cache',
+        '--shell=cmd',
+        status_option(),
+        no_status_option(),
+        execution_time_option(),
+        ...
+    }, ' ')
+    return run_posh_command(command)
 end
 
 local function set_posh_tooltip(tip_command)
-    if tip_command ~= "" and tip_command ~= cached_prompt.tip_command then
+    if tip_command ~= '' and tip_command ~= cached_prompt.tip_command then
         -- Escape special characters properly, if any.
-        local escaped_tip_command = string.gsub(tip_command, '(\\+)"', '%1%1"'):gsub('(\\+)$', '%1%1'):gsub('"', '\\"'):gsub('([&<>%(%)@%^|])', '^%1')
-
-        local prompt_exe = string.format('%s print tooltip --shell=cmd %s --command="%s"', omp_exe(), error_level_option(), escaped_tip_command)
-        local tooltip = run_posh_command(prompt_exe)
+        local escaped_tip_command = string.gsub(tip_command, '(\\+)"', '%1%1"'):gsub('(\\+)$', '%1%1'):gsub('"', '\\"'):gsub('([&<>%(%)@|%^])', '^%1'):gsub('%%', '%%%%')
+        local command_option = string.format('--command "%s"', escaped_tip_command)
+        local tooltip = get_posh_prompt('tooltip', command_option)
         -- Do not cache an empty tooltip.
-        if tooltip == "" then
+        if tooltip == '' then
             return
         end
         cached_prompt.tip_command = tip_command
@@ -185,25 +176,10 @@ local function display_cached_prompt()
     cached_prompt.only_use_cache = nil
 end
 
-local function async_collect_posh_prompts()
-    -- Generate the left prompt.
-    cached_prompt.left = get_posh_prompt(false)
-
-    -- Generate the right prompt, if needed.
-    if rprompt_enabled then
-        display_cached_prompt() -- Show left side; don't wait for right side.
-        cached_prompt.right = get_posh_prompt(true)
-    end
-end
-
 local function command_executed_mark(input)
-    if string.gsub(input, "^%s*(.-)%s*$", "%1") ~= "" then
-        no_exit_code = false
-    else
-        no_exit_code = true
-    end
-    if "::FTCS_MARKS::" == "true" then
-        clink.print("\x1b]133;C\007", NONL)
+    no_exit_code = string.gsub(input, '^%s*(.-)%s*$', '%1') == ''
+    if ftcs_marks_enabled then
+        clink.print('\x1b]133;C\007', NONL)
     end
 end
 
@@ -216,7 +192,7 @@ function p:filter(prompt)
 
     -- Get a left prompt immediately if nothing is available yet.
     if not cached_prompt.left then
-        cached_prompt.left = get_posh_prompt(false)
+        cached_prompt.left = get_posh_prompt('primary')
         need_left = false
     end
 
@@ -228,10 +204,10 @@ function p:filter(prompt)
             -- function was defined.  That way if a new prompt starts (which
             -- discards the old coroutine) and a new coroutine starts, the old
             -- coroutine won't stomp on the new cached_prompt table.
-            clink.promptcoroutine(function ()
+            clink.promptcoroutine(function()
                 -- Generate left prompt, if needed.
                 if need_left then
-                    cached_prompt.left = get_posh_prompt(false)
+                    cached_prompt.left = get_posh_prompt('primary')
                 end
                 -- Generate right prompt, if needed.
                 if rprompt_enabled then
@@ -239,17 +215,17 @@ function p:filter(prompt)
                         -- Show left side while right side is being generated.
                         display_cached_prompt()
                     end
-                    cached_prompt.right = get_posh_prompt(true)
+                    cached_prompt.right = get_posh_prompt('right')
                 else
                     cached_prompt.right = nil
                 end
             end)
         else
             if need_left then
-                cached_prompt.left = get_posh_prompt(false)
+                cached_prompt.left = get_posh_prompt('primary')
             end
             if rprompt_enabled then
-                cached_prompt.right = get_posh_prompt(true)
+                cached_prompt.right = get_posh_prompt('right')
             end
         end
     end
@@ -269,10 +245,9 @@ function p:transientfilter(prompt)
         return nil
     end
 
-    local prompt_exe = string.format('%s print transient --shell=cmd %s %s', omp_exe(), error_level_option(), no_exit_code_option())
-    prompt = run_posh_command(prompt_exe)
+    prompt = get_posh_prompt('transient')
 
-    if prompt == "" then
+    if prompt == '' then
         prompt = nil
     end
 
@@ -280,7 +255,7 @@ function p:transientfilter(prompt)
 end
 
 function p:transientrightfilter(prompt)
-    return "", false
+    return '', false
 end
 
 -- Event handlers
@@ -303,12 +278,12 @@ end
 
 -- Tooltips
 
-function ohmyposh_space(rl_buffer)
+function _omp_space_keybinding(rl_buffer)
     -- Insert space first, in case it might affect the tip word, e.g. it could
     -- split "gitcommit" into "git commit".
-    rl_buffer:insert(" ")
+    rl_buffer:insert(' ')
     -- Get the first word of command line as tip.
-    local tip_command = rl_buffer:getbuffer():gsub("^%s*([^%s]*).*$", "%1")
+    local tip_command = rl_buffer:getbuffer():gsub('^%s*(.-)%s*$', '%1')
 
     -- Generate a tooltip asynchronously (via coroutine) if available, otherwise
     -- generate a tooltip immediately.
@@ -318,7 +293,7 @@ function ohmyposh_space(rl_buffer)
     elseif cached_prompt.coroutine then
         -- No action needed; a tooltip coroutine is already running.
     else
-        cached_prompt.coroutine = coroutine.create(function ()
+        cached_prompt.coroutine = coroutine.create(function()
             set_posh_tooltip(tip_command)
             if cached_prompt.coroutine == coroutine.running() then
                 cached_prompt.coroutine = nil
@@ -333,5 +308,5 @@ local function enable_tooltips()
         return
     end
 
-    rl.setbinding(' ', [["luafunc:ohmyposh_space"]], 'emacs')
+    rl.setbinding(' ', [["luafunc:_omp_space_keybinding"]], 'emacs')
 end
diff --git a/src/shell/scripts/omp.nu b/src/shell/scripts/omp.nu
index 963ce897..6c3fdecf 100644
--- a/src/shell/scripts/omp.nu
+++ b/src/shell/scripts/omp.nu
@@ -4,28 +4,48 @@ if ($env.config? | is-not-empty) {
 }
 
 $env.POWERLINE_COMMAND = 'oh-my-posh'
-$env.POSH_THEME = ::CONFIG::
+$env.POSH_THEME = (echo ::CONFIG::)
 $env.PROMPT_INDICATOR = ""
 $env.POSH_PID = (random uuid)
 $env.POSH_SHELL_VERSION = (version | get version)
 
-let _omp_executable: string = ::OMP::
+let _omp_executable: string = (echo ::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.
+# PROMPTS
+
+def --wrapped _omp_get_prompt [
+    type: string,
+    ...args: string
+] {
+    mut execution_time = -1
+    mut no_status = true
+    # We have to do this because the initial value of `$env.CMD_DURATION_MS` is always `0823`, which is an official setting.
     # See https://github.com/nushell/nushell/discussions/6402#discussioncomment-3466687.
-    if $env.CMD_DURATION_MS == "0823" { 0 } else { $env.CMD_DURATION_MS }
-}
+    if $env.CMD_DURATION_MS != '0823' {
+        $execution_time = $env.CMD_DURATION_MS
+        $no_status = false
+    }
 
-def posh_width [] {
-    (term size).columns | into string
+    (
+        ^$_omp_executable print $type
+            --save-cache
+            --shell=nu
+            $"--shell-version=($env.POSH_SHELL_VERSION)"
+            $"--status=($env.LAST_EXIT_CODE)"
+            $"--no-status=($no_status)"
+            $"--execution-time=($execution_time)"
+            $"--terminal-width=((term size).columns)"
+            ...$args
+    )
 }
 
-# PROMPTS
-$env.PROMPT_MULTILINE_INDICATOR = (^$_omp_executable print secondary --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)")
+$env.PROMPT_MULTILINE_INDICATOR = (
+    ^$_omp_executable print secondary
+        --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
     # this obviously isn't bulletproof, but it's a start
     mut clear = false
@@ -37,9 +57,7 @@ $env.PROMPT_COMMAND = { ||
         do --env $env.SET_POSHCONTEXT
     }
 
-    ^$_omp_executable print primary --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_get_prompt primary $"--cleared=($clear)"
 }
 
-$env.PROMPT_COMMAND_RIGHT = { ||
-    ^$_omp_executable print right --shell=nu $"--shell-version=($env.POSH_SHELL_VERSION)" $"--execution-time=(posh_cmd_duration)" $"--status=($env.LAST_EXIT_CODE)" $"--terminal-width=(posh_width)"
-}
+$env.PROMPT_COMMAND_RIGHT = {|| _omp_get_prompt right }
diff --git a/src/shell/scripts/omp.ps1 b/src/shell/scripts/omp.ps1
index 3fe9c461..62e91ea7 100644
--- a/src/shell/scripts/omp.ps1
+++ b/src/shell/scripts/omp.ps1
@@ -48,28 +48,24 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
         $env:POSH_THEME = (Resolve-Path -Path ::CONFIG::).ProviderPath
     }
 
-    function Start-Utf8Process {
-        param(
-            [string]$FileName,
-            [string[]]$Arguments = @()
-        )
+    function Invoke-Utf8Posh {
+        param([string[]]$Arguments = @())
 
         if ($script:ConstrainedLanguageMode) {
-            $standardOut = Invoke-Expression "& `$FileName `$Arguments 2>&1"
-            $standardOut -join "`n"
+            $output = Invoke-Expression "& `$global:_ompExecutable `$Arguments 2>&1"
+            $output -join "`n"
             return
         }
 
         $Process = New-Object System.Diagnostics.Process
         $StartInfo = $Process.StartInfo
-        $StartInfo.FileName = $FileName
+        $StartInfo.FileName = $global:_ompExecutable
         if ($StartInfo.ArgumentList.Add) {
             # ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)
             # ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0
             # ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core
             $Arguments | ForEach-Object -Process { $StartInfo.ArgumentList.Add($_) }
-        }
-        else {
+        } else {
             # escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
             $escapedArgs = $Arguments | ForEach-Object {
                 # escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones
@@ -113,8 +109,6 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
         $stdoutTask.Result
     }
 
-    function Set-PoshContext([bool]$originalStatus) {}
-
     function Get-NonFSWD {
         # We only need to return a non-filesystem working directory.
         if ($PWD.Provider.Name -ne 'FileSystem') {
@@ -131,6 +125,192 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
         $terminalWidth
     }
 
+    function Get-FileHyperlink {
+        param(
+            [Parameter(Mandatory, ValuefromPipeline = $True)]
+            [string]$Uri,
+            [Parameter(ValuefromPipeline = $True)]
+            [string]$Name
+        )
+
+        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 "`e]8;;file://$Uri`e\$Name`e]8;;`e\"
+    }
+
+    function Set-TransientPrompt {
+        $previousOutputEncoding = [Console]::OutputEncoding
+        try {
+            $script:TransientPrompt = $true
+            [Console]::OutputEncoding = [Text.Encoding]::UTF8
+            [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt()
+        } finally {
+            [Console]::OutputEncoding = $previousOutputEncoding
+        }
+    }
+
+    function Set-PoshPromptType {
+        if ($script:TransientPrompt -eq $true) {
+            $script:PromptType = "transient"
+            $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
+        # 3) https://github.com/JanDeDobbeleer/oh-my-posh/issues/5153
+        if ($Host.Runspace.Debugger.InBreakpoint) {
+            $script:PromptType = "debug"
+            return
+        }
+
+        $script:PromptType = "primary"
+
+        if ($global:_ompJobCount) {
+            $script:JobCount = (Get-Job -State Running).Count
+        }
+
+        if ($global:_ompAzure) {
+            try {
+                $env:POSH_AZURE_SUBSCRIPTION = Get-AzContext | ConvertTo-Json
+            } catch {}
+        }
+
+        if ($global:_ompPoshGit) {
+            try {
+                $global:GitStatus = Get-GitStatus
+                $env:POSH_GIT_STATUS = $global:GitStatus | ConvertTo-Json
+            } catch {}
+        }
+    }
+
+    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
+        if ($script:OriginalLastExecutionStatus) {
+            $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
+            return
+        }
+    }
+
+    function Get-PoshPrompt {
+        param(
+            [string]$Type,
+            [string[]]$Arguments
+        )
+        $nonFSWD = Get-NonFSWD
+        $stackCount = Get-PoshStackCount
+        $terminalWidth = Get-TerminalWidth
+        Invoke-Utf8Posh @(
+            "print", $Type
+            "--save-cache"
+            "--shell=$script:ShellName"
+            "--shell-version=$script:PSVersion"
+            "--status=$script:ErrorCode"
+            "--no-status=$script:NoExitCode"
+            "--execution-time=$script:ExecutionTime"
+            "--pswd=$nonFSWD"
+            "--stack-count=$stackCount"
+            "--terminal-width=$terminalWidth"
+            "--job-count=$script:JobCount"
+            if ($Arguments) { $Arguments }
+        )
+    }
+
+    $promptFunction = {
+        # store the orignal last command execution status
+        if ($global:NVS_ORIGINAL_LASTEXECUTIONSTATUS -is [bool]) {
+            # make it compatible with NVS auto-switching, if enabled
+            $script:OriginalLastExecutionStatus = $global:NVS_ORIGINAL_LASTEXECUTIONSTATUS
+        } else {
+            $script:OriginalLastExecutionStatus = $?
+        }
+        # store the orignal last exit code
+        $script:OriginalLastExitCode = $global:LASTEXITCODE
+
+        Set-PoshPromptType
+
+        if ($script:PromptType -ne 'transient') {
+            Update-PoshErrorCode
+        }
+
+        Set-PoshContext $script:ErrorCode
+
+        # 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
+
+        $output = Get-PoshPrompt $script:PromptType
+        # make sure PSReadLine knows if we have a multiline prompt
+        Set-PSReadLineOption -ExtraPromptLineCount (($output | Measure-Object -Line).Lines - 1)
+
+        # The output can be multi-line, joining them ensures proper rendering.
+        $output = $output -join "`n"
+
+        if ($script:PromptType -eq 'transient') {
+            # Workaround to prevent a command from eating the tail of a transient prompt, when we're at the end of the line.
+            $command = ''
+            [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)
+            if ($command) {
+                $output += "  `b`b"
+            }
+        }
+
+        $output
+
+        # remove any posh-git status
+        $env:POSH_GIT_STATUS = $null
+
+        # restore the orignal last exit code
+        $global:LASTEXITCODE = $script:OriginalLastExitCode
+    }
+
+    $Function:prompt = $promptFunction
+
+    # set secondary prompt
+    Set-PSReadLineOption -ContinuationPrompt ((Invoke-Utf8Posh @("print", "secondary", "--shell=$script:ShellName")) -join "`n")
+
+    ### Exported Functions ###
+
+    function Set-PoshContext([bool]$originalStatus) {}
+
     function Enable-PoshTooltips {
         if ($script:ConstrainedLanguageMode) {
             return
@@ -151,35 +331,21 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
                 }
 
                 $script:TooltipCommand = $command
-                $column = $Host.UI.RawUI.CursorPosition.X
-                $terminalWidth = Get-TerminalWidth
-                $nonFSWD = Get-NonFSWD
-                $stackCount = global:Get-PoshStackCount
 
-                $standardOut = (Start-Utf8Process $global:_ompExecutable @("print", "tooltip", "--status=$script:ErrorCode", "--shell=$script:ShellName", "--pswd=$nonFSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--command=$command", "--shell-version=$script:PSVersion", "--column=$column", "--terminal-width=$terminalWidth", "--no-status=$script:NoExitCode", "--job-count=$script:JobCount")) -join ''
-                if (!$standardOut) {
+                $output = (Get-PoshPrompt "tooltip" @(
+                        "--column=$($Host.UI.RawUI.CursorPosition.X)"
+                        "--command=$command"
+                    )) -join ''
+                if (!$output) {
                     return
                 }
 
-                Write-Host $standardOut -NoNewline
+                Write-Host $output -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
+            } finally {}
         }
     }
 
@@ -197,8 +363,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
                     $script:TooltipCommand = ''
                     Set-TransientPrompt
                 }
-            }
-            finally {
+            } finally {
                 [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
                 if ($global:_ompFTCSMarks -and $executingCommand) {
                     # Write FTCS_COMMAND_EXECUTED after accepting the input - it should still happen before execution
@@ -216,16 +381,15 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
                     $script:TooltipCommand = ''
                     Set-TransientPrompt
                 }
-            }
-            finally {
+            } finally {
                 [Microsoft.PowerShell.PSConsoleReadLine]::CopyOrCancelLine()
             }
         }
     }
 
     function Enable-PoshLineError {
-        $validLine = (Start-Utf8Process $global:_ompExecutable @("print", "valid", "--shell=$script:ShellName")) -join "`n"
-        $errorLine = (Start-Utf8Process $global:_ompExecutable @("print", "error", "--shell=$script:ShellName")) -join "`n"
+        $validLine = (Invoke-Utf8Posh @("print", "valid", "--shell=$script:ShellName")) -join "`n"
+        $errorLine = (Invoke-Utf8Posh @("print", "error", "--shell=$script:ShellName")) -join "`n"
         Set-PSReadLineOption -PromptText $validLine, $errorLine
     }
 
@@ -264,40 +428,24 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
             $Format = 'json'
         )
 
-        $configString = Start-Utf8Process $global:_ompExecutable @("config", "export", "--format=$Format")
-        # if no path, copy to clipboard by default
         if ($FilePath) {
             # https://stackoverflow.com/questions/3038337/powershell-resolve-path-that-might-not-exist
             $FilePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($FilePath)
-            [IO.File]::WriteAllLines($FilePath, $configString)
         }
-        else {
-            Set-Clipboard $configString
-            Write-Output "Theme copied to clipboard"
-        }
-    }
 
-    function Get-FileHyperlink {
-        param(
-            [Parameter(Mandatory, ValuefromPipeline = $True)]
-            [string]$uri,
-            [Parameter(ValuefromPipeline = $True)]
-            [string]$name
+        $output = Invoke-Utf8Posh @(
+            "config", "export"
+            "--format=$Format"
+            "--output=$FilePath"
         )
-
-        $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
+        if (!$output) {
+            Write-Host "Theme exported to $(Get-FileHyperlink $FilePath)."
+            return
         }
 
-        # return an ANSI formatted hyperlink
-        return "$esc]8;;file://$uri$esc\$name$esc]8;;$esc\"
+        # When no path is provided, copy the output to clipboard.
+        Set-Clipboard $output
+        Write-Host 'Theme copied to clipboard.'
     }
 
     function Get-PoshThemes {
@@ -329,19 +477,28 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
         Write-Host $logo
         $themes = Get-ChildItem -Path "$Path/*" -Include '*.omp.json' | Sort-Object Name
         if ($List -eq $true) {
-            $themes | Select-Object @{ Name = 'hyperlink'; Expression = { Get-FileHyperlink -uri $_.FullName } } | Format-Table -HideTableHeaders
-        }
-        else {
+            $themes | Select-Object @{ Name = 'hyperlink'; Expression = { Get-FileHyperlink -Uri $_.FullName } } | Format-Table -HideTableHeaders
+        } else {
             $nonFSWD = Get-NonFSWD
+            $stackCount = Get-PoshStackCount
+            $terminalWidth = Get-TerminalWidth
             $themes | ForEach-Object -Process {
-                Write-Host "Theme: $(Get-FileHyperlink -uri $_.FullName -Name ($_.BaseName -replace '\.omp$', ''))`n"
-                Start-Utf8Process $global:_ompExecutable @("print", "primary", "--config=$($_.FullName)", "--pswd=$nonFSWD", "--shell=$script:ShellName")
+                Write-Host "Theme: $(Get-FileHyperlink -Uri $_.FullName -Name ($_.BaseName -replace '\.omp$', ''))`n"
+                Invoke-Utf8Posh @(
+                    "print", "primary"
+                    "--config=$($_.FullName)"
+                    "--shell=$script:ShellName"
+                    "--shell-version=$script:PSVersion"
+                    "--pswd=$nonFSWD"
+                    "--stack-count=$stackCount"
+                    "--terminal-width=$terminalWidth"
+                )
                 Write-Host "`n"
             }
         }
         Write-Host @"
 
-Themes location: $(Get-FileHyperlink -uri "$Path")
+Themes location: $(Get-FileHyperlink -Uri "$Path")
 
 To change your theme, adjust the init script in $PROFILE.
 Example:
@@ -350,139 +507,6 @@ Example:
 "@
     }
 
-    function Set-PoshPromptType {
-        if ($script:TransientPrompt -eq $true) {
-            $script:PromptType = "transient"
-            $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
-        # 3) https://github.com/JanDeDobbeleer/oh-my-posh/issues/5153
-        if ($Host.Runspace.Debugger.InBreakpoint) {
-            $script:PromptType = "debug"
-            return
-        }
-
-        $script:PromptType = "primary"
-
-        if ($global:_ompJobCount) {
-            $script:JobCount = (Get-Job -State Running).Count
-        }
-
-        if ($global:_ompAzure) {
-            try {
-                $env:POSH_AZURE_SUBSCRIPTION = Get-AzContext | ConvertTo-Json
-            }
-            catch {}
-        }
-
-        if ($global:_ompPoshGit) {
-            try {
-                $global:GitStatus = Get-GitStatus
-                $env:POSH_GIT_STATUS = $global:GitStatus | ConvertTo-Json
-            }
-            catch {}
-        }
-    }
-
-    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
-        if ($script:OriginalLastExecutionStatus) {
-            $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
-            return
-        }
-    }
-
-    $promptFunction = {
-        # store the orignal last command execution status
-        if ($global:NVS_ORIGINAL_LASTEXECUTIONSTATUS -is [bool]) {
-            # make it compatible with NVS auto-switching, if enabled
-            $script:OriginalLastExecutionStatus = $global:NVS_ORIGINAL_LASTEXECUTIONSTATUS
-        }
-        else {
-            $script:OriginalLastExecutionStatus = $?
-        }
-        # store the orignal last exit code
-        $script:OriginalLastExitCode = $global:LASTEXITCODE
-
-        Set-PoshPromptType
-
-        if ($script:PromptType -ne 'transient') {
-            Update-PoshErrorCode
-        }
-
-        Set-PoshContext $script:ErrorCode
-
-        $nonFSWD = Get-NonFSWD
-        $stackCount = global:Get-PoshStackCount
-        $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
-
-        $standardOut = Start-Utf8Process $global:_ompExecutable @("print", $script:PromptType, "--status=$script:ErrorCode", "--pswd=$nonFSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--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)
-
-        # The output can be multi-line, joining them ensures proper rendering.
-        $output = $standardOut -join "`n"
-
-        if ($script:PromptType -eq 'transient') {
-            # Workaround to prevent a command from eating the tail of a transient prompt, when we're at the end of the line.
-            $command = ''
-            [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)
-            if ($command) {
-                $output += "  `b`b"
-            }
-        }
-
-        $output
-
-        # remove any posh-git status
-        $env:POSH_GIT_STATUS = $null
-
-        # restore the orignal last exit code
-        $global:LASTEXITCODE = $script:OriginalLastExitCode
-    }
-
-    $Function:prompt = $promptFunction
-
-    # set secondary prompt
-    Set-PSReadLineOption -ContinuationPrompt ((Start-Utf8Process $global:_ompExecutable @("print", "secondary", "--shell=$script:ShellName")) -join "`n")
-
     # perform cleanup on removal so a new initialization in current session works
     if (!$script:ConstrainedLanguageMode) {
         $ExecutionContext.SessionState.Module.OnRemove += {
@@ -506,11 +530,6 @@ Example:
         }
     }
 
-    $notice = Start-Utf8Process $global:_ompExecutable @("notice")
-    if ($notice) {
-        Write-Host $notice -NoNewline
-    }
-
     Export-ModuleMember -Function @(
         "Set-PoshContext"
         "Enable-PoshTooltips"
@@ -518,7 +537,6 @@ Example:
         "Enable-PoshLineError"
         "Export-PoshTheme"
         "Get-PoshThemes"
-        "Start-Utf8Process"
         "prompt"
     )
 } | Import-Module -Global
diff --git a/src/shell/scripts/omp.py b/src/shell/scripts/omp.py
deleted file mode 100644
index 3cc52837..00000000
--- a/src/shell/scripts/omp.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import uuid
-
-$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
-    status = last_cmd.rtn if last_cmd else 0
-    duration = round((last_cmd.ts[1] - last_cmd.ts[0]) * 1000) if last_cmd else 0
-    return status, duration
-
-def posh_primary():
-    status, duration = get_command_context()
-    return $(@($POSH_EXECUTABLE) print primary --shell=xonsh --status=@(status) --execution-time=@(duration) --shell-version=@($POSH_SHELL_VERSION))
-
-def posh_right():
-    status, duration = get_command_context()
-    return $(@($POSH_EXECUTABLE) print right --shell=xonsh --status=@(status) --execution-time=@(duration) --shell-version=@($POSH_SHELL_VERSION))
-
-
-$PROMPT = posh_primary
-$RIGHT_PROMPT = posh_right
diff --git a/src/shell/scripts/omp.tcsh b/src/shell/scripts/omp.tcsh
index c105bc55..0f633606 100644
--- a/src/shell/scripts/omp.tcsh
+++ b/src/shell/scripts/omp.tcsh
@@ -1,20 +1,34 @@
 setenv POWERLINE_COMMAND "oh-my-posh";
 setenv POSH_THEME ::CONFIG::;
-setenv POSH_SHELL_VERSION "";
+setenv POSH_SHELL_VERSION "$tcsh";
 setenv POSH_PID $$;
 setenv OSTYPE "$OSTYPE";
 
-if ("$OSTYPE" =~ {msys,cygwin}*) then
-  setenv POSH_PID "`cat /proc/$$/winpid`";
-endif
+if ( "$OSTYPE" =~ {msys,cygwin}* ) setenv POSH_PID "`cat /proc/$$/winpid`";
 
-set POSH_COMMAND = ::OMP::;
-set USER_PRECMD = "`alias precmd`";
-set USER_POSTCMD = "`alias postcmd`";
-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 --status=$POSH_CMD_STATUS --execution-time=$POSH_DURATION`";set POSH_START_TIME = -1';
-set POSH_POSTCMD = 'set POSH_START_TIME = `$POSH_COMMAND get millis`';
+if ( ! $?_omp_enabled ) alias precmd '
+  set _omp_status = $status;
+  set _omp_execution_time = -1;
+  set _omp_last_cmd = `echo $_:q`;
+  if ( $#_omp_last_cmd && $?_omp_cmd_executed ) @ _omp_execution_time = `"$_omp_executable" get millis` - $_omp_start_time;
+  unset _omp_last_cmd;
+  unset _omp_cmd_executed;
+  @ _omp_stack_count = $#dirstack - 1;
+  set prompt = "`$_omp_executable:q print primary
+    --save-cache
+    --shell=tcsh
+    --shell-version=$tcsh
+    --status=$_omp_status
+    --execution-time=$_omp_execution_time
+    --stack-count=$_omp_stack_count`";
+'"`alias precmd`";
 
-alias precmd "$POSH_PRECMD;$USER_PRECMD";
-alias postcmd "$POSH_POSTCMD;$USER_POSTCMD";
+if ( ! $?_omp_enabled ) alias postcmd '
+  set _omp_start_time = `"$_omp_executable" get millis`;
+  set _omp_cmd_executed;
+'"`alias postcmd`";
 
-set POSH_START_TIME = `$POSH_COMMAND get millis`;
+set _omp_enabled;
+set _omp_executable = ::OMP::;
+set _omp_execution_time = -1;
+set _omp_start_time = -1;
diff --git a/src/shell/scripts/omp.xsh b/src/shell/scripts/omp.xsh
new file mode 100644
index 00000000..a43f69ed
--- /dev/null
+++ b/src/shell/scripts/omp.xsh
@@ -0,0 +1,49 @@
+import uuid
+
+$POWERLINE_COMMAND = "oh-my-posh"
+$POSH_THEME = ::CONFIG::
+$POSH_PID = uuid.uuid4().hex
+$POSH_SHELL_VERSION = $XONSH_VERSION
+
+_omp_executable = ::OMP::
+_omp_history_length = 0
+
+def _omp_get_context():
+    global _omp_history_length
+    status = 0
+    duration = -1
+
+    if __xonsh__.history:
+        last_cmd = __xonsh__.history[-1]
+        if last_cmd:
+            status = last_cmd.rtn
+
+        history_length = len(__xonsh__.history)
+        if history_length != _omp_history_length:
+            _omp_history_length = history_length
+            duration = round((last_cmd.ts[1] - last_cmd.ts[0]) * 1000)
+
+    return status, duration
+
+def _omp_get_prompt(type: str, *args: str):
+    status, duration = _omp_get_context()
+    return $(
+        @(_omp_executable) print @(type) \
+            --save-cache \
+            --shell=xonsh \
+            --shell-version=$XONSH_VERSION \
+            --status=@(status) \
+            --execution-time=@(duration) \
+            @(args)
+    )
+
+def _omp_get_primary():
+    return _omp_get_prompt('primary')
+
+def _omp_get_right():
+    return _omp_get_prompt('right')
+
+$PROMPT = _omp_get_primary
+# When the primary prompt has multiple lines, the right prompt is always displayed on the first line, which is inconsistent with other supported shells.
+# The behavior is controlled by Xonsh, and there is no way to change it.
+$RIGHT_PROMPT = _omp_get_right
diff --git a/src/shell/scripts/omp.zsh b/src/shell/scripts/omp.zsh
index 89273307..5fbc273f 100644
--- a/src/shell/scripts/omp.zsh
+++ b/src/shell/scripts/omp.zsh
@@ -1,9 +1,8 @@
 export POSH_THEME=::CONFIG::
 export POSH_SHELL_VERSION=$ZSH_VERSION
 export POSH_PID=$$
-export POWERLINE_COMMAND="oh-my-posh"
+export POWERLINE_COMMAND='oh-my-posh'
 export CONDA_PROMPT_MODIFIER=false
-export POSH_PROMPT_COUNT=0
 export ZLE_RPROMPT_INDENT=0
 export OSTYPE=$OSTYPE
 
@@ -12,6 +11,7 @@ if [[ $OSTYPE =~ ^(msys|cygwin) ]]; then
 fi
 
 _omp_executable=::OMP::
+_omp_tooltip_command=''
 
 # switches to enable/disable features
 _omp_cursor_positioning=0
@@ -31,7 +31,7 @@ function _omp_set_cursor_position() {
   stty raw -echo min 0
 
   local pos
-  echo -en "\033[6n" >/dev/tty
+  echo -en '\033[6n' >/dev/tty
   read -r -d R pos
   pos=${pos:2} # strip off the esc-[
   local parts=(${(s:;:)pos})
@@ -49,32 +49,30 @@ function set_poshcontext() {
 
 function _omp_preexec() {
   if [[ $_omp_ftcs_marks == 0 ]]; then
-    printf "\033]133;C\007"
+    printf '\033]133;C\007'
   fi
 
   _omp_start_time=$($_omp_executable get millis)
 }
 
 function _omp_precmd() {
-  _omp_status_cache=$?
-  _omp_pipestatus_cache=(${pipestatus[@]})
+  _omp_status=$?
+  _omp_pipestatus=(${pipestatus[@]})
   _omp_stack_count=${#dirstack[@]}
-  _omp_elapsed=-1
-  _omp_no_exit_code="true"
+  _omp_execution_time=-1
+  _omp_no_status=true
+  _omp_tooltip_command=''
 
   if [ $_omp_start_time ]; then
-    local omp_now=$($_omp_executable get millis --shell=zsh)
-    _omp_elapsed=$(($omp_now - $_omp_start_time))
-    _omp_no_exit_code="false"
+    local omp_now=$($_omp_executable get millis)
+    _omp_execution_time=$(($omp_now - $_omp_start_time))
+    _omp_no_status=false
   fi
 
-  if [[ ${_omp_pipestatus_cache[-1]} != "$_omp_status_cache" ]]; then
-    _omp_pipestatus_cache=("$_omp_status_cache")
+  if [[ ${_omp_pipestatus[-1]} != "$_omp_status" ]]; then
+    _omp_pipestatus=("$_omp_status")
   fi
 
-  count=$((POSH_PROMPT_COUNT + 1))
-  export POSH_PROMPT_COUNT=$count
-
   set_poshcontext
   _omp_set_cursor_position
 
@@ -86,8 +84,8 @@ function _omp_precmd() {
   setopt PROMPT_PERCENT
 
   PS2=$_omp_secondary_prompt
+  eval "$(_omp_get_prompt primary --eval)"
 
-  eval "$($_omp_executable print primary --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
 }
 
@@ -116,6 +114,21 @@ function _omp_cleanup() {
 _omp_cleanup
 unset -f _omp_cleanup
 
+function _omp_get_prompt() {
+  local type=$1
+  local args=("${@[2,-1]}")
+  $_omp_executable print $type \
+    --save-cache \
+    --shell=zsh \
+    --shell-version=$ZSH_VERSION \
+    --status=$_omp_status \
+    --pipestatus="${_omp_pipestatus[*]}" \
+    --no-status=$_omp_no_status \
+    --execution-time=$_omp_execution_time \
+    --stack-count=$_omp_stack_count \
+    ${args[@]}
+}
+
 function _omp_render_tooltip() {
   if [[ $KEYS != ' ' ]]; then
     return
@@ -130,7 +143,7 @@ function _omp_render_tooltip() {
   fi
 
   _omp_tooltip_command="$tooltip_command"
-  local tooltip=$($_omp_executable print tooltip --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_get_prompt tooltip --command="$tooltip_command")
   if [[ -z $tooltip ]]; then
     return
   fi
@@ -148,23 +161,21 @@ function _omp_zle-line-init() {
   local -i ret=$?
   (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2]
 
-  _omp_tooltip_command=''
-  eval "$($_omp_executable print transient --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_get_prompt transient --eval)"
   zle .reset-prompt
 
-  # Exit the shell if we receive EOT.
-  if [[ $ret == 0 && $KEYS == $'\4' ]]; then
-    exit
-  fi
-
   if ((ret)); then
     # TODO (fix): this is not equal to sending a SIGINT, since the status code ($?) is set to 1 instead of 130.
     zle .send-break
-  else
-    # Enter
-    zle .accept-line
   fi
-  return ret
+
+  # Exit the shell if we receive EOT.
+  if [[ $KEYS == $'\4' ]]; then
+    exit
+  fi
+
+  zle .accept-line
+  return $ret
 }
 
 # Helper function for calling a widget before the specified OMP function.
@@ -205,7 +216,7 @@ function _omp_create_widget() {
 }
 
 function enable_poshtooltips() {
-  local widget=${$(bindkey " "):2}
+  local widget=${$(bindkey ' '):2}
 
   if [[ -z $widget ]]; then
     widget=self-insert
diff --git a/src/shell/tcsh.go b/src/shell/tcsh.go
index a6eac334..04a5ede8 100644
--- a/src/shell/tcsh.go
+++ b/src/shell/tcsh.go
@@ -2,6 +2,8 @@ package shell
 
 import (
 	_ "embed"
+	"fmt"
+	"strings"
 )
 
 //go:embed scripts/omp.tcsh
@@ -10,12 +12,23 @@ var tcshInit string
 func (f Feature) Tcsh() Code {
 	switch f {
 	case Upgrade:
-		return "$POSH_COMMAND upgrade;"
+		return `"$_omp_executable" upgrade;`
 	case Notice:
-		return "$POSH_COMMAND notice;"
+		return `"$_omp_executable" notice;`
 	case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, Transient, FTCSMarks, CursorPositioning:
 		fallthrough
 	default:
 		return ""
 	}
 }
+
+func quoteCshStr(str string) string {
+	if len(str) == 0 {
+		return "''"
+	}
+
+	// An non-working edge case: there is no way to preserve a newline ('\n') in command substitution.
+	// Therefore, we can only get a limited string without newlines for "eval".
+	return fmt.Sprintf("'%s'", strings.NewReplacer("'", `'"'"'`,
+		"!", `\!`).Replace(str))
+}
diff --git a/src/shell/xonsh.go b/src/shell/xonsh.go
index 6aaabfd4..083b0f68 100644
--- a/src/shell/xonsh.go
+++ b/src/shell/xonsh.go
@@ -2,20 +2,34 @@ package shell
 
 import (
 	_ "embed"
+	"fmt"
+	"strings"
 )
 
-//go:embed scripts/omp.py
+//go:embed scripts/omp.xsh
 var xonshInit string
 
 func (f Feature) Xonsh() Code {
 	switch f {
 	case Upgrade:
-		return "@($POSH_EXECUTABLE) upgrade"
+		return "@(_omp_executable) upgrade"
 	case Notice:
-		return "@($POSH_EXECUTABLE) notice"
+		return "@(_omp_executable) notice"
 	case PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, Transient, CursorPositioning, FTCSMarks:
 		fallthrough
 	default:
 		return ""
 	}
 }
+
+func quotePythonStr(str string) string {
+	if len(str) == 0 {
+		return "''"
+	}
+
+	return fmt.Sprintf("'%s'", strings.NewReplacer(
+		"'", `'"'"'`,
+		`\`, `\\`,
+		"\n", `\n`,
+	).Replace(str))
+}
diff --git a/src/shell/zsh.go b/src/shell/zsh.go
index 443ef7ec..6262cdab 100644
--- a/src/shell/zsh.go
+++ b/src/shell/zsh.go
@@ -7,21 +7,16 @@ import (
 //go:embed scripts/omp.zsh
 var zshInit string
 
-const (
-	unixUpgrade = "$_omp_executable upgrade"
-	unixNotice  = "$_omp_executable notice"
-)
-
 func (f Feature) Zsh() Code {
 	switch f {
 	case CursorPositioning:
-		return "_omp_cursor_positioning=1"
+		return unixCursorPositioning
 	case Tooltips:
 		return "enable_poshtooltips"
 	case Transient:
 		return "_omp_create_widget zle-line-init _omp_zle-line-init"
 	case FTCSMarks:
-		return "_omp_ftcs_marks=1"
+		return unixFTCSMarks
 	case Upgrade:
 		return unixUpgrade
 	case Notice:
diff --git a/src/terminal/writer.go b/src/terminal/writer.go
index baee0ffe..01ce8e09 100644
--- a/src/terminal/writer.go
+++ b/src/terminal/writer.go
@@ -183,34 +183,29 @@ func ClearAfter() string {
 }
 
 func FormatTitle(title string) string {
+	switch Shell {
 	// These shells don't support setting the console title.
-	if Shell == shell.ELVISH || Shell == shell.XONSH {
+	case shell.ELVISH, shell.XONSH, shell.TCSH:
 		return ""
-	}
-
-	title = trimAnsi(title)
-
-	if Plain {
-		return title
-	}
-
-	if Shell != shell.BASH && Shell != shell.ZSH {
-		return fmt.Sprintf(formats.Title, title)
-	}
+	case shell.BASH, shell.ZSH:
+		title = trimAnsi(title)
+		s := new(strings.Builder)
+
+		// We have to do this to prevent the shell from misidentifying escape sequences.
+		for _, char := range title {
+			escaped, shouldEscape := formats.EscapeSequences[char]
+			if shouldEscape {
+				s.WriteString(escaped)
+				continue
+			}
 
-	// We have to do this to prevent Bash/Zsh from misidentifying escape sequences.
-	s := new(strings.Builder)
-	for _, char := range title {
-		escaped, shouldEscape := formats.EscapeSequences[char]
-		if shouldEscape {
-			s.WriteString(escaped)
-			continue
+			s.WriteRune(char)
 		}
 
-		s.WriteRune(char)
+		return fmt.Sprintf(formats.Title, s.String())
+	default:
+		return fmt.Sprintf(formats.Title, trimAnsi(title))
 	}
-
-	return fmt.Sprintf(formats.Title, s.String())
 }
 
 func EscapeText(text string) string {
diff --git a/website/docs/installation/customize.mdx b/website/docs/installation/customize.mdx
index 6dae2ef3..430f10af 100644
--- a/website/docs/installation/customize.mdx
+++ b/website/docs/installation/customize.mdx
@@ -188,10 +188,10 @@ to only require remote scripts to be signed using `Set-ExecutionPolicy RemoteSig
 Adjust the Oh My Posh init line in `~/.tcshrc` by adding the `--config` flag with the location of your configuration.
 
 ```bash
-eval `oh-my-posh init tcsh --config ~/jandedobbeleer.omp.json`
+eval "`oh-my-posh init tcsh --config ~/jandedobbeleer.omp.json`"
 ```
 
-Once added, reload your profile for the changes to take effect.
+Note that the surrounding quotes are required. Once added, reload your profile for the changes to take effect.
 
 ```bash
 exec tcsh
diff --git a/website/docs/installation/prompt.mdx b/website/docs/installation/prompt.mdx
index 4c2e1e6e..869c3c30 100644
--- a/website/docs/installation/prompt.mdx
+++ b/website/docs/installation/prompt.mdx
@@ -183,10 +183,10 @@ Once added, reload your profile for the changes to take effect.
 Add the following at the end of `~/.tcshrc`:
 
 ```bash
-eval `oh-my-posh init tcsh`
+eval "`oh-my-posh init tcsh`"
 ```
 
-Once added, reload your profile for the changes to take effect.
+Note that the surrounding quotes are required. Once added, reload your profile for the changes to take effect.
 
 ```bash
 exec tcsh


Test patch:
diff --git a/src/shell/bash_test.go b/src/shell/bash_test.go
index d8dcafe8..845e5fad 100644
--- a/src/shell/bash_test.go
+++ b/src/shell/bash_test.go
@@ -1,6 +1,7 @@
 package shell
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -17,3 +18,17 @@ _omp_cursor_positioning=1`
 
 	assert.Equal(t, want, got)
 }
+
+func TestQuotePosixStr(t *testing.T) {
+	tests := []struct {
+		str      string
+		expected string
+	}{
+		{str: "", expected: "''"},
+		{str: `/tmp/"omp's dir"/oh-my-posh`, expected: `$'/tmp/"omp\'s dir"/oh-my-posh'`},
+		{str: `C:/tmp\omp's dir/oh-my-posh.exe`, expected: `$'C:/tmp\\omp\'s dir/oh-my-posh.exe'`},
+	}
+	for _, tc := range tests {
+		assert.Equal(t, tc.expected, QuotePosixStr(tc.str), fmt.Sprintf("QuotePosixStr: %s", tc.str))
+	}
+}
diff --git a/src/shell/cmd_test.go b/src/shell/cmd_test.go
index 7a267467..3e164e7b 100644
--- a/src/shell/cmd_test.go
+++ b/src/shell/cmd_test.go
@@ -1,6 +1,7 @@
 package shell
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -12,9 +13,24 @@ func TestCmdFeatures(t *testing.T) {
 	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()))
+ftcs_marks_enabled = true
+os.execute(string.format('"%s" upgrade', omp_executable))
+os.execute(string.format('"%s" notice', omp_executable))
 rprompt_enabled = true`
 
 	assert.Equal(t, want, got)
 }
+
+func TestEscapeLuaStr(t *testing.T) {
+	tests := []struct {
+		str      string
+		expected string
+	}{
+		{str: "", expected: ""},
+		{str: `/tmp/"omp's dir"/oh-my-posh`, expected: `/tmp/\"omp\'s dir\"/oh-my-posh`},
+		{str: `C:/tmp\omp's dir/oh-my-posh.exe`, expected: `C:/tmp\\omp\'s dir/oh-my-posh.exe`},
+	}
+	for _, tc := range tests {
+		assert.Equal(t, tc.expected, escapeLuaStr(tc.str), fmt.Sprintf("escapeLuaStr: %s", tc.str))
+	}
+}
diff --git a/src/shell/fish_test.go b/src/shell/fish_test.go
index fcadce44..c4798f51 100644
--- a/src/shell/fish_test.go
+++ b/src/shell/fish_test.go
@@ -1,6 +1,7 @@
 package shell
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -13,9 +14,23 @@ func TestFishFeatures(t *testing.T) {
 enable_poshtooltips
 set --global _omp_transient_prompt 1
 set --global _omp_ftcs_marks 1
-$_omp_executable upgrade
-$_omp_executable notice
+"$_omp_executable" upgrade
+"$_omp_executable" notice
 set --global _omp_prompt_mark 1`
 
 	assert.Equal(t, want, got)
 }
+
+func TestQuoteFishStr(t *testing.T) {
+	tests := []struct {
+		str      string
+		expected string
+	}{
+		{str: "", expected: "''"},
+		{str: `/tmp/"omp's dir"/oh-my-posh`, expected: `'/tmp/"omp\'s dir"/oh-my-posh'`},
+		{str: `C:/tmp\omp's dir/oh-my-posh.exe`, expected: `'C:/tmp\\omp\'s dir/oh-my-posh.exe'`},
+	}
+	for _, tc := range tests {
+		assert.Equal(t, tc.expected, quoteFishStr(tc.str), fmt.Sprintf("quoteFishStr: %s", tc.str))
+	}
+}
diff --git a/src/shell/init_test.go b/src/shell/init_test.go
deleted file mode 100644
index de7b951d..00000000
--- a/src/shell/init_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package shell
-
-import (
-	"fmt"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestQuotePwshOrElvishStr(t *testing.T) {
-	tests := []struct {
-		str      string
-		expected string
-	}{
-		{str: ``, expected: `''`},
-		{str: `/tmp/oh-my-posh`, expected: `'/tmp/oh-my-posh'`},
-		{str: `/tmp/omp's dir/oh-my-posh`, expected: `'/tmp/omp''s dir/oh-my-posh'`},
-		{str: `C:\tmp\oh-my-posh.exe`, expected: `'C:\tmp\oh-my-posh.exe'`},
-		{str: `C:\tmp\omp's dir\oh-my-posh.exe`, expected: `'C:\tmp\omp''s dir\oh-my-posh.exe'`},
-	}
-	for _, tc := range tests {
-		assert.Equal(t, tc.expected, quotePwshOrElvishStr(tc.str), fmt.Sprintf("quotePwshStr: %s", tc.str))
-	}
-}
-
-func TestQuotePosixStr(t *testing.T) {
-	tests := []struct {
-		str      string
-		expected string
-	}{
-		{str: ``, expected: `''`},
-		{str: `/tmp/oh-my-posh`, expected: `/tmp/oh-my-posh`},
-		{str: `/tmp/omp's dir/oh-my-posh`, expected: `$'/tmp/omp\'s dir/oh-my-posh'`},
-		{str: `C:/tmp/oh-my-posh.exe`, expected: `C:/tmp/oh-my-posh.exe`},
-		{str: `C:/tmp/omp's dir/oh-my-posh.exe`, expected: `$'C:/tmp/omp\'s dir/oh-my-posh.exe'`},
-	}
-	for _, tc := range tests {
-		assert.Equal(t, tc.expected, QuotePosixStr(tc.str), fmt.Sprintf("quotePosixStr: %s", tc.str))
-	}
-}
-
-func TestQuoteFishStr(t *testing.T) {
-	tests := []struct {
-		str      string
-		expected string
-	}{
-		{str: ``, expected: `''`},
-		{str: `/tmp/oh-my-posh`, expected: `/tmp/oh-my-posh`},
-		{str: `/tmp/omp's dir/oh-my-posh`, expected: `'/tmp/omp\'s dir/oh-my-posh'`},
-		{str: `C:/tmp/oh-my-posh.exe`, expected: `C:/tmp/oh-my-posh.exe`},
-		{str: `C:/tmp/omp's dir/oh-my-posh.exe`, expected: `'C:/tmp/omp\'s dir/oh-my-posh.exe'`},
-	}
-	for _, tc := range tests {
-		assert.Equal(t, tc.expected, quoteFishStr(tc.str), fmt.Sprintf("quoteFishStr: %s", tc.str))
-	}
-}
-
-func TestQuoteLuaStr(t *testing.T) {
-	tests := []struct {
-		str      string
-		expected string
-	}{
-		{str: ``, expected: `''`},
-		{str: `/tmp/oh-my-posh`, expected: `'/tmp/oh-my-posh'`},
-		{str: `/tmp/omp's dir/oh-my-posh`, expected: `'/tmp/omp\'s dir/oh-my-posh'`},
-		{str: `C:/tmp/oh-my-posh.exe`, expected: `'C:/tmp/oh-my-posh.exe'`},
-		{str: `C:/tmp/omp's dir/oh-my-posh.exe`, expected: `'C:/tmp/omp\'s dir/oh-my-posh.exe'`},
-	}
-	for _, tc := range tests {
-		assert.Equal(t, tc.expected, quoteLuaStr(tc.str), fmt.Sprintf("quoteLuaStr: %s", tc.str))
-	}
-}
-
-func TestQuoteNuStr(t *testing.T) {
-	tests := []struct {
-		str      string
-		expected string
-	}{
-		{str: ``, expected: `''`},
-		{str: `/tmp/oh-my-posh`, expected: `"/tmp/oh-my-posh"`},
-		{str: `/tmp/omp's dir/oh-my-posh`, expected: `"/tmp/omp's dir/oh-my-posh"`},
-		{str: `C:/tmp/oh-my-posh.exe`, expected: `"C:/tmp/oh-my-posh.exe"`},
-		{str: `C:/tmp/omp's dir/oh-my-posh.exe`, expected: `"C:/tmp/omp's dir/oh-my-posh.exe"`},
-	}
-	for _, tc := range tests {
-		assert.Equal(t, tc.expected, quoteNuStr(tc.str), fmt.Sprintf("quoteNuStr: %s", tc.str))
-	}
-}
diff --git a/src/shell/nu_test.go b/src/shell/nu_test.go
index d4d3b786..af932a6c 100644
--- a/src/shell/nu_test.go
+++ b/src/shell/nu_test.go
@@ -1,6 +1,7 @@
 package shell
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -9,11 +10,24 @@ import (
 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)" }
+$env.TRANSIENT_PROMPT_COMMAND = {|| _omp_get_prompt transient }
 ^$_omp_executable upgrade
 ^$_omp_executable notice`
 
 	assert.Equal(t, want, got)
 }
+
+func TestQuoteNuStr(t *testing.T) {
+	tests := []struct {
+		str      string
+		expected string
+	}{
+		{str: "", expected: "''"},
+		{str: `/tmp/"omp's dir"/oh-my-posh`, expected: `"/tmp/\"omp's dir\"/oh-my-posh"`},
+		{str: `C:/tmp\omp's dir/oh-my-posh.exe`, expected: `"C:/tmp\\omp's dir/oh-my-posh.exe"`},
+	}
+	for _, tc := range tests {
+		assert.Equal(t, tc.expected, quoteNuStr(tc.str), fmt.Sprintf("quoteNuStr: %s", tc.str))
+	}
+}
diff --git a/src/shell/pwsh_test.go b/src/shell/pwsh_test.go
index 8b8cc77c..b89ab280 100644
--- a/src/shell/pwsh_test.go
+++ b/src/shell/pwsh_test.go
@@ -1,6 +1,7 @@
 package shell
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -24,3 +25,17 @@ $global:_ompFTCSMarks = $true
 
 	assert.Equal(t, want, got)
 }
+
+func TestQuotePwshOrElvishStr(t *testing.T) {
+	tests := []struct {
+		str      string
+		expected string
+	}{
+		{str: "", expected: "''"},
+		{str: `/tmp/"omp's dir"/oh-my-posh`, expected: `'/tmp/"omp''s dir"/oh-my-posh'`},
+		{str: `C:/tmp\omp's dir/oh-my-posh.exe`, expected: `'C:/tmp\omp''s dir/oh-my-posh.exe'`},
+	}
+	for _, tc := range tests {
+		assert.Equal(t, tc.expected, quotePwshOrElvishStr(tc.str), fmt.Sprintf("quotePwshOrElvishStr: %s", tc.str))
+	}
+}
diff --git a/src/shell/tcsh_test.go b/src/shell/tcsh_test.go
index 292b2c64..438e39e6 100644
--- a/src/shell/tcsh_test.go
+++ b/src/shell/tcsh_test.go
@@ -1,6 +1,7 @@
 package shell
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -10,8 +11,22 @@ 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;`
+"$_omp_executable" upgrade;
+"$_omp_executable" notice;`
 
 	assert.Equal(t, want, got)
 }
+
+func TestQuoteCshStr(t *testing.T) {
+	tests := []struct {
+		str      string
+		expected string
+	}{
+		{str: "", expected: "''"},
+		{str: `/tmp/"omp's dir"!/oh-my-posh`, expected: `'/tmp/"omp'"'"'s dir"\!/oh-my-posh'`},
+		{str: `C:/tmp\omp's dir/oh-my-posh.exe`, expected: `'C:/tmp\omp'"'"'s dir/oh-my-posh.exe'`},
+	}
+	for _, tc := range tests {
+		assert.Equal(t, tc.expected, quoteCshStr(tc.str), fmt.Sprintf("quoteCshStr: %s", tc.str))
+	}
+}
diff --git a/src/shell/xonsh_test.go b/src/shell/xonsh_test.go
index 321f3fcc..4d8ce7d7 100644
--- a/src/shell/xonsh_test.go
+++ b/src/shell/xonsh_test.go
@@ -1,6 +1,7 @@
 package shell
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -10,8 +11,22 @@ 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`
+@(_omp_executable) upgrade
+@(_omp_executable) notice`
 
 	assert.Equal(t, want, got)
 }
+
+func TestQuotePythonStr(t *testing.T) {
+	tests := []struct {
+		str      string
+		expected string
+	}{
+		{str: "", expected: "''"},
+		{str: `/tmp/"omp's dir"/oh-my-posh`, expected: `'/tmp/"omp'"'"'s dir"/oh-my-posh'`},
+		{str: `C:/tmp\omp's dir/oh-my-posh.exe`, expected: `'C:/tmp\\omp'"'"'s dir/oh-my-posh.exe'`},
+	}
+	for _, tc := range tests {
+		assert.Equal(t, tc.expected, quotePythonStr(tc.str), fmt.Sprintf("quotePythonStr: %s", tc.str))
+	}
+}
diff --git a/src/shell/zsh_test.go b/src/shell/zsh_test.go
index 592b6250..d98a8e91 100644
--- a/src/shell/zsh_test.go
+++ b/src/shell/zsh_test.go
@@ -13,8 +13,8 @@ func TestZshFeatures(t *testing.T) {
 enable_poshtooltips
 _omp_create_widget zle-line-init _omp_zle-line-init
 _omp_ftcs_marks=1
-$_omp_executable upgrade
-$_omp_executable notice
+"$_omp_executable" upgrade
+"$_omp_executable" notice
 _omp_cursor_positioning=1`
 
 	assert.Equal(t, want, got)