main dotfiles / dot_config / yash / base.sh
Eric Bower  ·  2026-08-20
  1set --brace-expand    # bash-like extended exp
  2set --extended-glob   # recursive pathname exp
  3set --no-clobber      # prevent redirections from overwriting existing files
  4set --no-unset        # don't expand non-existent variables to empty strings
  5set --hist-space      # don't save cmds starting with a space in history
  6set --notify-le       # print job status update asap while line-editing
  7set --le-no-conv-meta # terminfo data broken; meta flags ignore utf-8
  8set --le-predict      # enable line prediction
  9set -o vi             # vim mode
 10
 11bindkey --vi-insert '\^F' accept-prediction
 12
 13sh() { yash --posix "$@"; }
 14yash() { command yash "$@"; }
 15
 16if [ "${COLORTERM-}" = "truecolor" ] || [ "${COLORTERM-}" = "24bit" ] || \
 17  [ "$(tput colors 2>/dev/null || echo 0)" -ge 8 ]; then
 18  ls() { command ls --color=auto "$@"; }
 19  grep() { command grep --color=auto "$@"; }
 20fi
 21
 22: ${LOGNAME:=$(logname)} ${HOSTNAME:=$(uname -n)}
 23# disable confusing treatment of arguments in the echo command
 24: ${ECHO_STYLE:=RAW}
 25
 26if ! [ "${HISTFILE-}" ]; then
 27  HISTFILE=${XDG_STATE_HOME:-~/.local/state}/yash/history
 28fi
 29# create HISTFILE parent directory if missing
 30! [ -d "${HISTFILE%/*}" ] && mkdir -p "${HISTFILE%/*}"
 31
 32HISTSIZE=5000
 33
 34# default mail check interval is too long
 35MAILCHECK=0
 36
 37# emulate bash's $SHLVL
 38if [ "${_old_shlvl+set}" != set ]; then
 39  _old_shlvl=${SHLVL-}
 40fi
 41SHLVL=$((_old_shlvl+1)) 2>/dev/null || SHLVL=1
 42export SHLVL
 43
 44# initialize event handlers
 45COMMAND_NOT_FOUND_HANDLER=()
 46PROMPT_COMMAND=()
 47POST_PROMPT_COMMAND=()
 48YASH_AFTER_CD=()
 49
 50# define prompt
 51_hc='\f${${SSH_CONNECTION:+y}:-g}.'
 52if [ "$(id -u)" -eq 0 ]; then
 53  _uc='\fr.'     # red username for root
 54  _2c='\fr.'     # red PS2 for root
 55else
 56  _uc=$_hc _hc=  # same username color as hostname for non-root user
 57  _2c=           # PS2 in normal color for non-root user
 58fi
 59# The main prompt ($YASH_PS1) contains the username, hostname, working
 60# directory, last exit status (only if non-zero), and $SHLVL (only if
 61# non-one).
 62YASH_PS1=$_uc'${LOGNAME}'$_hc'@${HOSTNAME%%.*}\fd. '\
 63'${${${PWD:/~/\~}##*/}:-$PWD} ${{?:/0/}:+\\fr.$?\\fd. }${{SHLVL-0}:/1}\$ '
 64YASH_PS1S='\fo.'
 65YASH_PS2=$_2c'> '
 66YASH_PS2S=$YASH_PS1S
 67YASH_PS4='\fm.+ '
 68YASH_PS4S='\fmo.'
 69unset _hc _uc _2c
 70# No escape sequences allowed in the POSIXly-correct mode.
 71PS1='${LOGNAME}@${HOSTNAME%%.*} '$PS1
 72
 73# find escape sequence to change terminal window title
 74case "$TERM" in
 75  (xterm*|gnome*|putty*|cygwin*|alacritty*|foot*|kitty*|wezterm*|ghostty*|rxvt*|st*|tmux*|screen*|rio*|contour*)
 76    _tsl='\033]0;' _fsl='\a' ;;
 77  (*)
 78    _tsl=$( (tput tsl 0; echo) 2>/dev/null |
 79    sed -e 's/\\/\\\\/g' -e 's/%/%%/g')
 80    _fsl=$( (tput fsl  ; echo) 2>/dev/null |
 81    sed -e 's/\\/\\\\/g' -e 's/%/%%/g')
 82    if [ -z "$_tsl" ] || [ -z "$_fsl" ]; then
 83      if [ "${TERM:-dumb}" != "dumb" ] && [ "${TERM:-dumb}" != "linux" ]; then
 84        _tsl='\033]0;' _fsl='\a'
 85      fi
 86    fi
 87    ;;
 88esac
 89# if terminal window title can be changed...
 90if [ "$_tsl" ] && [ "$_fsl" ]; then
 91  # set terminal window title on each prompt
 92  _set_term_title() {
 93    if [ -t 2 ]; then
 94      printf "$_tsl"'%s@%s:%s'"$_fsl" "${LOGNAME}" "${HOSTNAME%%.*}" \
 95        "${${PWD:/$HOME/\~}/#$HOME\//\~\/}" >&2
 96    fi
 97  }
 98  # set terminal window title when executing a command
 99  _set_cmd_title() {
100    if [ -t 2 ] && [ -n "${COMMAND-}" ]; then
101      local nl="
102"
103      local cmd="${COMMAND%%"$nl"*}"
104      if [ -n "$cmd" ]; then
105        printf "$_tsl"'%s'"$_fsl" "$cmd" >&2
106      fi
107    fi
108  }
109  PROMPT_COMMAND=("$PROMPT_COMMAND" '_set_term_title')
110  POST_PROMPT_COMMAND=("$POST_PROMPT_COMMAND" '_set_cmd_title')
111fi
112
113_osc7_cwd() {
114  local tmp="${PWD}" encoded="" cut c esc
115  esc="$(printf '\33')"  # or: esc="$(/usr/bin/printf '\033')"
116  while [ -n "$tmp" ]; do
117    cut="${tmp#?}"
118    c="${tmp%"$cut"}"
119    case "$c" in
120      [-/:_.!\'\(\)~[:alnum:]]) encoded="$encoded$c" ;;
121      *) encoded="$encoded$(printf '%%%02X' "'$c")" ;;
122    esac
123    tmp="$cut"
124  done
125  printf '%s]7;file://%s%s%s\\' "$esc" "${HOSTNAME:-$(uname -n)}" "$encoded" "$esc" > /dev/tty
126}
127
128_update_direnv() {
129  if ! command -v direnv > /dev/null 2>&1; then
130    return
131  fi
132
133 eval "$(
134   direnv export json |
135   jq -r 'to_entries | .[] |
136   if .value == null then
137     @sh "unset \(.key)"
138   else
139     @sh "export \(.key)=\(.value)"
140   end'
141 )"
142}
143
144YASH_AFTER_CD=("$YASH_AFTER_CD" _osc7_cwd _update_direnv)
145_osc7_cwd
146_update_direnv > /dev/null 2>&1
147
148# kak: filetype=sh