This commit is contained in:
Ray Elliott 2026-10-27 13:32:52 +00:00
commit baa2d124b0
10 changed files with 14 additions and 372 deletions

View file

@ -1,63 +1,29 @@
# Shared shell profile # Shared login profile
This repository owns the login environment and interactive commands intended This repository owns the portable login environment. It is deliberately quiet,
to be shared by Bourne-family shells. shell-agnostic and independent of interactive shell configuration.
"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 ## Responsibilities
- Install `~/.profile` as a symlink into this repository. - Install `~/.profile` as a symlink into this repository.
- Define XDG locations and general editor/browser environment variables. - Define XDG locations and general editor/browser environment variables.
- Construct PATH idempotently for language and user-level executable paths. - Construct `PATH` idempotently for language and user-level executables.
- Load environment setup that is portable at login, such as Cargo's `env` file. - Load portable login environment setup, such as Cargo's `env` file.
- Provide common aliases and small interactive functions that are useful
across supported Bourne-family shells.
- Isolate Arch Linux commands from otherwise portable shell configuration.
## Boundaries ## Boundaries
The `profile` file must remain quiet, idempotent and safe for a POSIX shell to The `profile` file must remain safe for a POSIX shell to source during login. It
source during login. It must not print an alias catalogue, configure a prompt, must not print output, configure a prompt, define interactive conveniences,
perform interactive terminal operations or start background work. perform terminal operations or start background work.
Interactive shells should source `interactive.sh` from their own RC file. The Aliases, interactive functions, reminders, command catalogues, completion,
login profile deliberately does not source it, because login profiles may also history and prompt configuration belong to the relevant shell repository. User
run in non-interactive sessions. services and timers belong in the separate `systemd` repository.
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 ## Files
- `profile`: portable login environment and PATH construction. - `profile`: portable login environment and `PATH` construction.
- `interactive.sh`: POSIX loader and manually curated alias reminder.
- `aliases.sh`: common POSIX interactive aliases and helper functions.
- `commands.sh`: command-catalogue display and validation functions.
- `hosts.sh`: SSH destination listing function.
- `platform/arch.sh`: Arch Linux applications, GNU options and Pacman/systemd
integration, written with POSIX shell syntax.
- `commands.tsv`: curated command descriptions and reminder visibility.
- `commands.README.md`: format and maintenance instructions for `commands.tsv`.
- `memory.tsv`: selectively curated shell-memory questions and answers.
- `memory.README.md`: format, scope and daily-selection behavior for the memory
question bank.
- `install.sh`: installs the `~/.profile` symlink. - `install.sh`: installs the `~/.profile` symlink.
## Alias portability Interactive Bash uses this environment through the conventional `~/.profile`
interface. This repository does not reference or load the Bash repository.
The shared interactive files use POSIX shell syntax. Bash-only compatibility
aliases—including names that are deliberately being retired—live in the Bash
repository's `aliases.bash` instead.
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.
The Arch `update` function runs the local `archnews_wrap` Pacman workflow and,
after a successful upgrade, requests a non-blocking refresh from the systemd
user service `package-status-refresh.service`.

View file

@ -1,79 +0,0 @@
#!/bin/sh
# Common interactive aliases and helpers using POSIX 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 <directory>' >&2
return 2
fi
mkdir -p "$1" || return
cd "$1" || return
}

View file

@ -1,23 +0,0 @@
# 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.

View file

@ -1,68 +0,0 @@
#!/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}/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"
}

View file

@ -1,16 +0,0 @@
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
1 yes nap snippet manager
2 yes hyprpicker Wayland colour picker
3 yes nmcli NetworkManager command-line client
4 yes lftp file-transfer client
5 yes lxc-wp create a local WordPress LXC project
6 yes qv4l2 Video4Linux control panel
7 no cheat command-line cheatsheets
8 no vimv batch rename files in Vim
9 yes rclone sync files with cloud storage
10 yes zathura document viewer
11 yes tesseract optical character recognition
12 yes remmina remote desktop client
13 yes wl-copy copy to the Wayland clipboard
14 yes wl-paste paste from the Wayland clipboard
15 yes hosts list SSH destinations
16 yes commands list remembered commands and descriptions

View file

@ -1,16 +0,0 @@
#!/bin/sh
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"
}

View file

@ -1,20 +0,0 @@
#!/bin/sh
# Shared interactive setup for POSIX-compatible shells.
_profile_interactive_dir=${XDG_CONFIG_HOME:-$HOME/.config}/profile
. "$_profile_interactive_dir/aliases.sh"
. "$_profile_interactive_dir/commands.sh"
. "$_profile_interactive_dir/hosts.sh"
if [ -r /etc/arch-release ]; then
. "$_profile_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 _profile_interactive_dir

View file

@ -1,23 +0,0 @@
# Shell memory questions
`memory.tsv` is a selectively curated question-and-answer bank for reinforcing
useful shell 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.

View file

@ -1,23 +0,0 @@
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 <directory>
1 nap What do you use as a snippet manager? nap
2 hyprpicker What do you use as a colour picker? hyprpicker
3 nmcli What manages NetworkManager from the terminal? nmcli
4 lftp What do you use for interactive file transfers? lftp
5 lxc-wp What creates a local WordPress LXC project? lxc-wp
6 qv4l2 What opens the Video4Linux control panel? qv4l2
7 cheat What displays command-line cheatsheets? cheat
8 vimv What lets you batch rename files in Vim? vimv
9 rclone What synchronizes files with cloud storage? rclone
10 zathura What lightweight application opens documents? zathura
11 tesseract What performs optical character recognition? tesseract
12 remmina What opens remote desktop connections? remmina
13 wl-copy What copies text to the Wayland clipboard? wl-copy
14 wl-paste What pastes text from the Wayland clipboard? wl-paste
15 hosts What lists your configured SSH destinations? hosts
16 commands What lists remembered commands and their descriptions? commands
17 et What opens TODO.md for editing? et
18 en What opens NOTES.md for editing? en
19 ens What opens NEXT_STEPS.md for editing? ens
20 ee What opens the current directory in Neovim? ee
21 dusort What displays disk usage sorted by size? dusort [path]
22 debuglog What clears and follows debug.log? debuglog
23 mkcd What creates a directory and enters it? mkcd <directory>

View file

@ -1,56 +0,0 @@
#!/bin/sh
# Interactive 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
}