From 2ac0f22dba2a07d0f6ee81dbfd74ee704066b3e1 Mon Sep 17 00:00:00 2001 From: ray Date: Tue, 27 Oct 2026 13:32:57 +0000 Subject: [PATCH] update --- README.md | 22 ++++++--- aliases.sh | 79 ++++++++++++++++++++++++++++++++ bashrc.d/30-integrations.bash | 6 ++- bashrc.d/90-memory-question.bash | 2 +- commands.README.md | 23 ++++++++++ commands.sh | 68 +++++++++++++++++++++++++++ commands.tsv | 16 +++++++ hosts.sh | 18 ++++++++ interactive.sh | 20 ++++++++ memory.README.md | 23 ++++++++++ memory.tsv | 23 ++++++++++ platform/arch.sh | 56 ++++++++++++++++++++++ 12 files changed, 346 insertions(+), 10 deletions(-) create mode 100644 aliases.sh create mode 100644 commands.README.md create mode 100644 commands.sh create mode 100644 commands.tsv create mode 100644 hosts.sh create mode 100644 interactive.sh create mode 100644 memory.README.md create mode 100644 memory.tsv create mode 100644 platform/arch.sh diff --git a/README.md b/README.md index 4da262e..448f69c 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,10 @@ the Bash login sequence. - Configure Bash history, prompt rendering, completion and command-not-found behaviour. - Initialize Bash integrations such as NVM, Pyenv, z.lua and gitstatus. +- Own interactive aliases, functions and their curated command catalogue. +- Isolate Arch-specific interactive commands from general Bash configuration. - Display the startup greeting and cached package status. - Display `TODO.md` and `.autonote.md` after successful directory changes. -- Load common interactive aliases from the `profile` repository. ## Boundaries @@ -20,8 +21,6 @@ This repository does not own: - Portable login environment variables or shared PATH construction. Those belong in the `profile` repository. -- Common aliases intended for more than one Bourne-family shell. Those load - through `profile/interactive.sh`; genuinely Bash-specific aliases live here. - User services, timers or background refresh logic. Those belong in the `systemd` repository. Bash may consume their cached output or request a non-blocking service start. @@ -44,7 +43,16 @@ shell is not interactive. - `bash_profile`: connects Bash login startup to the shared profile and Bash RC. - `bashrc`: interactive guard and ordered module loader. - `bashrc.d/`: numbered interactive Bash modules; lower numbers load first. -- `aliases.bash`: Bash-specific and warning-only transition aliases. +- `interactive.sh`: loads interactive aliases, functions and reminders. +- `aliases.sh`: general interactive aliases and functions, written portably. +- `aliases.bash`: aliases requiring Bash-specific naming or behaviour. +- `commands.sh`: command-catalogue display and validation functions. +- `commands.tsv`: curated command descriptions and reminder visibility. +- `commands.README.md`: format and maintenance instructions for the catalogue. +- `hosts.sh`: SSH destination listing function. +- `memory.tsv`: curated daily shell-memory questions and answers. +- `memory.README.md`: memory-bank format and selection behaviour. +- `platform/arch.sh`: Arch-specific applications and system integration. - `gitstatus-custom.sh`: prompt integration for gitstatus. - `cheat.bash`: completion for `cheat`. - `install.sh`: installs the home-directory symlinks and gitstatus dependency. @@ -59,7 +67,7 @@ The loader sources every readable `bashrc.d/*.bash` file in lexical order: - `00-core.bash`: colors, history, terminal and Readline settings. - `10-prompt.bash`: prompt, gitstatus and per-command history flushing. - `20-greeting.bash`: calendar-day greeting and adjective selection. -- `30-integrations.bash`: shared aliases, NVM and z.lua. +- `30-integrations.bash`: interactive commands, NVM and z.lua. - `40-status.bash`: command reminders, memory and cached package status. - `50-completions.bash`: command-specific completion setup. - `60-directory-notes.bash`: `TODO.md` and `.autonote.md` display after `cd`. @@ -78,5 +86,5 @@ local package transaction, Bash requests a non-blocking start of `package-status-refresh.service`, subject to a five-minute retry backoff. The refresh service and 30-minute timer are owned and documented by the -`systemd` repository. The Arch `update` wrapper in the `profile` repository -also requests a refresh after a successful upgrade. +`systemd` repository. The Arch `update` wrapper in this repository also +requests a refresh after a successful upgrade. diff --git a/aliases.sh b/aliases.sh new file mode 100644 index 0000000..c52bc32 --- /dev/null +++ b/aliases.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# Interactive aliases and helpers written with portable shell syntax. + +alias venv='. ./venv/bin/activate' + +alias e='nvim' +alias er='nvim README.md' +alias et='nvim TODO.md' +alias en='nvim NOTES.md' +alias ens='nvim NEXT_STEPS.md' +alias ea='nvim .autonote.md' +alias ee='nvim .' + +debuglog() { + clear + : > debug.log + tail -f debug.log +} + +alias g='git status' + +gg() { + _gg_message=${*:-update} + if git add . && git commit -m "$_gg_message" && git push; then + unset _gg_message + return 0 + fi + + unset _gg_message + return 1 +} + +wget() { + printf 'wget wrapper: using HSTS file %s\n' "$XDG_DATA_HOME/wget-hsts" >&2 + command wget --hsts-file="$XDG_DATA_HOME/wget-hsts" "$@" +} + +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' + +# lf gets confused by TERMINFO when running in tmux. +# https://github.com/gokcehan/lf/issues/138#issuecomment-464477665 +if [ -n "${TERMINFO:-}" ]; then + alias lf='TERMINFO= lf -last-dir-path="$HOME/.cache/lf-last-dir"' +else + alias lf='lf -last-dir-path="$HOME/.cache/lf-last-dir"' +fi + +cdlf() { + [ -r "$HOME/.cache/lf-last-dir" ] || return 1 + IFS= read -r _cdlf_last_dir < "$HOME/.cache/lf-last-dir" + [ -n "$_cdlf_last_dir" ] || return 1 + + if cd "$_cdlf_last_dir"; then + unset _cdlf_last_dir + return 0 + fi + + unset _cdlf_last_dir + return 1 +} + +lfcd() { + lf -last-dir-path="$HOME/.cache/lf-last-dir" && cdlf +} + +mkcd() { + if [ "$#" -ne 1 ]; then + printf '%s\n' 'Usage: mkcd ' >&2 + return 2 + fi + + mkdir -p "$1" || return + cd "$1" || return +} diff --git a/bashrc.d/30-integrations.bash b/bashrc.d/30-integrations.bash index d950672..1308e1b 100644 --- a/bashrc.d/30-integrations.bash +++ b/bashrc.d/30-integrations.bash @@ -1,7 +1,9 @@ # shellcheck shell=bash -[ -r "$HOME/.config/profile/interactive.sh" ] && . "$HOME/.config/profile/interactive.sh" -[ -r "$HOME/.config/bash/aliases.bash" ] && . "$HOME/.config/bash/aliases.bash" +_bash_config_home=${XDG_CONFIG_HOME:-$HOME/.config}/bash +[ -r "$_bash_config_home/interactive.sh" ] && . "$_bash_config_home/interactive.sh" +[ -r "$_bash_config_home/aliases.bash" ] && . "$_bash_config_home/aliases.bash" +unset _bash_config_home export NVM_DIR="$HOME/.nvm" if [[ -s "$NVM_DIR/nvm.sh" ]]; then diff --git a/bashrc.d/90-memory-question.bash b/bashrc.d/90-memory-question.bash index 0db6e4b..5a1c660 100644 --- a/bashrc.d/90-memory-question.bash +++ b/bashrc.d/90-memory-question.bash @@ -1,6 +1,6 @@ # shellcheck shell=bash -_memory_file="${XDG_CONFIG_HOME:-$HOME/.config}/profile/memory.tsv" +_memory_file="${XDG_CONFIG_HOME:-$HOME/.config}/bash/memory.tsv" _memory_question_color='\033[38;5;11m' _memory_names=() _memory_questions=() diff --git a/commands.README.md b/commands.README.md new file mode 100644 index 0000000..e07f160 --- /dev/null +++ b/commands.README.md @@ -0,0 +1,23 @@ +# Command reminders + +`commands.tsv` is the manually curated source for Bash'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.sh b/commands.sh new file mode 100644 index 0000000..bf4a145 --- /dev/null +++ b/commands.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +# Display and validate the curated command catalogue. + +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}/bash/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}/bash/commands.tsv" +} diff --git a/commands.tsv b/commands.tsv new file mode 100644 index 0000000..d50c3c6 --- /dev/null +++ b/commands.tsv @@ -0,0 +1,16 @@ +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 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 diff --git a/hosts.sh b/hosts.sh new file mode 100644 index 0000000..441be02 --- /dev/null +++ b/hosts.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# List the concrete destinations defined by the user's SSH configuration. + +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" +} diff --git a/interactive.sh b/interactive.sh new file mode 100644 index 0000000..4a626d5 --- /dev/null +++ b/interactive.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# Interactive Bash setup assembled from focused, mostly portable files. + +_bash_interactive_dir=${XDG_CONFIG_HOME:-$HOME/.config}/bash + +. "$_bash_interactive_dir/aliases.sh" +. "$_bash_interactive_dir/commands.sh" +. "$_bash_interactive_dir/hosts.sh" + +if [ -r /etc/arch-release ]; then + . "$_bash_interactive_dir/platform/arch.sh" +fi + +printf '%s\n' 'Remember aliases:' +printf '\033[1;37m%s\n' ' et en ens ee' +printf '%s\n' ' dusort debuglog mkcd' +printf '\033[0m\n\n' + +unset _bash_interactive_dir diff --git a/memory.README.md b/memory.README.md new file mode 100644 index 0000000..addc974 --- /dev/null +++ b/memory.README.md @@ -0,0 +1,23 @@ +# Shell memory questions + +`memory.tsv` is a selectively curated question-and-answer bank for reinforcing +useful Bash commands. It deliberately excludes internal functions, standard +command overrides and deprecated transition aliases. + +Each non-empty line contains three tab-separated fields: + +```text +name question answer +``` + +- `name` is a unique stable identifier, normally the command or alias name. +- `question` is displayed on shell startup. +- `answer` is displayed by running `answerpls` in that terminal. + +The file has no header or comments. Empty fields, duplicate names and malformed +rows are errors. + +Bash selects one entry deterministically from the local calendar date. Every +terminal opened on the same day therefore shows the same question without +requiring a state file. Editing the bank may change which question maps to a +given date. diff --git a/memory.tsv b/memory.tsv new file mode 100644 index 0000000..8617f4e --- /dev/null +++ b/memory.tsv @@ -0,0 +1,23 @@ +nap What do you use as a snippet manager? nap +hyprpicker What do you use as a colour picker? hyprpicker +nmcli What manages NetworkManager from the terminal? nmcli +lftp What do you use for interactive file transfers? lftp +lxc-wp What creates a local WordPress LXC project? lxc-wp +qv4l2 What opens the Video4Linux control panel? qv4l2 +cheat What displays command-line cheatsheets? cheat +vimv What lets you batch rename files in Vim? vimv +rclone What synchronizes files with cloud storage? rclone +zathura What lightweight application opens documents? zathura +tesseract What performs optical character recognition? tesseract +remmina What opens remote desktop connections? remmina +wl-copy What copies text to the Wayland clipboard? wl-copy +wl-paste What pastes text from the Wayland clipboard? wl-paste +hosts What lists your configured SSH destinations? hosts +commands What lists remembered commands and their descriptions? commands +et What opens TODO.md for editing? et +en What opens NOTES.md for editing? en +ens What opens NEXT_STEPS.md for editing? ens +ee What opens the current directory in Neovim? ee +dusort What displays disk usage sorted by size? dusort [path] +debuglog What clears and follows debug.log? debuglog +mkcd What creates a directory and enters it? mkcd diff --git a/platform/arch.sh b/platform/arch.sh new file mode 100644 index 0000000..7a7a6ff --- /dev/null +++ b/platform/arch.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +# Interactive Bash commands specific to this Arch Linux workstation. + +_ARCH_GREEN='\033[0;32m' +_ARCH_BLUE='\033[0;34m' +_ARCH_NC='\033[0m' + +alias backup='sudo borgmatic create --verbosity 1 --files' +alias cs='lxc list -c ns4b,user.comment:comment' + +pc() { + nohup pcmanfm . >/dev/null 2>&1 & +} + +# Expand aliases for commands following sudo. +alias sudo='sudo ' + +alias speak='/usr/local/src/kokora/speak' + +alias ls='LC_COLLATE=C ls --color=auto -h --group-directories-first --time-style=+"%d.%m.%Y %H:%M" -F' +alias cp='cp -irv' +alias mkdir='mkdir -vp' +alias mv='mv -iv' +alias rm='rm -dv' +alias grep='grep --colour=auto' + +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 +} + +update() { + printf 'Executing "%bpacman -Syu%b" via "%barchnews_wrap%b" wrapper\n' \ + "$_ARCH_GREEN" "$_ARCH_NC" "$_ARCH_BLUE" "$_ARCH_NC" + + sudo "$HOME/.src/archnews/archnews_wrap" -Syu || return + systemctl --user start --no-block package-status-refresh.service >/dev/null 2>&1 || true +}