fix(shell): avoid unnecessary CLI calls for prompt repaint

This commit is contained in:
L. Yeung 2024-07-10 20:28:08 +08:00 committed by Jan De Dobbeleer
parent dbc5da5800
commit 66f1347357
5 changed files with 280 additions and 246 deletions

View file

@ -172,11 +172,11 @@ func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {
defer e.patchPowerShellBleed()
// This is deprecated but we leave it in to not break configs
// It is encouraged to used "newline": true on block level
// rather than the standalone the linebreak block
// It is encouraged to use "newline": true on block level
// rather than the standalone linebreak block
if block.Type == config.LineBreak {
// do not print a newline to avoid a leading space
// when we're printin the first primary prompt in
// when we're printing the first primary prompt in
// the shell
if !cancelNewline {
e.writeNewline()
@ -191,7 +191,7 @@ func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {
}
// do not print a newline to avoid a leading space
// when we're printin the first primary prompt in
// when we're printing the first primary prompt in
// the shell
if block.Newline && !cancelNewline {
e.writeNewline()

View file

@ -1,6 +1,7 @@
package prompt
import (
"slices"
"strings"
"github.com/jandedobbeleer/oh-my-posh/src/config"
@ -9,6 +10,18 @@ import (
)
func (e *Engine) Tooltip(tip string) string {
supportedShells := []string{
shell.ZSH,
shell.CMD,
shell.FISH,
shell.PWSH,
shell.PWSH5,
shell.GENERIC,
}
if !slices.Contains(supportedShells, e.Env.Shell()) {
return ""
}
tip = strings.Trim(tip, " ")
tooltips := make([]*config.Segment, 0, 1)
@ -35,40 +48,29 @@ func (e *Engine) Tooltip(tip string) string {
Alignment: config.Right,
Segments: tooltips,
}
block.Init(e.Env)
if !block.Enabled() {
return ""
}
text, length := e.renderBlockSegments(block)
switch e.Env.Shell() {
case shell.ZSH, shell.CMD, shell.FISH, shell.GENERIC:
block.Init(e.Env)
if !block.Enabled() {
return ""
}
text, _ := e.renderBlockSegments(block)
return text
case shell.PWSH, shell.PWSH5:
if !block.Enabled() {
e.rprompt = text
e.rpromptLength = length
e.currentLineLength = e.Env.Flags().Column
space, ok := e.canWriteRightBlock(true)
if !ok {
return ""
}
consoleWidth, err := e.Env.TerminalWidth()
if err != nil || consoleWidth == 0 {
return ""
}
text, length := e.renderBlockSegments(block)
space := consoleWidth - e.Env.Flags().Column - length
if space <= 0 {
return ""
}
// clear from cursor to the end of the line in case a previous tooltip
// is cut off and partially preserved, if the new one is shorter
e.write(terminal.ClearAfter())
e.write(terminal.SaveCursorPosition())
e.write(strings.Repeat(" ", space))
e.write(text)
e.write(terminal.RestoreCursorPosition())
return e.string()
default:
return text
}
return ""
}
func (e *Engine) shouldInvokeWithTip(segment *config.Segment, tip string) bool {

View file

@ -1,17 +1,22 @@
set --export POSH_THEME ::CONFIG::
set --export POSH_SHELL_VERSION $FISH_VERSION
set --global POWERLINE_COMMAND "oh-my-posh"
set --global POWERLINE_COMMAND oh-my-posh
set --global POSH_PID $fish_pid
set --global CONDA_PROMPT_MODIFIER false
set --global omp_tooltip_prompt ""
set --global has_omp_tooltip false
set --global omp_transient 0
set --global omp_tooltip_command ''
set --global omp_current_rprompt ''
set --global omp_transient false
# We use this to avoid unnecessary CLI calls for prompt repaint.
set --global omp_new_prompt true
# template function for context loading
function set_poshcontext
return
return
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
@ -19,11 +24,14 @@ function fish_prompt
# 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:: print transient --config $POSH_THEME --shell fish --status $omp_status_cache --pipestatus="$omp_pipestatus_cache" --execution-time $omp_duration --stack-count $omp_stack_count --shell-version $FISH_VERSION --no-status=$omp_no_exit_code
return
if test "$omp_transient" = true
::OMP:: print transient --config $POSH_THEME --shell fish --status $omp_status_cache --pipestatus="$omp_pipestatus_cache" --execution-time $omp_duration --stack-count $omp_stack_count --shell-version $FISH_VERSION --no-status=$omp_no_exit_code
return
end
if test "$omp_new_prompt" = false
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_stack_count (count $dirstack)
@ -31,22 +39,22 @@ function fish_prompt
set --global omp_no_exit_code false
# check if variable set, < 3.2 case
if set --query omp_lastcommand; and test "$omp_lastcommand" = ""
set omp_duration 0
set omp_no_exit_code true
if set --query omp_lastcommand; and test -z "$omp_lastcommand"
set omp_duration 0
set omp_no_exit_code true
end
# works with fish >=3.2
if set --query omp_last_status_generation; and test "$omp_last_status_generation" = "$status_generation"
set omp_duration 0
set omp_no_exit_code true
set omp_duration 0
set omp_no_exit_code 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
# first execution - $status_generation is 0, $omp_last_status_generation is empty
set omp_no_exit_code true
end
if set --query status_generation
set --global --export omp_last_status_generation $status_generation
set --global omp_last_status_generation $status_generation
end
set_poshcontext
@ -55,112 +63,146 @@ function fish_prompt
set --local omp_cleared false
set --local last_command (history search --max 1)
if test "$last_command" = "clear"
set omp_cleared true
if test "$last_command" = clear
set omp_cleared true
end
::PROMPT_MARK::
::OMP:: print primary --config $POSH_THEME --shell fish --status $omp_status_cache --pipestatus="$omp_pipestatus_cache" --execution-time $omp_duration --stack-count $omp_stack_count --shell-version $FISH_VERSION --cleared=$omp_cleared --no-status=$omp_no_exit_code
# The prompt is saved for possible reuse, typically a repaint after clearing the screen buffer.
set --global omp_current_prompt (::OMP:: print primary --config $POSH_THEME --shell fish --status $omp_status_cache --pipestatus="$omp_pipestatus_cache" --execution-time $omp_duration --stack-count $omp_stack_count --shell-version $FISH_VERSION --cleared=$omp_cleared --no-status=$omp_no_exit_code | string collect)
echo -n "$omp_current_prompt"
end
function fish_right_prompt
if test "$omp_transient" = "1"
echo -n ""
set omp_transient 0
set has_omp_tooltip false
return
if test "$omp_transient" = true
set omp_transient false
return
end
if test -n "$omp_tooltip_prompt"
echo -n $omp_tooltip_prompt
set omp_tooltip_prompt ""
set has_omp_tooltip true
return
# Repaint an existing right prompt.
if test "$omp_new_prompt" = false
echo -n "$omp_current_rprompt"
return
end
set has_omp_tooltip false
::OMP:: print right --config $POSH_THEME --shell fish --status $omp_status_cache --execution-time $omp_duration --stack-count $omp_stack_count --shell-version $FISH_VERSION
set omp_new_prompt false
set --global omp_current_rprompt (::OMP:: print right --config $POSH_THEME --shell fish --status $omp_status_cache --pipestatus="$omp_pipestatus_cache" --execution-time $omp_duration --stack-count $omp_stack_count --shell-version $FISH_VERSION --no-status=$omp_no_exit_code | string join '')
echo -n "$omp_current_rprompt"
end
function postexec_omp --on-event fish_postexec
# works with fish <3.2
# pre and postexec not fired for empty command in fish >=3.2
set --global --export omp_lastcommand $argv
end
# fix tooltip not resetting on SIGINT (ctrl+c)
function sigint_omp --on-signal INT
commandline --function repaint
# works with fish <3.2
# pre and postexec not fired for empty command in fish >=3.2
set --global omp_lastcommand $argv
end
function preexec_omp --on-event fish_preexec
if "::FTCS_MARKS::" = "true"
echo -ne "\e]133;C\a"
end
if test "::FTCS_MARKS::" = true
echo -ne "\e]133;C\a"
end
end
# perform cleanup so a new initialization in current session works
if test "$(string match -e '_render_transient' $(bind \r --user 2>/dev/null))" != ''
bind -e \r
if test -n (bind \r --user 2>/dev/null | string match -e _omp_enter_key_handler)
bind -e \r -M default
bind -e \r -M insert
bind -e \r -M visual
end
if test "$(string match -e '_render_tooltip' $(bind \x20 --user 2>/dev/null))" != ''
bind -e \x20
if test -n (bind \n --user 2>/dev/null | string match -e _omp_enter_key_handler)
bind -e \n -M default
bind -e \n -M insert
bind -e \n -M visual
end
if test -n (bind \cc --user 2>/dev/null | string match -e _omp_ctrl_c_key_handler)
bind -e \cc -M default
bind -e \cc -M insert
bind -e \cc -M visual
end
if test -n (bind \x20 --user 2>/dev/null | string match -e _omp_space_key_handler)
bind -e \x20 -M default
bind -e \x20 -M insert
end
# tooltip
function _render_tooltip
commandline --function expand-abbr
commandline --insert " "
# get the first word of command line as tip
set omp_tooltip_command (commandline --current-buffer | string trim -l | string split --allow-empty -f1 ' ' | string collect)
if not test -n "$omp_tooltip_command"
return
end
set omp_tooltip_prompt (::OMP:: print tooltip --config $POSH_THEME --shell fish --status $omp_status_cache --shell-version $FISH_VERSION --command $omp_tooltip_command)
if not test -n "$omp_tooltip_prompt"
if test "$has_omp_tooltip" = "true"
commandline --function repaint
function _omp_space_key_handler
commandline --function expand-abbr
commandline --insert ' '
# Get the first word of command line as tip.
set --local tooltip_command (commandline --current-buffer | string trim -l | string split --allow-empty -f1 ' ' | string collect)
# Ignore an empty/repeated tooltip command.
if test -z "$tooltip_command" || test "$tooltip_command" = "$omp_tooltip_command"
return
end
return
end
commandline --function repaint
set omp_tooltip_command $tooltip_command
set --local tooltip_prompt (::OMP:: print tooltip --config $POSH_THEME --shell fish --status $omp_status_cache --pipestatus="$omp_pipestatus_cache" --execution-time $omp_duration --stack-count $omp_stack_count --shell-version $FISH_VERSION --command $omp_tooltip_command --no-status=$omp_no_exit_code | string join '')
if test -z "$tooltip_prompt"
return
end
# Save the tooltip prompt to avoid unnecessary CLI calls.
set omp_current_rprompt $tooltip_prompt
commandline --function repaint
end
if test "::TOOLTIPS::" = "true"
bind \x20 _render_tooltip -M default
bind \x20 _render_tooltip -M insert
if test "::TOOLTIPS::" = true
bind \x20 _omp_space_key_handler -M default
bind \x20 _omp_space_key_handler -M insert
end
# transient prompt
function _render_transient
if commandline --paging-mode
commandline --function accept-autosuggestion
return
end
set omp_transient 1
commandline --function repaint
commandline --function execute
function _omp_enter_key_handler
if commandline --paging-mode
commandline --function accept-autosuggestion
return
end
if commandline --is-valid || test -z (commandline --current-buffer | string trim -l | string collect)
set omp_new_prompt true
set omp_tooltip_command ''
if test "::TRANSIENT::" = true
set omp_transient true
commandline --function repaint
end
end
commandline --function execute
end
if test "::TRANSIENT::" = "true"
bind \r _render_transient -M default
bind \r _render_transient -M insert
bind \r _render_transient -M visual
function _omp_ctrl_c_key_handler
if test -z (commandline --current-buffer | string collect)
return
end
# Render a transient prompt on Ctrl-C with non-empty command line buffer.
set omp_new_prompt true
set omp_tooltip_command ''
if test "::TRANSIENT::" = true
set omp_transient true
commandline --function repaint
end
commandline --function cancel-commandline
commandline --function repaint
end
bind \r _omp_enter_key_handler -M default
bind \r _omp_enter_key_handler -M insert
bind \r _omp_enter_key_handler -M visual
bind \n _omp_enter_key_handler -M default
bind \n _omp_enter_key_handler -M insert
bind \n _omp_enter_key_handler -M visual
bind \cc _omp_ctrl_c_key_handler -M default
bind \cc _omp_ctrl_c_key_handler -M insert
bind \cc _omp_ctrl_c_key_handler -M visual
# legacy functions
function enable_poshtooltips
return
return
end
function enable_poshtransientprompt
return
return
end
if test "::UPGRADE::" = "true"
echo "::UPGRADENOTICE::"
if test "::UPGRADE::" = true
echo "::UPGRADENOTICE::"
end
if test "::AUTOUPGRADE::" = "true"
::OMP:: upgrade
if test "::AUTOUPGRADE::" = true
::OMP:: upgrade
end

View file

@ -14,20 +14,29 @@ function global:Get-PoshStackCount {
}
New-Module -Name "oh-my-posh-core" -ScriptBlock {
# Check `ConstrainedLanguage` mode.
$script:ConstrainedLanguageMode = $ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage"
# Prompt related backup.
$script:OriginalPromptFunction = $Function:prompt
$script:OriginalContinuationPrompt = (Get-PSReadLineOption).ContinuationPrompt
$script:OriginalPromptText = (Get-PSReadLineOption).PromptText
$script:NoExitCode = $true
$script:ErrorCode = 0
$script:ExecutionTime = 0
$script:OMPExecutable = ::OMP::
$script:ShellName = "::SHELL::"
$script:PSVersion = $PSVersionTable.PSVersion.ToString()
$script:TransientPrompt = $false
$script:ToolTipCommand = ""
$script:TooltipCommand = ''
$env:POWERLINE_COMMAND = "oh-my-posh"
$env:POSH_SHELL_VERSION = $script:PSVersion
$env:POSH_PID = $PID
$env:CONDA_PROMPT_MODIFIER = $false
# set the default theme
if ((::CONFIG:: -ne '') -and (Test-Path -LiteralPath ::CONFIG::)) {
if (::CONFIG:: -and (Test-Path -LiteralPath ::CONFIG::)) {
$env:POSH_THEME = (Resolve-Path -Path ::CONFIG::).ProviderPath
}
@ -56,7 +65,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
[string[]]$Arguments = @()
)
if ($ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage") {
if ($script:ConstrainedLanguageMode) {
$standardOut = Invoke-Expression "& `$FileName `$Arguments 2>&1"
$standardOut -join "`n"
return
@ -99,12 +108,14 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
}
$StartInfo.CreateNoWindow = $true
[void]$Process.Start()
# we do this to remove a deadlock potential on Windows
# Remove deadlock potential on Windows.
$stdoutTask = $Process.StandardOutput.ReadToEndAsync()
$stderrTask = $Process.StandardError.ReadToEndAsync()
$Process.WaitForExit()
$stderr = $stderrTask.Result.Trim()
if ($stderr -ne '') {
if ($stderr) {
$Host.UI.WriteErrorLine($stderr)
}
$stdoutTask.Result
@ -120,77 +131,79 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
return $pswd
}
if (("::TOOLTIPS::" -eq "true") -and ($ExecutionContext.SessionState.LanguageMode -ne "ConstrainedLanguage")) {
Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock {
[Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ')
$command = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)
$command = $command.TrimStart().Split(" ", 2) | Select-Object -First 1
# ignore an empty/repeated tip
if ($command -eq '' -or $command -eq $script:ToolTipCommand) {
return
}
$position = $host.UI.RawUI.CursorPosition
$terminalWidth = $Host.UI.RawUI.WindowSize.Width
$cleanPSWD = Get-CleanPSWD
$standardOut = @(Start-Utf8Process $script:OMPExecutable @("print", "tooltip", "--status=$script:ErrorCode", "--shell=$script:ShellName", "--pswd=$cleanPSWD", "--config=$env:POSH_THEME", "--command=$command", "--shell-version=$script:PSVersion", "--column=$($position.X)", "--terminal-width=$terminalWidth"))
# ignore an empty tooltip
if ($standardOut -eq '') {
return
}
Write-Host $standardOut -NoNewline
$host.UI.RawUI.CursorPosition = $position
# cache the tip command
$script:ToolTipCommand = $command
# we need this workaround to prevent the text after cursor from disappearing when the tooltip is rendered
[Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ')
[Microsoft.PowerShell.PSConsoleReadLine]::Undo()
function Get-TerminalWidth {
$terminalWidth = $Host.UI.RawUI.WindowSize.Width
# Set a sane default when the value can't be retrieved.
if (-not $terminalWidth) {
return 0
}
$terminalWidth
}
function Set-TransientPrompt {
$previousOutputEncoding = [Console]::OutputEncoding
$executingCommand = $false
if (!$script:ConstrainedLanguageMode) {
if ('::TOOLTIPS::' -eq 'true') {
Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock {
param([ConsoleKeyInfo]$key)
[Microsoft.PowerShell.PSConsoleReadLine]::SelfInsert($key)
try {
$command = ''
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)
# Get the first word of command line as tip.
$command = $command.TrimStart().Split(' ', 2) | Select-Object -First 1
# Ignore an empty/repeated tooltip command.
if (!$command -or ($command -eq $script:TooltipCommand)) {
return
}
$script:TooltipCommand = $command
$column = $Host.UI.RawUI.CursorPosition.X
$terminalWidth = Get-TerminalWidth
$cleanPSWD = Get-CleanPSWD
$stackCount = global:Get-PoshStackCount
$standardOut = (Start-Utf8Process $script:OMPExecutable @("print", "tooltip", "--status=$script:ErrorCode", "--shell=$script:ShellName", "--pswd=$cleanPSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--config=$env:POSH_THEME", "--command=$command", "--shell-version=$script:PSVersion", "--column=$column", "--terminal-width=$terminalWidth", "--no-status=$script:NoExitCode")) -join ''
if (!$standardOut) {
return
}
Write-Host $standardOut -NoNewline
try {
$parseErrors = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$null, [ref]$null, [ref]$parseErrors, [ref]$null)
if ($parseErrors.Count -eq 0) {
$executingCommand = $true
# 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 {
# If PSReadline is set to display suggestion list, this workaround is needed to clear the buffer below
# before accepting the current commandline. The max amount of items in the list is 10, so 12 lines
# are cleared (10 + 1 more for the prompt + 1 more for current commandline).
if ((Get-PSReadLineOption).PredictionViewStyle -eq 'ListView') {
$terminalHeight = $Host.UI.RawUI.WindowSize.Height
# only do this on an valid value
if ([int]$terminalHeight -gt 0) {
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("`n" * [System.Math]::Min($terminalHeight - $Host.UI.RawUI.CursorPosition.Y - 1, 12))
[Microsoft.PowerShell.PSConsoleReadLine]::Undo()
}
finally {
[Console]::OutputEncoding = $previousOutputEncoding
}
[Console]::OutputEncoding = $previousOutputEncoding
}
return $executingCommand
}
if (("::TRANSIENT::" -eq "true") -and ($ExecutionContext.SessionState.LanguageMode -ne "ConstrainedLanguage")) {
Set-PSReadLineKeyHandler -Key Enter -BriefDescription 'OhMyPoshEnterKeyHandler' -ScriptBlock {
try {
$executingCommand = Set-TransientPrompt
$parseErrors = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$null, [ref]$null, [ref]$parseErrors, [ref]$null)
$executingCommand = $parseErrors.Count -eq 0
if ($executingCommand) {
$script:TooltipCommand = ''
if ('::TRANSIENT::' -eq 'true') {
Set-TransientPrompt
}
}
}
finally {
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
# Write FTCS_COMMAND_EXECUTED after accepting the input - it should still happen before execution
if (("::FTCS_MARKS::" -eq "true") -and $executingCommand) {
if (('::FTCS_MARKS::' -eq 'true') -and $executingCommand) {
# Write FTCS_COMMAND_EXECUTED after accepting the input - it should still happen before execution
Write-Host "$([char]0x1b)]133;C`a" -NoNewline
}
}
finally {}
}
Set-PSReadLineKeyHandler -Key Ctrl+c -BriefDescription 'OhMyPoshCtrlCKeyHandler' -ScriptBlock {
try {
@ -198,37 +211,21 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
[Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$start, [ref]$null)
# only render a transient prompt when no text is selected
if ($start -eq -1) {
Set-TransientPrompt
$script:TooltipCommand = ''
if ('::TRANSIENT::' -eq 'true') {
Set-TransientPrompt
}
}
}
finally {}
[Microsoft.PowerShell.PSConsoleReadLine]::CopyOrCancelLine()
}
}
if (("::FTCS_MARKS::" -eq "true") -and ("::TRANSIENT::" -ne "true") -and ($ExecutionContext.SessionState.LanguageMode -ne "ConstrainedLanguage")) {
Set-PSReadLineKeyHandler -Key Enter -BriefDescription 'OhMyPoshEnterKeyHandler' -ScriptBlock {
$executingCommand = $false
try {
$parseErrors = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$null, [ref]$null, [ref]$parseErrors, [ref]$null)
$executingCommand = $parseErrors.Count -eq 0
}
finally {}
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
# Write FTCS_COMMAND_EXECUTED after accepting the input - it should still happen before execution
if ($executingCommand) {
Write-Host "$([char]0x1b)]133;C`a" -NoNewline
finally {
[Microsoft.PowerShell.PSConsoleReadLine]::CopyOrCancelLine()
}
}
}
if ("::ERROR_LINE::" -eq "true") {
$validLine = @(Start-Utf8Process $script:OMPExecutable @("print", "valid", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n"
$errorLine = @(Start-Utf8Process $script:OMPExecutable @("print", "error", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n"
$validLine = (Start-Utf8Process $script:OMPExecutable @("print", "valid", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n"
$errorLine = (Start-Utf8Process $script:OMPExecutable @("print", "error", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n"
Set-PSReadLineOption -PromptText $validLine, $errorLine
}
@ -267,9 +264,9 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
$Format = 'json'
)
$configString = @(Start-Utf8Process $script:OMPExecutable @("config", "export", "--config=$env:POSH_THEME", "--format=$Format"))
$configString = Start-Utf8Process $script:OMPExecutable @("config", "export", "--config=$env:POSH_THEME", "--format=$Format")
# if no path, copy to clipboard by default
if ('' -ne $FilePath) {
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)
@ -288,7 +285,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
[string]$name
)
$esc = [char]27
if ("" -eq $name) {
if (!$name) {
# if name not set, uri is used as the name of the hyperlink
$name = $uri
}
@ -335,7 +332,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
$cleanPSWD = Get-CleanPSWD
$themes | ForEach-Object -Process {
Write-Host "Theme: $(Get-FileHyperlink -uri $_.FullName -Name ($_.BaseName -replace '\.omp$', ''))`n"
@(Start-Utf8Process $script:OMPExecutable @("print", "primary", "--config=$($_.FullName)", "--pswd=$cleanPSWD", "--shell=$script:ShellName"))
Start-Utf8Process $script:OMPExecutable @("print", "primary", "--config=$($_.FullName)", "--pswd=$cleanPSWD", "--shell=$script:ShellName")
Write-Host "`n"
}
}
@ -400,7 +397,7 @@ Example:
}
}
function prompt {
$promptFunction = {
# store the orignal last command execution status
if ($global:NVS_ORIGINAL_LASTEXECUTIONSTATUS -is [bool]) {
# make it compatible with NVS auto-switching, if enabled
@ -419,41 +416,30 @@ Example:
$cleanPSWD = Get-CleanPSWD
$stackCount = global:Get-PoshStackCount
Set-PoshContext
$terminalWidth = $Host.UI.RawUI.WindowSize.Width
# set a sane default when the value can't be retrieved
if (-not $terminalWidth) {
$terminalWidth = 0
}
# in some cases we have an empty $script:NoExitCode
# this is a workaround to make sure we always have a value
# see https://github.com/JanDeDobbeleer/oh-my-posh/issues/4128
if ($null -eq $script:NoExitCode) {
$script:NoExitCode = $true
}
$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 $script:OMPExecutable @("print", $script:PromptType, "--status=$script:ErrorCode", "--pswd=$cleanPSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--config=$env:POSH_THEME", "--shell-version=$script:PSVersion", "--terminal-width=$terminalWidth", "--shell=$script:ShellName", "--no-status=$script:NoExitCode"))
$standardOut = Start-Utf8Process $script:OMPExecutable @("print", $script:PromptType, "--status=$script:ErrorCode", "--pswd=$cleanPSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--config=$env:POSH_THEME", "--shell-version=$script:PSVersion", "--terminal-width=$terminalWidth", "--shell=$script:ShellName", "--no-status=$script:NoExitCode")
# make sure PSReadLine knows if we have a multiline prompt
Set-PSReadLineOption -ExtraPromptLineCount (($standardOut | Measure-Object -Line).Lines - 1)
# the output can be multiline, joining these ensures proper rendering by adding line breaks with `n
# The output can be multi-line, joining them ensures proper rendering.
$standardOut -join "`n"
# remove any posh-git status
$env:POSH_GIT_STATUS = $null
# remove cached tip command
$script:ToolTipCommand = ""
# restore the orignal last exit code
$global:LASTEXITCODE = $script:OriginalLastExitCode
}
$Function:prompt = $promptFunction
# set secondary prompt
Set-PSReadLineOption -ContinuationPrompt (@(Start-Utf8Process $script:OMPExecutable @("print", "secondary", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n")
Set-PSReadLineOption -ContinuationPrompt ((Start-Utf8Process $script:OMPExecutable @("print", "secondary", "--config=$env:POSH_THEME", "--shell=$script:ShellName")) -join "`n")
# legacy functions
function Enable-PoshTooltips {}
@ -461,21 +447,25 @@ Example:
function Enable-PoshLineError {}
# perform cleanup on removal so a new initialization in current session works
if ($ExecutionContext.SessionState.LanguageMode -ne "ConstrainedLanguage") {
if (!$script:ConstrainedLanguageMode) {
$ExecutionContext.SessionState.Module.OnRemove += {
if ((Get-PSReadLineKeyHandler -Key Spacebar).Function -eq 'OhMyPoshSpaceKeyHandler') {
Remove-PSReadLineKeyHandler -Key Spacebar
Remove-Item Function:Get-PoshStackCount
$Function:prompt = $script:OriginalPromptFunction
(Get-PSReadLineOption).ContinuationPrompt = $script:OriginalContinuationPrompt
(Get-PSReadLineOption).PromptText = $script:OriginalPromptText
if ((Get-PSReadLineKeyHandler Spacebar).Function -eq 'OhMyPoshSpaceKeyHandler') {
Remove-PSReadLineKeyHandler Spacebar
}
if ((Get-PSReadLineKeyHandler -Key Enter).Function -eq 'OhMyPoshEnterKeyHandler') {
Set-PSReadLineKeyHandler -Key Enter -Function AcceptLine
if ((Get-PSReadLineKeyHandler Enter).Function -eq 'OhMyPoshEnterKeyHandler') {
Set-PSReadLineKeyHandler Enter -Function AcceptLine
}
if ((Get-PSReadLineKeyHandler -Key Ctrl+c).Function -eq 'OhMyPoshCtrlCKeyHandler') {
Set-PSReadLineKeyHandler -Key Ctrl+c -Function CopyOrCancelLine
if ((Get-PSReadLineKeyHandler Ctrl+c).Function -eq 'OhMyPoshCtrlCKeyHandler') {
Set-PSReadLineKeyHandler Ctrl+c -Function CopyOrCancelLine
}
}
}
$notice = @(Start-Utf8Process $script:OMPExecutable @("notice"))
$notice = Start-Utf8Process $script:OMPExecutable @("notice")
if ($notice) {
Write-Host $notice -NoNewline
}
@ -488,7 +478,6 @@ Example:
"Export-PoshTheme"
"Get-PoshThemes"
"Start-Utf8Process"
"prompt"
)
} | Import-Module -Global

View file

@ -20,7 +20,7 @@ function _set_posh_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})
@ -44,24 +44,24 @@ function prompt_ohmyposh_preexec() {
}
function prompt_ohmyposh_precmd() {
omp_last_error=$?
local pipeStatus=(${pipestatus[@]})
omp_status_cache=$?
omp_pipestatus_cache=(${pipestatus[@]})
omp_stack_count=${#dirstack[@]}
omp_elapsed=-1
no_exit_code="true"
omp_no_exit_code="true"
if [ $omp_start_time ]; then
local omp_now=$(::OMP:: get millis --shell=zsh)
omp_elapsed=$(($omp_now-$omp_start_time))
no_exit_code="false"
omp_elapsed=$(($omp_now - $omp_start_time))
omp_no_exit_code="false"
fi
if [[ "${pipeStatus[-1]}" != "$omp_last_error" ]]; then
pipeStatus=("$omp_last_error")
if [[ "${omp_pipestatus_cache[-1]}" != "$omp_status_cache" ]]; then
omp_pipestatus_cache=("$omp_status_cache")
fi
count=$((POSH_PROMPT_COUNT+1))
count=$((POSH_PROMPT_COUNT + 1))
export POSH_PROMPT_COUNT=$count
set_poshcontext
_set_posh_cursor_position
eval "$(::OMP:: print primary --config="$POSH_THEME" --status="$omp_last_error" --pipestatus="${pipeStatus[*]}" --execution-time="$omp_elapsed" --stack-count="$omp_stack_count" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$no_exit_code")"
eval "$(::OMP:: print primary --config="$POSH_THEME" --status="$omp_status_cache" --pipestatus="${omp_pipestatus_cache[*]}" --execution-time="$omp_elapsed" --stack-count="$omp_stack_count" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$omp_no_exit_code")"
unset omp_start_time
}
@ -82,7 +82,7 @@ function _posh-tooltip() {
# https://github.com/zsh-users/zsh-autosuggestions - clear suggestion to avoid keeping it after the newly inserted space
if [[ "$(zle -lL autosuggest-clear)" ]]; then
# only if suggestions not disabled (variable not set)
if ! [[ -v _ZSH_AUTOSUGGEST_DISABLED ]]; then
if [[ ! -v _ZSH_AUTOSUGGEST_DISABLED ]]; then
zle autosuggest-clear
fi
fi
@ -90,19 +90,19 @@ function _posh-tooltip() {
# https://github.com/zsh-users/zsh-autosuggestions - fetch new suggestion after the space
if [[ "$(zle -lL autosuggest-fetch)" ]]; then
# only if suggestions not disabled (variable not set)
if ! [[ -v _ZSH_AUTOSUGGEST_DISABLED ]]; then
if [[ ! -v _ZSH_AUTOSUGGEST_DISABLED ]]; then
zle autosuggest-fetch
fi
fi
# get the first word of command line as tip
local tip=${${(MS)BUFFER##[[:graph:]]*}%%[[:space:]]*}
# ignore an empty tip
if [[ -z "$tip" ]]; then
# Get the first word of command line as tip.
local tooltip_command=${${(MS)BUFFER##[[:graph:]]*}%%[[:space:]]*}
# Ignore an empty/repeated tooltip command.
if [[ -z "$tooltip_command" ]] || [[ "$tooltip_command" = "$omp_tooltip_command" ]]; then
return
fi
local tooltip=$(::OMP:: print tooltip --config="$POSH_THEME" --shell=zsh --status="$omp_last_error" --command="$tip" --shell-version="$ZSH_VERSION")
# ignore an empty tooltip
omp_tooltip_command="$tooltip_command"
local tooltip=$(::OMP:: print tooltip --config="$POSH_THEME" --status="$omp_status_cache" --pipestatus="${omp_pipestatus_cache[*]}" --execution-time="$omp_elapsed" --stack-count="$omp_stack_count" --command="$tooltip_command" --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$omp_no_exit_code")
if [[ -z "$tooltip" ]]; then
return
fi
@ -119,7 +119,8 @@ function _posh-zle-line-init() {
local -i ret=$?
(( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2]
eval "$(::OMP:: print transient --status="$omp_last_error" --execution-time="$omp_elapsed" --stack-count="$omp_stack_count" --config="$POSH_THEME" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$no_exit_code")"
omp_tooltip_command=''
eval "$(::OMP:: print transient --config="$POSH_THEME" --status="$omp_status_cache" --pipestatus="${omp_pipestatus_cache[*]}" --execution-time="$omp_elapsed" --stack-count="$omp_stack_count" --eval --shell=zsh --shell-version="$ZSH_VERSION" --no-status="$omp_no_exit_code")"
zle .reset-prompt
# Exit the shell if we receive EOT.