diff --git a/README.md b/README.md index 9d30c35..2d7c181 100644 --- a/README.md +++ b/README.md @@ -1 +1,51 @@ -Shell agnostic shell startup commands. +# Shared shell profile + +This repository owns the login environment and interactive commands intended +to be shared by Bourne-family shells. + +"Shared" means shells capable of reading POSIX-style `sh`, such as `sh`, Bash, +Dash and—with appropriate compatibility—Zsh. It does not mean that the same +file can be sourced directly by shells with different languages, such as Fish +or Nushell. + +## Responsibilities + +- Install `~/.profile` as a symlink into this repository. +- Define XDG locations and general editor/browser environment variables. +- Construct PATH idempotently for language and user-level executable paths. +- Load environment setup that is portable at login, such as Cargo's `env` file. +- Provide common aliases and small interactive functions that are useful + across supported Bourne-family shells. + +## Boundaries + +The `profile` file must remain quiet, idempotent and safe for a POSIX shell to +source during login. It must not print an alias catalogue, configure a prompt, +perform interactive terminal operations or start background work. + +Interactive shells should source `aliases.sh` from their own RC file. The +login profile deliberately does not source it, because login profiles may also +run in non-interactive sessions. + +Shell-specific prompt, history, completion and initialization belongs in the +corresponding shell repository, currently `bash`. User services and timers +belong in the separate `systemd` repository. + +## Files + +- `profile`: portable login environment and PATH construction. +- `aliases.sh`: common interactive aliases and helper functions. +- `commands.tsv`: curated command descriptions and startup visibility. +- `commands.README.md`: format and maintenance instructions for `commands.tsv`. +- `install.sh`: installs the `~/.profile` symlink. + +## Alias portability + +`aliases.sh` is intended to become POSIX-compatible for Bourne-family shells, +but it currently contains some Bash-oriented constructs. Before another shell +sources it, replace or isolate uses of `source`, `disown`, `local`, `echo -e`, +Bash-style `cd --`, and the transitional `debug.log` alias name. + +External commands remain platform-specific by design: aliases for Pacman, +systemd, GNU utilities and local applications target this Arch Linux setup. +Syntax portability does not imply operating-system portability. diff --git a/aliases.sh b/aliases.sh index 9b8bba5..180d013 100644 --- a/aliases.sh +++ b/aliases.sh @@ -5,18 +5,14 @@ ALIASES_BLUE='\033[0;34m' # Blue ALIASES_WHITE='\033[1;37m' # White ALIASES_NC='\033[0m' # No Color -echo "Aliases added:" -echo -e "${ALIASES_WHITE} cs pc venv cdlf lfcd" -echo " e er et en ens ea ee" -echo " g gg disk-usage debug.log" -echo " backup update re mc" -echo " mac red alice phthalo zirconia datapasa ultra kermit singsay pi4" -echo -e " ${ALIASES_NC}client:${ALIASES_WHITE} crafty lv" +echo "Remember aliases:" +echo -e "${ALIASES_WHITE} et en ens ee" +echo " dusort debuglog mkcd" echo -e "${ALIASES_NC}" echo "" alias backup='sudo borgmatic create --verbosity 1 --files' -alias disk-usage='sudo du -h -d 2 .[^.]* * | sort -h' +alias disk-usage='printf "%s\n" "disk-usage is deprecated; use dusort instead." >&2' alias cs='lxc list -c ns4b,user.comment:comment' alias pc='pcmanfm . & disown' @@ -37,7 +33,36 @@ alias ee='nvim .' alias speak='/usr/local/src/kokora/speak' -alias debug.log='clear && echo "" > debug.log && tail -f debug.log' +debuglog() { + clear + : > debug.log + tail -f debug.log +} + +alias debug.log='printf "%s\n" "debug.log is deprecated; use debuglog instead." >&2' + +dusort() { + if [ "$#" -gt 1 ]; then + printf '%s\n' 'Usage: dusort [path]' >&2 + return 2 + fi + + _dusort_path=${1:-.} + if [ ! -e "$_dusort_path" ]; then + printf 'dusort: path does not exist: %s\n' "$_dusort_path" >&2 + unset _dusort_path + return 1 + fi + + if sudo du -h -d 2 -- "$_dusort_path" | sort -h; then + unset _dusort_path + return 0 + fi + + unset _dusort_path + return 1 +} + alias g='git status' alias gg='git add . && git commit -m "update" && git push' @@ -53,29 +78,91 @@ alias wget='wget --hsts-file="$XDG_DATA_HOME/wget-hsts"' alias grep='grep --colour=auto' alias egrep='egrep --colour=auto' alias fgrep='fgrep --colour=auto' -alias hgrep='history | grep --color=auto' - alias bc='bc -q -l' alias ytdl='yt-dlp --write-info-json --write-description --no-playlist' alias ytdlb='yt-dlp --write-info-json --write-description --no-playlist -a' alias ytdl-mp3='yt-dlp -f bestaudio --extract-audio --audio-format mp3 --embed-thumbnail --add-metadata' -alias mac='ssh rya@192.168.0.67' -alias pi4='ssh pi@192.168.0.11' -alias red='ssh ray@red.isnet.uk' -alias alice='ssh ray@alice.isnet.uk' -alias phthalo='ssh root@phthalo.isnet.uk' -alias zirconia='ssh ray@zirconia.isnet.uk' -alias zirconiarc='ssh runcloud@zirconia.isnet.uk' -alias datapasa='ssh root@144.31.38.58' -alias ultra='ssh gabbaell@mimas.usbx.me' -alias singsay="ssh ray@singsay.isnet.uk -p 53584" -alias kermit="ssh ray@kermit.isnet.uk -p 50308" +# Transitional aliases for destinations now managed by ~/.ssh/config. +alias mac='printf "%s\n" "mac is deprecated; use ssh mac instead." >&2' +alias pi4='printf "%s\n" "pi4 is deprecated; use ssh pi4 instead." >&2' +alias red='printf "%s\n" "red is deprecated; use ssh red instead." >&2' +alias alice='printf "%s\n" "alice is deprecated; use ssh alice instead." >&2' +alias phthalo='printf "%s\n" "phthalo is deprecated; use ssh phthalo instead." >&2' +alias zirconia='printf "%s\n" "zirconia is deprecated; use ssh zirconia instead." >&2' +alias zirconiarc='printf "%s\n" "zirconiarc is deprecated; use ssh zirconiarc instead." >&2' +alias datapasa='printf "%s\n" "datapasa is deprecated; use ssh datapasa instead." >&2' +alias ultra='printf "%s\n" "ultra is deprecated; use ssh ultra instead." >&2' +alias singsay='printf "%s\n" "singsay is deprecated; use ssh singsay instead." >&2' +alias kermit='printf "%s\n" "kermit is deprecated; use ssh kermit instead." >&2' +alias crafty='printf "%s\n" "crafty is deprecated; use ssh crafty instead." >&2' +alias lv='printf "%s\n" "lv is deprecated; use ssh lv instead." >&2' -# clients -alias crafty='ssh craftyqu@192.250.239.57' -alias lv='ssh nhg5vomib8ue@92.205.144.38' +commands() { + awk -F '\t' ' + NF == 0 { next } + NF != 3 || ($1 != "yes" && $1 != "no") || $2 == "" || $3 == "" { + printf "Invalid command reminder on line %d.\n", NR > "/dev/stderr" + invalid = 1 + next + } + seen[$2]++ { + printf "Duplicate command reminder for %s on line %d.\n", $2, NR > "/dev/stderr" + invalid = 1 + next + } + { + count++ + reminder[count] = $1 + command[count] = $2 + description[count] = $3 + if (length($2) > command_width) command_width = length($2) + if (length($3) > description_width) description_width = length($3) + } + END { + if (invalid) exit 1 + if (length("COMMAND") > command_width) command_width = length("COMMAND") + if (length("DESCRIPTION") > description_width) description_width = length("DESCRIPTION") + printf "%-*s %-*s %s\n", command_width, "COMMAND", description_width, "DESCRIPTION", "REMINDER" + for (row = 1; row <= count; row++) { + printf "%-*s %-*s %s\n", command_width, command[row], description_width, description[row], reminder[row] + } + } + ' "${XDG_CONFIG_HOME:-$HOME/.config}/profile/commands.tsv" +} + +_command_reminder() { + awk -F '\t' -v width="${COLUMNS:-80}" ' + NF == 0 { next } + NF != 3 || ($1 != "yes" && $1 != "no") || $2 == "" || $3 == "" { + printf "Invalid command reminder on line %d.\n", NR > "/dev/stderr" + invalid = 1 + next + } + seen[$2]++ { + printf "Duplicate command reminder for %s on line %d.\n", $2, NR > "/dev/stderr" + invalid = 1 + next + } + $1 == "yes" { command[++count] = $2 } + END { + if (invalid) exit 1 + if (width < 40) width = 80 + line = " " + for (row = 1; row <= count; row++) { + separator = (line == " " ? "" : " ") + if (length(line) + length(separator) + length(command[row]) > width) { + print line + line = " " command[row] + } else { + line = line separator command[row] + } + } + if (line != " ") print line + } + ' "${XDG_CONFIG_HOME:-$HOME/.config}/profile/commands.tsv" +} # lf gets confused by TERMINFO env var when running in tmux # https://github.com/gokcehan/lf/issues/138#issuecomment-464477665 @@ -97,6 +184,21 @@ lfcd() { lf -last-dir-path="$HOME"/.cache/lf-last-dir && cdlf } +hosts() { + if [ ! -r "$HOME/.ssh/config.d/hosts.conf" ]; then + printf '%s\n' 'SSH host configuration is unavailable.' >&2 + return 1 + fi + + awk ' + tolower($1) == "host" { + for (field = 2; field <= NF; field++) { + if ($field !~ /[*?!]/) print $field + } + } + ' "$HOME/.ssh/config.d/hosts.conf" +} + update() { echo -e "Executing \"${ALIASES_GREEN}pacman -Syu${ALIASES_NC}\" via \"${ALIASES_BLUE}archnews_wrap${ALIASES_NC}\" wrapper" @@ -104,15 +206,7 @@ update() { systemctl --user start --no-block package-status-refresh.service >/dev/null 2>&1 || true } -re() { - if [ -n "${2:-}" ]; then - git clone "ssh://git@git.rayelliott.dev:3222/rayelliott/$1.git" "$2" - else - git clone "ssh://git@git.rayelliott.dev:3222/rayelliott/$1.git" - fi -} - -mc() { +mkcd() { mkdir "$1" || return cd "$1" || return } diff --git a/commands.README.md b/commands.README.md new file mode 100644 index 0000000..7b94f5b --- /dev/null +++ b/commands.README.md @@ -0,0 +1,23 @@ +# Command reminders + +`commands.tsv` is the manually curated source for the shell's command reminder. +It is not an inventory of every installed executable. + +Each non-empty line contains three tab-separated fields: + +```text +reminder command description +``` + +- `reminder` must be `yes` or `no`. `yes` includes the command in the shell + reminder; `no` keeps it available only in the full listing. +- `command` is the name entered at the shell. +- `description` is a brief explanation displayed by `commands`. + +The data file deliberately has no header or comments. Blank lines are allowed; +put explanatory material in this README instead. Duplicate commands, unknown +reminder values and malformed rows are reported as errors. + +Run `commands` to display every entry. To add or remove something from the +shell reminder, edit only its `reminder` field; do not duplicate the command +list in shell configuration. diff --git a/commands.tsv b/commands.tsv new file mode 100644 index 0000000..15bdf6b --- /dev/null +++ b/commands.tsv @@ -0,0 +1,17 @@ +yes nap snippet manager +yes hyprpicker Wayland colour picker +yes nmcli NetworkManager command-line client +yes lftp file-transfer client +yes lxc-wp create a local WordPress LXC project +yes qv4l2 Video4Linux control panel +no cheat command-line cheatsheets +no vimv batch rename files in Vim +yes rclone sync files with cloud storage +yes mid3v2 edit ID3 audio metadata +yes zathura document viewer +yes tesseract optical character recognition +yes remmina remote desktop client +yes wl-copy copy to the Wayland clipboard +yes wl-paste paste from the Wayland clipboard +yes hosts list SSH destinations +yes commands list remembered commands and descriptions