# /etc/zsh/zshrc — the system-wide interactive zsh configuration for SchOS.
#
# Deliberately short. This sets up the things an interactive shell is useless
# without -- history, completion, and the keys a console sends -- and stops.
# Anything beyond that belongs in a user's own ~/.zshrc, which is the file zsh
# reads after this one.

# ---------------------------------------------------------------------------
# History
# ---------------------------------------------------------------------------
HISTFILE=${HOME:-/root}/.zsh_history
HISTSIZE=2000
SAVEHIST=2000
setopt APPEND_HISTORY INC_APPEND_HISTORY SHARE_HISTORY
setopt HIST_IGNORE_DUPS HIST_IGNORE_SPACE HIST_REDUCE_BLANKS

# ---------------------------------------------------------------------------
# Behaviour
# ---------------------------------------------------------------------------
setopt AUTO_CD                 # `cd /tmp` is implied by typing `/tmp`
setopt EXTENDED_GLOB
setopt INTERACTIVE_COMMENTS    # a # in an interactive line is a comment
setopt NO_BEEP                 # SchOS has no audio, but it would also scroll
unsetopt FLOW_CONTROL          # ^S/^Q are worth more as keys than as flow control

# ---------------------------------------------------------------------------
# Keys
# ---------------------------------------------------------------------------
# Emacs bindings, because that is what every other line editor on the system
# does -- mksh's default and the kernel's own canonical-mode editing both.
bindkey -e

# Home, End, Delete and the arrows, taken from terminfo rather than written
# out as escape sequences. The sequences differ between the SchOS console and
# a serial terminal; the terminal's own description does not.
typeset -A _sch_keys=(
  "${terminfo[khome]}"  beginning-of-line
  "${terminfo[kend]}"   end-of-line
  "${terminfo[kdch1]}"  delete-char
  "${terminfo[kich1]}"  overwrite-mode
  "${terminfo[kcuu1]}"  up-line-or-search
  "${terminfo[kcud1]}"  down-line-or-search
  "${terminfo[kcub1]}"  backward-char
  "${terminfo[kcuf1]}"  forward-char
)
for _k _w in "${(@kv)_sch_keys}"; do
  [[ -n $_k ]] && bindkey -- "$_k" "$_w"
done
unset _sch_keys _k _w

# A terminal that has just been resized, or that zsh has just taken over, may
# not have told terminfo yet. This puts the keypad in the mode the escape
# sequences above were described for, and takes it back out on exit.
if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then
  autoload -Uz add-zle-hook-widget 2>/dev/null
  function _sch_zle_init { echoti smkx }
  function _sch_zle_line_finish { echoti rmkx }
  zle -N zle-line-init _sch_zle_init
  zle -N zle-line-finish _sch_zle_line_finish
fi

# ---------------------------------------------------------------------------
# Completion
# ---------------------------------------------------------------------------
# Completion is NOT initialised here yet, and the reason is a filesystem
# measurement rather than anything to do with zsh.
#
# A small write to SchFS costs about 58 ms, because every operation is its own
# transaction group and a commit is two cache flushes and an uberblock write --
# see the comment at the top of kernel/fs/schfs/kmount.c, which describes the
# trade-off exactly. Measured on this machine, 200 writes:
#
#     to one open file on SchFS   11.75 s   (58 ms each)
#     open + write + close each   21.39 s   (107 ms each)
#     to /dev/null                 0.14 s   (0.7 ms each)
#
# compdump writes the digest with a few thousand separate `print` calls, so
# compinit -d takes minutes and looks exactly like a hang. compinit itself is
# fine: with -D, which skips the dump, it finishes in 3.6 seconds.
#
# So this waits for deferred commits. When small writes stop costing a disk
# barrier each, delete this comment and uncomment the three lines below.
#
#   autoload -Uz compinit
#   compinit -u -d ${HOME:-/root}/.zcompdump
#
# Until then, completion is available on demand in a shell you do not mind
# waiting three seconds for:
#
#   autoload -Uz compinit && compinit -D -u
#
# -u is not optional whenever this is turned back on. Without it compinit runs
# compaudit, decides the function directories are "insecure" because SchOS has
# no ownership model to check, and *prompts* for an answer on a shell that is
# still starting up -- which is a real hang, unlike the one above.

# These take effect as soon as compinit is turned on above; a zstyle with no
# completion system to read it is inert, not an error.
zstyle ':completion:*' menu select
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}'     # case-insensitive
zstyle ':completion:*' list-colors ''
zstyle ':completion:*:descriptions' format '%F{244}%d%f'

# ---------------------------------------------------------------------------
# Prompt
# ---------------------------------------------------------------------------
# The accent violet from include/gfx/theme.h, which is 99 in the 256-colour cube
# and falls back to magenta on the 8-colour console. The last-status marker is
# the only thing here that ever turns red -- same rule as the rest of the
# system: normal states are calm, only failure is loud.
setopt PROMPT_SUBST
# The chevron is », not ❯. The console font is CP437 and has a glyph for
# the first and none for the second, so ❯ renders as '?' -- correctly, since
# drawing a *different* character would be worse, but it still looks broken.
PROMPT='%F{magenta}%B%n@schos%b%f %F{cyan}%~%f %(?.%F{green}».%F{red}»)%f '
RPROMPT=''
