T34: prompts and commands carry OSC 133 marks: the tap reads every OSC body and hands 133's marks to the session, which keeps its last command's status; zsh, bash, fish and PowerShell mark what the shell leaves unmarked, and the user's prompt still sees the status
CI / platforms (ubuntu-24.04) (push) Successful in 1m2s
CI / platforms (windows-latest) (push) Successful in 1m45s
CI / macos (push) Successful in 12m10s

This commit is contained in:
ZacharyZhang-NY committed 2026-10-16 22:16:50 -04:00
1 parent cccfb2c82b
commit c53b540f42
18 files changed
+359 -88

No files matched your search

+31 -2
View File
@@ -1,4 +1,4 @@
# ELYTerminal: load the usual startup files, report folder and title.
# ELYTerminal: load the usual startup files, report folder and title, mark prompts and commands.
if [ -n "${ELY_BASH_LOGIN-}" ]; then
builtin unset ELY_BASH_LOGIN
[ -r /etc/profile ] && builtin source /etc/profile
@@ -12,8 +12,29 @@ if [ -n "${ELY_BASH_LOGIN-}" ]; then
else
[ -r ~/.bashrc ] && builtin source ~/.bashrc
fi
_ely_ran=
_ely_armed=
_ely_ps0=
if (( BASH_VERSINFO[0] * 100 + BASH_VERSINFO[1] >= 404 )); then
# PS0 runs in the shell, so its subscript can note that a command ran.
_ely_ps0='${_ely_note[_ely_ran=1]-}\e]133;C\a'
elif [ -z "$(builtin trap -p DEBUG)" ]; then
_ely_debug() {
[ -n "$_ely_armed" ] || builtin return 0
case $BASH_COMMAND in _ely_*) builtin return 0 ;; esac
_ely_armed=
_ely_ran=1
builtin printf '\e]133;C\a'
}
builtin trap '_ely_debug' DEBUG
fi
_ely_prompt() {
builtin local ret=$? LC_ALL=C char url= i title
_ely_armed=
if [ -n "$_ely_ran" ]; then
builtin printf '\e]133;D;%s\a' "$ret"
_ely_ran=
fi
for (( i = 0; i < ${#PWD}; i++ )); do
char=${PWD:i:1}
case $char in
@@ -25,4 +46,12 @@ _ely_prompt() {
builtin printf '\e]7;file://%s\a\e]2;%s\a' "$url" "${title//[[:cntrl:]]/}"
builtin return $ret
}
PROMPT_COMMAND="_ely_prompt${PROMPT_COMMAND:+;$PROMPT_COMMAND}"
# Last, after anything that sets PS1 or PS0.
_ely_mark() {
[[ $PS1 == *'\e]133;A'* ]] || PS1='\[\e]133;A\a\]'"$PS1"'\[\e]133;B\a\]'
if [ -n "$_ely_ps0" ] && builtin shopt -q promptvars && [[ ${PS0-} != *"$_ely_ps0"* ]]; then
PS0=$_ely_ps0${PS0-}
fi
_ely_armed=1
}
PROMPT_COMMAND="_ely_prompt${PROMPT_COMMAND:+;$PROMPT_COMMAND};_ely_mark"
@@ -1,4 +1,4 @@
# ELYTerminal: restore XDG_DATA_DIRS, report the folder; fish_title keeps the title.
# ELYTerminal: restore XDG_DATA_DIRS, report the folder, mark what this fish leaves unmarked; fish_title keeps the title.
if test -n "$ELY_FISH_XDG_DATA_DIRS"
set -gx XDG_DATA_DIRS $ELY_FISH_XDG_DATA_DIRS
else
@@ -9,4 +9,33 @@ if status is-interactive
function _ely_prompt --on-event fish_prompt
printf '\e]7;file://%s\a' (string escape --style=url -- $PWD)
end
# fish 4.3 marks its own prompts and commands; 4.0 all but the prompt's end; older ones none.
set -l v (string split ' ' -- (string replace -r '^(\d+)\.(\d+).*' '$1 $2' -- $version))
if test $v[1] -lt 4
set -g _ely_marks A B
function _ely_preexec --on-event fish_preexec
printf '\e]133;C\a'
end
function _ely_postexec --on-event fish_postexec
printf '\e]133;D;%s\a' $status
end
else if test $v[1] -eq 4 -a $v[2] -lt 3
set -g _ely_marks B
end
if set -q _ely_marks
# The user's prompt loads late and may change; the marks go around the one shown.
function _ely_wrap --on-event fish_prompt
if functions -q _ely_user_prompt; and string match -q '*_ely_user_prompt*' -- (functions fish_prompt)
return
end
functions -q _ely_user_prompt; and functions -e _ely_user_prompt
functions -c fish_prompt _ely_user_prompt
function fish_prompt
# First, so the user's prompt sees the command's status.
set -l text (_ely_user_prompt | string collect -N)
contains A $_ely_marks; and printf '\e]133;A\a'
printf '%s\e]133;B\a' "$text"
end
end
end
end
+32 -3
View File
@@ -1,6 +1,23 @@
# ELYTerminal: wrap the prompt to report folder and title.
# ELYTerminal: wrap the prompt to report folder and title and to mark prompts and commands.
$global:ElyPrompt = $function:prompt
$global:ElyRan = $false
function global:prompt {
# First: every statement sets $? again.
$ok = $?
$esc, $bel = [char]27, [char]7
if ($global:ElyRan) {
$code = 1
if ($ok) { $code = 0 }
elseif ($Error.Count -eq 0 -or [object]::ReferenceEquals($Error[0], $global:ElyError)) {
# No new error: a native program failed. Strict mode refuses an unset variable.
$code = Get-Variable LASTEXITCODE -Scope Global -ValueOnly -ErrorAction Ignore
}
[Console]::Write("$esc]133;D;$code$bel")
$global:ElyRan = $false
}
[Console]::Write("$esc]133;A$bel")
# The user's prompt sees a failed command's $? still.
if (-not $ok) { Write-Error '' -ErrorAction Ignore }
$text = & $global:ElyPrompt
$folder = $executionContext.SessionState.Path.CurrentLocation
if ($folder.Provider.Name -eq 'FileSystem') {
@@ -8,8 +25,20 @@ function global:prompt {
$path = ($parts | ForEach-Object { [Uri]::EscapeDataString($_) }) -join '/'
if (-not $path.StartsWith('/')) { $path = "/$path" }
$leaf = (Split-Path -Leaf $folder.ProviderPath) -replace '\p{Cc}', ''
$esc, $bel = [char]27, [char]7
[Console]::Write("$esc]7;file://$path$bel$esc]2;$leaf$bel")
}
$text
"$text$esc]133;B$bel"
}
# A command starts once PSReadLine hands over a line that is not blank.
if (Test-Path Function:\PSConsoleHostReadLine) {
$global:ElyReadLine = $function:PSConsoleHostReadLine
function global:PSConsoleHostReadLine {
$line = & $global:ElyReadLine
if (-not [string]::IsNullOrWhiteSpace($line)) {
$global:ElyRan = $true
$global:ElyError = if ($Error.Count) { $Error[0] }
[Console]::Write("$([char]27)]133;C$([char]7)")
}
$line
}
}
+16 -2
View File
@@ -1,4 +1,4 @@
# ELYTerminal: restore ZDOTDIR, load the user's .zshenv, report folder and title.
# ELYTerminal: restore ZDOTDIR, load the user's .zshenv, report folder and title, mark prompts and commands.
if [[ -n "${ELY_ZSH_ZDOTDIR+set}" ]]; then
ZDOTDIR=$ELY_ZSH_ZDOTDIR
builtin unset ELY_ZSH_ZDOTDIR
@@ -7,8 +7,13 @@ else
fi
[[ -r "${ZDOTDIR:-$HOME}/.zshenv" ]] && builtin source "${ZDOTDIR:-$HOME}/.zshenv"
if [[ -o interactive ]]; then
_ely_ran=
_ely_precmd() {
builtin local ret=$? LC_ALL=C char url=
if [[ -n $_ely_ran ]]; then
builtin printf '\e]133;D;%s\a' $ret
_ely_ran=
fi
for char in ${(s::)PWD}; do
case $char in
[[:cntrl:]]|%) builtin printf -v char '%%%02X' "'$char" ;;
@@ -16,12 +21,21 @@ if [[ -o interactive ]]; then
url+=$char
done
builtin printf '\e]7;file://%s\a\e]2;%s\a' "$url" "${${${PWD:t}:-/}//[[:cntrl:]]/}"
# Themes set PS1 in later hooks; from the next prompt the marks go on after them.
precmd_functions=(${precmd_functions:#_ely_mark} _ely_mark)
builtin return ret
}
_ely_mark() {
if [[ -o prompt_percent && $PS1 != *$'\e]133;A'* ]]; then
PS1=$'%{\e]133;A\a%}'$PS1$'%{\e]133;B\a%}'
fi
}
_ely_preexec() {
builtin printf '\e]2;%s\a' "${1//[[:cntrl:]]/}"
_ely_ran=1
builtin printf '\e]133;C\a\e]2;%s\a' "${1//[[:cntrl:]]/}"
}
builtin autoload -Uz add-zsh-hook
add-zsh-hook precmd _ely_precmd
add-zsh-hook precmd _ely_mark
add-zsh-hook preexec _ely_preexec
fi