Improve bash/zsh/terminal consistency

This commit is contained in:
Loic Nageleisen 2024-09-11 19:08:14 +02:00
parent bb8b9420d6
commit b780b2ce34
Signed by: lloeki
GPG key ID: D05DAEE6889F94C2
9 changed files with 160 additions and 50 deletions

View file

@ -66,8 +66,17 @@ __debug_invoke_preexec () {
local this_command; local this_command;
# TODO: hack: doesn't work when command is not added to history [ -n "$COMP_LINE" ] && return # completion
this_command=`history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//g"`; [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # precmd
# get current command by reading last history item
# contrary to zsh, the command needs to be inserted in the history
# so it may not work reliably depending on HISTCONTROL/HISTIGNORE
# - ignoredups is fine: last command stays the same
# - erasedups is fine: last command is inserted, older duplicates are removed
# - ignorespace is not fine (and therefore so is ignoreboth): never inserts
# - HISTIGNORE is not fine: never inserts
this_command="$(history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//g")";
preexec "$this_command" preexec "$this_command"
} }
@ -126,7 +135,7 @@ clear_incomplete_line() {
fi fi
} }
function sub_prompt_colors_unsized() { function sub_zprompt_unsized() {
sed \ sed \
-e 's#%F{black}#\\033[30m#g' \ -e 's#%F{black}#\\033[30m#g' \
-e 's#%F{red}#\\033[31m#g' \ -e 's#%F{red}#\\033[31m#g' \
@ -136,10 +145,11 @@ function sub_prompt_colors_unsized() {
-e 's#%F{magenta}#\\033[35m#g' \ -e 's#%F{magenta}#\\033[35m#g' \
-e 's#%F{cyan}#\\033[36m#g' \ -e 's#%F{cyan}#\\033[36m#g' \
-e 's#%F{white}#\\033[37m#g' \ -e 's#%F{white}#\\033[37m#g' \
-e 's#%f#\\033[00m#g' -e 's#%f#\\033[00m#g' \
-e 's#%{\(\([^%]\)*\)%}#\1#g'
} }
function sub_prompt_colors_sized() { function sub_zprompt_sized() {
sed \ sed \
-e 's#%F{black}#\\[\\033[30m\\]#g' \ -e 's#%F{black}#\\[\\033[30m\\]#g' \
-e 's#%F{red}#\\[\\033[31m\\]#g' \ -e 's#%F{red}#\\[\\033[31m\\]#g' \
@ -149,10 +159,11 @@ function sub_prompt_colors_sized() {
-e 's#%F{magenta}#\\[\\033[35m\\]#g' \ -e 's#%F{magenta}#\\[\\033[35m\\]#g' \
-e 's#%F{cyan}#\\[\\033[36m\\]#g' \ -e 's#%F{cyan}#\\[\\033[36m\\]#g' \
-e 's#%F{white}#\\[\\033[37m\\]#g' \ -e 's#%F{white}#\\[\\033[37m\\]#g' \
-e 's#%f#\\[\\033[00m\\]#g' -e 's#%f#\\[\\033[00m\\]#g' \
-e 's#%{\(\([^%]\)*\)%}#\\[\1\\]#g'
} }
function strip_prompt_colors() { function strip_zprompt() {
sed \ sed \
-e 's#%F{black}##g' \ -e 's#%F{black}##g' \
-e 's#%F{red}##g' \ -e 's#%F{red}##g' \
@ -162,15 +173,17 @@ function strip_prompt_colors() {
-e 's#%F{magenta}##g' \ -e 's#%F{magenta}##g' \
-e 's#%F{cyan}##g' \ -e 's#%F{cyan}##g' \
-e 's#%F{white}##g' \ -e 's#%F{white}##g' \
-e 's#%f##g' -e 's#%f##g' \
-e 's#%{\(\([^%]\)*\)%}##g'
} }
# right prompt support and PROMPT/RPROMPT vars # right prompt support and PROMPT/RPROMPT vars
function apply_prompt_rprompt() { function apply_prompt_rprompt() {
local rprompt=$(echo "${RPROMPT}" | sub_prompt_colors_unsized) local rprompt=$(echo "${RPROMPT}" | sub_zprompt_unsized)
local prompt=$(echo "${PROMPT}" | sub_prompt_colors_sized) local prompt=$(echo "${PROMPT}" | sub_zprompt_sized)
#local rprompt=$(echo "${RPROMPT}" | strip_prompt_colors) #local rprompt=$(echo "${RPROMPT}" | strip_zprompt)
#local prompt=$(echo "${PROMPT}" | strip_prompt_colors) #local prompt=$(echo "${PROMPT}" | strip_zprompt)
if [[ -n "${RPROMPT}" ]]; then if [[ -n "${RPROMPT}" ]]; then
PS1="$(printf "\[%*s\r\]%s" "${COLUMNS}" "${rprompt:-}" "${prompt:-}")" PS1="$(printf "\[%*s\r\]%s" "${COLUMNS}" "${rprompt:-}" "${prompt:-}")"
else else

View file

@ -1,16 +1,24 @@
# ignore repeated, space-started, and casual commands # ignore repeated, space-started, and casual commands
export HISTIGNORE="&:[ ]*:l[sl]:[bf]g:exit:cd .." # export HISTIGNORE="&:[ ]*:l[sl]:[bf]g:exit:cd .."
# ^ disabled until bash/ext preexec is fixed
export HISTIGNORE=""
# enable multiline historization as a single line # enable multiline historization as a single line
shopt -s cmdhist shopt -s cmdhist
# enable appending to histfile # enable appending to histfile on exit
shopt -s histappend shopt -s histappend
# ignore sequential duplicates # ignore sequential duplicates
export HISTCONTROL=ignoreboth export HISTCONTROL=ignoredups
# more! # more! (live)
export HISTSIZE=10000 export HISTSIZE=100000
# all! (persisted)
export HISTFILESIZE=1000000
# share with zsh
export HISTFILE=~/.history
# vim: ft=bash # vim: ft=bash

View file

@ -132,4 +132,29 @@ set_prompt() {
fi fi
} }
mark_prompt() {
local mark_a='%{\e]133;A\a%}'
local mark_b='%{\e]133;B\a%}'
PROMPT="${mark_a}${PROMPT}${mark_b}"
}
mark_command_exec() {
if [[ $# -eq 0 ]]; then
local mark_c="\e]133;C\a"
printf "${mark_c}" "${command}"
else
local command="${1:-}"
local mark_c="\e]133;C;cmdline=%q\a"
printf "${mark_c}" "${command}"
fi
}
mark_command_exit() {
local rc="${1:-}"
local mark_d="\e]133;D${rc};\a"
printf "${mark_d}"
}
# vim: ft=bash # vim: ft=bash

11
bash/rc
View file

@ -18,7 +18,7 @@ source $DOTFILES_SHELL_DIR/chruby
source $DOTFILES_BASH_DIR/fzf source $DOTFILES_BASH_DIR/fzf
source $DOTFILES_SHELL_DIR/direnv source $DOTFILES_SHELL_DIR/direnv
source $DOTFILES_SHELL_DIR/kd source $DOTFILES_SHELL_DIR/kd
source $DOTFILES_BASH_DIR/kitty #source $DOTFILES_BASH_DIR/kitty
source $DOTFILES_SHELL_DIR/git_prompt_info source $DOTFILES_SHELL_DIR/git_prompt_info
GIT_PS1_SHOWDIRTYSTATE=1 GIT_PS1_SHOWDIRTYSTATE=1
@ -28,6 +28,8 @@ GIT_PS1_SHOWUNTRACKEDFILES=1
precmd() { precmd() {
CMD_RC=$? CMD_RC=$?
mark_command_exit "${CMD_RC}"
# if [[ -n ${CMD_START} ]]; then # if [[ -n ${CMD_START} ]]; then
# CMD_END="${EPOCHREALTIME}" # CMD_END="${EPOCHREALTIME}"
# CMD_DURATION=$(bc <<<"${CMD_END} - ${CMD_START}") # CMD_DURATION=$(bc <<<"${CMD_END} - ${CMD_START}")
@ -38,20 +40,21 @@ precmd() {
_direnv_hook _direnv_hook
#clear_incomplete_line #clear_incomplete_line
set_prompt set_prompt
apply_prompt_rprompt
update_terminal_cwd
set_term_title set_term_title
mark_prompt
apply_prompt_rprompt
} }
preexec() { preexec() {
set_term_title set_term_title
CMD_START="${EPOCHREALTIME}" CMD_START="${EPOCHREALTIME}"
mark_command_exec "$1"
} }
chpwd() { chpwd() {
__git_ps1_gitdir __git_ps1_gitdir
_gopath _gopath
_auto-chruby if _has-chruby; then _auto-chruby; fi
} }
chpwd chpwd

View file

@ -1,4 +1,4 @@
# Tell the terminal about the working directory at each prompt. # Tell Apple Terminal about the working directory at each prompt.
if [ "$TERM_PROGRAM" == "Apple_Terminal" ] && [ -z "$INSIDE_EMACS" ]; then if [ "$TERM_PROGRAM" == "Apple_Terminal" ] && [ -z "$INSIDE_EMACS" ]; then
update_terminal_cwd() { update_terminal_cwd() {
# Identify the directory using a "file:" scheme URL, # Identify the directory using a "file:" scheme URL,
@ -14,15 +14,22 @@ else
fi fi
set_term_title() { set_term_title() {
if [[ -n "${SSH_CLIENT}" ]]; then
local title="$USER@${HOSTNAME%%.*}:${PWD/#$HOME/\~}"
else
local title="${PWD/#$HOME/\~}"
fi
update_terminal_cwd
case $TERM in case $TERM in
xterm*|rxvt*|alacritty) screen*|xterm*|rxvt*|alacritty)
local title="\033]2;$USER@${HOSTNAME%%.*}:${PWD/#$HOME/~}\a" printf "\e]2;%s\a" "${title}"
;; ;;
*) *)
local title="" : # NOOP
;; ;;
esac esac
printf "$title"
} }
# vim: ft=bash # vim: ft=bash

View file

@ -1,13 +1,29 @@
# ignore sequential duplicates # ignore sequential duplicates
setopt hist_ignore_dups setopt hist_ignore_dups
# ignore space-started
setopt hist_ignore_space setopt hist_ignore_space
setopt hist_reduce_blanks setopt hist_reduce_blanks
# append on exit
setopt append_history setopt append_history
# perform history expansion
setopt hist_verify setopt hist_verify
# do not load from persistence on every invocation
unsetopt share_history unsetopt share_history
HISTSIZE=100000 # more! (live)
SAVEHIST=100000 export HISTSIZE=100000
# all! (persisted)
export SAVEHIST=1000000
# share with bash
export HISTFILE=~/.history
# ignore repeated, space-started, and casual commands
HISTORY_IGNORE="(^ +|ls|bg|fg|pwd|exit|cd ..)" HISTORY_IGNORE="(^ +|ls|bg|fg|pwd|exit|cd ..)"
# vim: ft=zsh # vim: ft=zsh

View file

@ -184,6 +184,7 @@ set_prompt() {
[[ -n "${IN_NIX_SHELL}" ]] && buffer="${buffer} %F{yellow}nix" [[ -n "${IN_NIX_SHELL}" ]] && buffer="${buffer} %F{yellow}nix"
buffer="${buffer}%f> " buffer="${buffer}%f> "
PROMPT="${buffer}" PROMPT="${buffer}"
local rbuffer="" local rbuffer=""
@ -203,4 +204,29 @@ set_prompt() {
fi fi
} }
mark_prompt() {
local mark_a=$'%{\e]133;A\a%}'
local mark_b=$'%{\e]133;B\a%}'
PROMPT="${mark_a}${PROMPT}${mark_b}"
}
mark_command_exec() {
if [[ $# -eq 0 ]]; then
local mark_c="\e]133;C\a"
printf "${mark_c}" "${command}"
else
local command="${1:-}"
local mark_c="\e]133;C;cmdline=%q\a"
printf "${mark_c}" "${command}"
fi
}
mark_command_exit() {
local rc="${1:-}"
local mark_d="\e]133;D${rc};\a"
printf "${mark_d}"
}
# vim: ft=zsh # vim: ft=zsh

5
zsh/rc
View file

@ -14,7 +14,6 @@ source $DOTFILES_ZSH_DIR/prompt
source $DOTFILES_ZSH_DIR/fzf source $DOTFILES_ZSH_DIR/fzf
source $DOTFILES_SHELL_DIR/go source $DOTFILES_SHELL_DIR/go
source $DOTFILES_SHELL_DIR/direnv source $DOTFILES_SHELL_DIR/direnv
source $DOTFILES_ZSH_DIR/kitty
set -o ignoreeof set -o ignoreeof
unsetopt BEEP unsetopt BEEP
@ -30,6 +29,8 @@ zmodload zsh/datetime
precmd() { precmd() {
CMD_RC=$? CMD_RC=$?
mark_command_exit "${CMD_RC}"
if [[ -n ${CMD_START} ]]; then if [[ -n ${CMD_START} ]]; then
CMD_END="${EPOCHREALTIME}" CMD_END="${EPOCHREALTIME}"
CMD_DURATION=$(( ${CMD_END} - ${CMD_START} )) CMD_DURATION=$(( ${CMD_END} - ${CMD_START} ))
@ -41,11 +42,13 @@ precmd() {
psvar=() psvar=()
set_prompt set_prompt
set_term_title set_term_title
mark_prompt
} }
preexec() { preexec() {
set_term_title set_term_title
CMD_START="${EPOCHREALTIME}" CMD_START="${EPOCHREALTIME}"
mark_command_exec "$1"
} }
chpwd() { chpwd() {

View file

@ -1,28 +1,37 @@
# Set terminal title # Tell Apple Terminal about the working directory at each prompt.
set_term_title() { if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then
[[ -o interactive ]] || return update_terminal_cwd() {
# Bubble information up to the terminal # Identify the directory using a "file:" scheme URL,
case $TERM_PROGRAM in # including the host name to disambiguate local vs.
Apple_Terminal) # remote connections. Percent-escape spaces.
local SEARCH=' ' local SEARCH=' '
local REPLACE='%20' local REPLACE='%20'
local PWD_URL="file://$HOSTNAME${PWD//$SEARCH/$REPLACE}" local PWD_URL="file://$HOSTNAME${PWD//$SEARCH/$REPLACE}"
printf '\e]7;%s\a' "$PWD_URL" printf '\e]7;%s\a' "$PWD_URL"
;; }
*) else
# NOOP update_terminal_cwd() { :; }
;; fi
esac
# Set terminal title
set_term_title() {
[[ -o interactive ]] || return
if [[ -n "${SSH_CLIENT}" ]]; then
local title="$USER@${HOSTNAME%%.*}:${PWD/#$HOME/~}"
else
local title="${PWD/#$HOME/~}"
fi
update_terminal_cwd
case $TERM in case $TERM in
screen*) screen*|xterm*|rxvt*|alacritty)
#print -Pn "\ek%n@%m: %~\e\\" #breaks tmux #print -Pn "\ek%n@%m: %~\e\\" #breaks tmux
print -Pn "\e]2;%n@%m: %~\a" printf "\e]2;%s\a" "${title}"
;;
xterm*|*rxvt*)
print -Pn "\e]2;%n@%m: %~\a"
;; ;;
*) *)
# NOOP : # NOOP
;; ;;
esac esac
} }