update
This commit is contained in:
parent
7a97c460d8
commit
c3c680ecca
11 changed files with 364 additions and 356 deletions
36
README.md
36
README.md
|
|
@ -20,8 +20,8 @@ This repository does not own:
|
||||||
|
|
||||||
- Portable login environment variables or shared PATH construction. Those
|
- Portable login environment variables or shared PATH construction. Those
|
||||||
belong in the `profile` repository.
|
belong in the `profile` repository.
|
||||||
- Common aliases intended for more than one Bourne-family shell. Those belong
|
- Common aliases intended for more than one Bourne-family shell. Those load
|
||||||
in `profile/aliases.sh`; genuinely Bash-specific aliases may live here.
|
through `profile/interactive.sh`; genuinely Bash-specific aliases live here.
|
||||||
- User services, timers or background refresh logic. Those belong in the
|
- User services, timers or background refresh logic. Those belong in the
|
||||||
`systemd` repository. Bash may consume their cached output or request a
|
`systemd` repository. Bash may consume their cached output or request a
|
||||||
non-blocking service start.
|
non-blocking service start.
|
||||||
|
|
@ -42,10 +42,40 @@ shell is not interactive.
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
- `bash_profile`: connects Bash login startup to the shared profile and Bash RC.
|
- `bash_profile`: connects Bash login startup to the shared profile and Bash RC.
|
||||||
- `bashrc`: interactive Bash configuration.
|
- `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.
|
||||||
- `gitstatus-custom.sh`: prompt integration for gitstatus.
|
- `gitstatus-custom.sh`: prompt integration for gitstatus.
|
||||||
- `cheat.bash`: completion for `cheat`.
|
- `cheat.bash`: completion for `cheat`.
|
||||||
- `install.sh`: installs the home-directory symlinks and gitstatus dependency.
|
- `install.sh`: installs the home-directory symlinks and gitstatus dependency.
|
||||||
|
|
||||||
Run `install.sh` when initially installing the repository. It preserves an
|
Run `install.sh` when initially installing the repository. It preserves an
|
||||||
existing destination before creating each symlink.
|
existing destination before creating each symlink.
|
||||||
|
|
||||||
|
## Bash RC modules
|
||||||
|
|
||||||
|
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.
|
||||||
|
- `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`.
|
||||||
|
- `70-development.bash`: OpenCode and Pyenv initialization.
|
||||||
|
|
||||||
|
Keep cross-module dependencies explicit through this numbering. New modules
|
||||||
|
should own one coherent area rather than becoming another general-purpose RC.
|
||||||
|
|
||||||
|
## Package-status integration
|
||||||
|
|
||||||
|
`40-status.bash` is a read-only consumer of the package cache at
|
||||||
|
`~/.cache/package-status/status`. It never runs Pacman or synchronizes package
|
||||||
|
databases during shell startup. When the cache is missing, stale or predates a
|
||||||
|
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.
|
||||||
|
|
|
||||||
21
aliases.bash
Normal file
21
aliases.bash
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Warning-only transition aliases that rely on Bash alias naming/behaviour.
|
||||||
|
|
||||||
|
alias disk-usage='printf "%s\n" "disk-usage is deprecated; use dusort instead." >&2'
|
||||||
|
alias debug.log='printf "%s\n" "debug.log is deprecated; use debuglog instead." >&2'
|
||||||
|
|
||||||
|
# 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'
|
||||||
359
bashrc
359
bashrc
|
|
@ -1,359 +1,12 @@
|
||||||
# shellcheck shell=bash
|
# shellcheck shell=bash
|
||||||
|
|
||||||
# If not running interactively, don't do anything.
|
# Interactive Bash only. Login environment belongs to ~/.profile.
|
||||||
[[ $- != *i* ]] && return
|
[[ $- != *i* ]] && return
|
||||||
|
|
||||||
# Color definitions
|
_bash_config_dir=${XDG_CONFIG_HOME:-$HOME/.config}/bash
|
||||||
_WHITE='\033[1;37m' # White
|
|
||||||
_NC='\033[0m' # No color
|
|
||||||
|
|
||||||
_RED='\033[0;31m' # Red
|
for _bash_module in "$_bash_config_dir"/bashrc.d/*.bash; do
|
||||||
_GREEN='\033[01;32m' # Bright Green
|
[[ -r "$_bash_module" ]] && . "$_bash_module"
|
||||||
_YELLOW='\033[0;33m' # Yellow
|
done
|
||||||
_BLUE='\033[1;34m' # Bright Blue
|
|
||||||
_BRIGHT_GREEN='\033[1;32m' # Bright Green (for positive)
|
|
||||||
_BRIGHT_RED='\033[1;31m' # Bright Red (for negative)
|
|
||||||
_BRIGHT_WHITE='\033[1;37m' # Bright White
|
|
||||||
_DIM_RED='\033[91m' # Bright Red (for TODO files)
|
|
||||||
|
|
||||||
export SHELL_CONFIG="${SHELL_CONFIG:+${SHELL_CONFIG}:}.bashrc"
|
unset _bash_module _bash_config_dir
|
||||||
#
|
|
||||||
# ~/.bashrc
|
|
||||||
#
|
|
||||||
|
|
||||||
function show_date() {
|
|
||||||
local dotfile selected_adjective adjective classification
|
|
||||||
local day_of_week day_of_month month_name year day_suffix text_color full_date
|
|
||||||
local -a adjectives
|
|
||||||
|
|
||||||
# Define the dot file to store the selected adjective
|
|
||||||
dotfile="$HOME/.adjective_of_the_day"
|
|
||||||
|
|
||||||
# Check if the dot file exists and was modified since yesterday
|
|
||||||
if [[ -f "$dotfile" && $(date -d "$(stat -c %y "$dotfile")" +%s) -ge $(date -d 'yesterday' +%s) ]]; then
|
|
||||||
# If the dot file exists and was modified since yesterday
|
|
||||||
# read the stored adjective from the file
|
|
||||||
selected_adjective=$(cat "$dotfile")
|
|
||||||
else
|
|
||||||
# Define an array of adjectives with classifications
|
|
||||||
adjectives=(
|
|
||||||
"beautiful:positive"
|
|
||||||
"engaging:positive"
|
|
||||||
"majestic:positive"
|
|
||||||
"distinguished:positive"
|
|
||||||
"venerable:positive"
|
|
||||||
"formal:positive"
|
|
||||||
"elegant:positive"
|
|
||||||
"serene:positive"
|
|
||||||
"graceful:positive"
|
|
||||||
"regal:positive"
|
|
||||||
"noble:positive"
|
|
||||||
|
|
||||||
"miserable:negative"
|
|
||||||
"worthless:negative"
|
|
||||||
"depressing:negative"
|
|
||||||
"soulless:negative"
|
|
||||||
"desolate:negative"
|
|
||||||
"archaic:negative"
|
|
||||||
"grim:negative"
|
|
||||||
"dreadful:negative"
|
|
||||||
"forlorn:negative"
|
|
||||||
"wretched:negative"
|
|
||||||
|
|
||||||
"neutral:neutral"
|
|
||||||
"ordinary:neutral"
|
|
||||||
"common:neutral"
|
|
||||||
"antique:neutral"
|
|
||||||
"ceremonial:neutral"
|
|
||||||
"timeless:neutral"
|
|
||||||
"classic:neutral"
|
|
||||||
"historic:neutral"
|
|
||||||
"ancient:neutral"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Select a random adjective from the array
|
|
||||||
selected_adjective="${adjectives[$RANDOM % ${#adjectives[@]}]}"
|
|
||||||
|
|
||||||
# Store the selected adjective in the dot file
|
|
||||||
echo "$selected_adjective" > "$dotfile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Split the selected adjective into the adjective and classification parts
|
|
||||||
IFS=':' read -r adjective classification <<< "$selected_adjective"
|
|
||||||
|
|
||||||
# Get the current day of the week, day of the month, and year
|
|
||||||
day_of_week=$(date "+%A")
|
|
||||||
day_of_month=$(date "+%d")
|
|
||||||
month_name=$(date "+%B")
|
|
||||||
year=$(date "+%Y")
|
|
||||||
|
|
||||||
# Determine the day suffix (th, nd, rd)
|
|
||||||
case "$day_of_month" in
|
|
||||||
1[0-9]) day_suffix="th";;
|
|
||||||
*1) day_suffix="st";;
|
|
||||||
*2) day_suffix="nd";;
|
|
||||||
*3) day_suffix="rd";;
|
|
||||||
*) day_suffix="th";;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Determine the color based on the classification
|
|
||||||
case "$classification" in
|
|
||||||
"positive") text_color="$_BRIGHT_GREEN";;
|
|
||||||
"negative") text_color="$_BRIGHT_RED";;
|
|
||||||
*) text_color="";;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Create the full date format with colored parts and the selected adjective
|
|
||||||
full_date="Pray, be informed, on this ${text_color}${adjective}${_NC} day,\n${_BLUE}${day_of_week}${_NC} the ${_BLUE}${day_of_month}${day_suffix}${_NC} day of ${_BLUE}${month_name}${_NC}, in the year of our Lord ${_BLUE}${year}${_NC}!"
|
|
||||||
|
|
||||||
# Print the full date
|
|
||||||
echo -e "$full_date"
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# SHELL CONFIGURATION
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
export HISTCONTROL=ignoreboth:erasedups
|
|
||||||
export HISTFILE="$HOME/.histfile"
|
|
||||||
export HISTSIZE=10000
|
|
||||||
export HISTFILESIZE=10000
|
|
||||||
shopt -s histappend checkwinsize
|
|
||||||
|
|
||||||
# Disable terminal flow-control keys only when stdin is a terminal.
|
|
||||||
[[ -t 0 ]] && stty -ixon
|
|
||||||
|
|
||||||
# Optimized divider function - simple timestamp without coloring
|
|
||||||
function draw_prompt_divider() {
|
|
||||||
local timestamp prefix_length line_length i
|
|
||||||
printf -v timestamp '%(%H:%M:%S)T' -1 # Faster than $(date)
|
|
||||||
local prefix="$timestamp ├"
|
|
||||||
prefix_length=${#prefix}
|
|
||||||
line_length=$(( ${COLUMNS:-80} - prefix_length ))
|
|
||||||
|
|
||||||
# Print timestamp, junction, then fill with box-drawing characters
|
|
||||||
printf '%s' "$prefix"
|
|
||||||
for ((i=0; i<line_length; i++)); do printf '─'; done
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
# Cache static values that don't change during session
|
|
||||||
_CACHED_USER_HOST="$USER@$HOSTNAME"
|
|
||||||
_CACHED_USER_HOST_LENGTH=${#_CACHED_USER_HOST}
|
|
||||||
|
|
||||||
# Optimized git alignment calculation
|
|
||||||
function calculate_git_alignment() {
|
|
||||||
# Only calculate if git status exists
|
|
||||||
[[ -z "$GITSTATUS_PROMPT" ]] && { GIT_ALIGNMENT_PADDING=""; return; }
|
|
||||||
|
|
||||||
# Fast branch name extraction - use sed for reliable escape sequence removal
|
|
||||||
local cleaned
|
|
||||||
cleaned=$(echo "$GITSTATUS_PROMPT" | sed -e 's/\x01//g' -e 's/\x02//g' -e 's/\x1b\[[0-9;]*m//g')
|
|
||||||
local branch_name="${cleaned%% *}" # Get first word (branch)
|
|
||||||
|
|
||||||
# Calculate padding (cache the static hostname length)
|
|
||||||
local needed_padding=$((_CACHED_USER_HOST_LENGTH - ${#branch_name}))
|
|
||||||
[[ $needed_padding -lt 8 ]] && needed_padding=8
|
|
||||||
|
|
||||||
# Use printf once to generate padding
|
|
||||||
printf -v GIT_ALIGNMENT_PADDING '%*s' $needed_padding ''
|
|
||||||
}
|
|
||||||
|
|
||||||
# Persist each command promptly so a crashed terminal loses as little history
|
|
||||||
# as possible. Bash preserves the user's command status while running
|
|
||||||
# PROMPT_COMMAND, so this does not alter the prompt's error indicator or `$?`.
|
|
||||||
function append_new_history() {
|
|
||||||
history -a
|
|
||||||
}
|
|
||||||
|
|
||||||
# Load custom gitstatus configuration
|
|
||||||
[ -f "$HOME/.config/bash/gitstatus-custom.sh" ] && . "$HOME/.config/bash/gitstatus-custom.sh"
|
|
||||||
|
|
||||||
# Set up prompt command to save history, draw the divider, update git status,
|
|
||||||
# and calculate alignment.
|
|
||||||
PROMPT_COMMAND="append_new_history; draw_prompt_divider; my_gitstatus_prompt_update; calculate_git_alignment"
|
|
||||||
|
|
||||||
# Custom command_not_found_handle function to show errors in red
|
|
||||||
command_not_found_handle() {
|
|
||||||
echo -e "\033[01;31mbash: $1: command not found\033[00m" >&2
|
|
||||||
return 127
|
|
||||||
}
|
|
||||||
_error_block='██████'
|
|
||||||
# Set PS1 with user@host, directory, git status, and prompt ($ color works!)
|
|
||||||
PS1='\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[1;34m\]\w\[\033[00m\]\n${GITSTATUS_PROMPT:+$GIT_ALIGNMENT_PADDING$GITSTATUS_PROMPT\n}$([ "$?" -eq 0 ] && echo "" || echo "\[\033[01;31m\]$_error_block\[\033[00m\] ")\$ \[\e]0;\u@\h: \w\a\]'
|
|
||||||
|
|
||||||
# If there are multiple matches for completion, Tab should cycle through them
|
|
||||||
bind TAB:menu-complete
|
|
||||||
# Display a list of the matching files
|
|
||||||
bind "set show-all-if-ambiguous on"
|
|
||||||
# Perform partial (common) completion on the first Tab press, only start
|
|
||||||
# cycling full results on the second Tab press (from bash version 5)
|
|
||||||
bind "set menu-complete-display-prefix on"
|
|
||||||
|
|
||||||
show_date
|
|
||||||
|
|
||||||
[ -r "$HOME/.config/profile/aliases.sh" ] && . "$HOME/.config/profile/aliases.sh"
|
|
||||||
|
|
||||||
export NVM_DIR="$HOME/.nvm"
|
|
||||||
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
|
|
||||||
\. "$NVM_DIR/nvm.sh"
|
|
||||||
nvm use default >/dev/null
|
|
||||||
[[ -s "$NVM_DIR/bash_completion" ]] && \. "$NVM_DIR/bash_completion"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# https://github.com/skywind3000/z.lua
|
|
||||||
if command -v lua ; then
|
|
||||||
eval "$(lua "$HOME/.z.lua/z.lua" --init bash enhanced once echo)"
|
|
||||||
fi > /dev/null
|
|
||||||
|
|
||||||
_mem_available=$(awk '/MemAvailable/ { printf "%.1f \n", $2/1024/1024 }' /proc/meminfo)
|
|
||||||
_package_status_cache="${XDG_CACHE_HOME:-$HOME/.cache}/package-status/status"
|
|
||||||
_package_status_attempt="${XDG_CACHE_HOME:-$HOME/.cache}/package-status/last-attempt"
|
|
||||||
_package_status_max_age=3600
|
|
||||||
_package_status_retry_delay=300
|
|
||||||
_package_status_version=""
|
|
||||||
_package_status_checked_at=""
|
|
||||||
_package_status_pacman_log_signature=""
|
|
||||||
_updates_available="0"
|
|
||||||
_orphans_available="0"
|
|
||||||
|
|
||||||
if [ -r "$_package_status_cache" ]; then
|
|
||||||
while IFS='=' read -r _package_status_key _package_status_value; do
|
|
||||||
case "$_package_status_key" in
|
|
||||||
version) _package_status_version="$_package_status_value" ;;
|
|
||||||
updates) _updates_available="$_package_status_value" ;;
|
|
||||||
orphans) _orphans_available="$_package_status_value" ;;
|
|
||||||
checked_at) _package_status_checked_at="$_package_status_value" ;;
|
|
||||||
pacman_log_signature) _package_status_pacman_log_signature="$_package_status_value" ;;
|
|
||||||
esac
|
|
||||||
done < "$_package_status_cache"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_package_status_now=$(date +%s)
|
|
||||||
_package_status_current_pacman_log_signature=$(stat -c '%Y:%s:%i' /var/log/pacman.log 2>/dev/null || echo '0:0:0')
|
|
||||||
|
|
||||||
if ! [[ "$_package_status_version" == "1" \
|
|
||||||
&& "$_updates_available" =~ ^[0-9]+$ \
|
|
||||||
&& "$_orphans_available" =~ ^[0-9]+$ \
|
|
||||||
&& "$_package_status_checked_at" =~ ^[0-9]+$ \
|
|
||||||
&& "$_package_status_pacman_log_signature" =~ ^[0-9]+:[0-9]+:[0-9]+$ \
|
|
||||||
&& $_package_status_now -ge $_package_status_checked_at \
|
|
||||||
&& $((_package_status_now - _package_status_checked_at)) -le $_package_status_max_age \
|
|
||||||
&& "$_package_status_pacman_log_signature" == "$_package_status_current_pacman_log_signature" ]]; then
|
|
||||||
_updates_available="0"
|
|
||||||
_orphans_available="0"
|
|
||||||
|
|
||||||
_package_status_attempt_time=$(stat -c %Y "$_package_status_attempt" 2>/dev/null || echo 0)
|
|
||||||
if ! [[ "$_package_status_attempt_time" =~ ^[0-9]+$ \
|
|
||||||
&& $_package_status_now -ge $_package_status_attempt_time \
|
|
||||||
&& $((_package_status_now - _package_status_attempt_time)) -lt $_package_status_retry_delay ]]; then
|
|
||||||
systemctl --user start --no-block package-status-refresh.service >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
unset _package_status_cache _package_status_attempt _package_status_max_age
|
|
||||||
unset _package_status_retry_delay _package_status_attempt_time _package_status_version
|
|
||||||
unset _package_status_checked_at _package_status_pacman_log_signature
|
|
||||||
unset _package_status_now _package_status_current_pacman_log_signature
|
|
||||||
unset _package_status_key _package_status_value
|
|
||||||
|
|
||||||
echo "Remember commands:"
|
|
||||||
printf '%b' "$_WHITE"
|
|
||||||
_command_reminder
|
|
||||||
printf '%b\n' "$_NC"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [ ${_mem_available%.*} -lt 5 ] ; then
|
|
||||||
echo -ne "Memory available: ${_YELLOW}"
|
|
||||||
[ ${_mem_available%.*} -lt 3 ] && echo -ne "${_RED}"
|
|
||||||
echo -n "${_mem_available}"
|
|
||||||
echo -e "GB${_NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $_updates_available -gt 0 ] ; then
|
|
||||||
update_color="$_BRIGHT_WHITE" # default white
|
|
||||||
if [ $_updates_available -gt 29 ] ; then
|
|
||||||
update_color="$_RED" # red
|
|
||||||
elif [ $_updates_available -gt 15 ] ; then
|
|
||||||
update_color="$_YELLOW" # yellow
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -ne "Updates available: ${update_color}${_updates_available}${_NC}"
|
|
||||||
echo -ne " [ update with: ${update_color}update${_NC} ]"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $_orphans_available -gt 0 ] ; then
|
|
||||||
echo -ne "Orphaned packages: $_BRIGHT_WHITE"
|
|
||||||
|
|
||||||
orphan_color="$_BRIGHT_WHITE"
|
|
||||||
if [ $_orphans_available -gt 9 ] ; then
|
|
||||||
orphan_color="$_RED"
|
|
||||||
elif [ $_orphans_available -gt 4 ] ; then
|
|
||||||
orphan_color="$_YELLOW"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -ne "${orphan_color}${_orphans_available}${_NC}"
|
|
||||||
echo -ne " [ remove with: ${orphan_color}sudo pacman -Rns \$(pacman -Qdtq)${_NC} ]"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "Remember \"${_BLUE}TODO.md${_NC}\" (${_BLUE}et${_NC}) and \"${_BLUE}autonote.md${_NC}\" (${_BLUE}ea${_NC}) files have content automatically displayed."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
[ -r "$HOME/.config/bash/cheat.bash" ] && . "$HOME/.config/bash/cheat.bash"
|
|
||||||
|
|
||||||
#openai codex completion
|
|
||||||
if command -v codex >/dev/null 2>&1; then
|
|
||||||
eval "$(codex completion bash)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Function to check for TODO.md and echo its contents
|
|
||||||
function check_todo() {
|
|
||||||
if [ -f "TODO.md" ]; then
|
|
||||||
echo
|
|
||||||
echo -e "${_DIM_RED}TODO.md${_NC}"
|
|
||||||
echo "---------------------------"
|
|
||||||
if command -v mdcat >/dev/null 2>&1; then mdcat TODO.md; else cat TODO.md; fi
|
|
||||||
echo "---------------------------"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
# Function to check for .autonote.md and echo its contents
|
|
||||||
function check_autonote() {
|
|
||||||
if [ -f ".autonote.md" ]; then
|
|
||||||
echo
|
|
||||||
echo -e "${_DIM_RED}autonote.md${_NC}"
|
|
||||||
echo "---------------------------"
|
|
||||||
if command -v mdcat >/dev/null 2>&1; then mdcat .autonote.md; else cat .autonote.md; fi
|
|
||||||
echo "---------------------------"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
# Hook to execute check_todo, check_autonote when changing directories
|
|
||||||
cd() {
|
|
||||||
builtin cd "$@" || return
|
|
||||||
check_todo
|
|
||||||
check_autonote
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# opencode
|
|
||||||
case ":$PATH:" in
|
|
||||||
*":$HOME/.opencode/bin:"*) ;;
|
|
||||||
*) export PATH="$HOME/.opencode/bin:$PATH" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
#pyenv
|
|
||||||
export PYENV_ROOT="$HOME/.pyenv"
|
|
||||||
case ":$PATH:" in
|
|
||||||
*":$PYENV_ROOT/bin:"*) ;;
|
|
||||||
*) export PATH="$PYENV_ROOT/bin:$PATH" ;;
|
|
||||||
esac
|
|
||||||
if [[ -z ${PYENV_SHELL:-} ]] && command -v pyenv >/dev/null 2>&1; then
|
|
||||||
eval "$(pyenv init -)"
|
|
||||||
fi
|
|
||||||
|
|
|
||||||
29
bashrc.d/00-core.bash
Normal file
29
bashrc.d/00-core.bash
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
# Shared colors used by later Bash modules.
|
||||||
|
_WHITE='\033[1;37m'
|
||||||
|
_NC='\033[0m'
|
||||||
|
_RED='\033[0;31m'
|
||||||
|
_YELLOW='\033[0;33m'
|
||||||
|
_BLUE='\033[1;34m'
|
||||||
|
_BRIGHT_GREEN='\033[1;32m'
|
||||||
|
_BRIGHT_RED='\033[1;31m'
|
||||||
|
_BRIGHT_WHITE='\033[1;37m'
|
||||||
|
_DIM_RED='\033[91m'
|
||||||
|
|
||||||
|
export SHELL_CONFIG="${SHELL_CONFIG:+${SHELL_CONFIG}:}.bashrc"
|
||||||
|
|
||||||
|
export HISTCONTROL=ignoreboth:erasedups
|
||||||
|
export HISTFILE="$HOME/.histfile"
|
||||||
|
export HISTSIZE=10000
|
||||||
|
export HISTFILESIZE=10000
|
||||||
|
shopt -s histappend checkwinsize
|
||||||
|
|
||||||
|
# Disable terminal flow-control keys only when stdin is a terminal.
|
||||||
|
[[ -t 0 ]] && stty -ixon
|
||||||
|
|
||||||
|
# If there are multiple completion matches, cycle through them while still
|
||||||
|
# displaying the shared prefix and full candidate list.
|
||||||
|
bind TAB:menu-complete
|
||||||
|
bind "set show-all-if-ambiguous on"
|
||||||
|
bind "set menu-complete-display-prefix on"
|
||||||
43
bashrc.d/10-prompt.bash
Normal file
43
bashrc.d/10-prompt.bash
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
draw_prompt_divider() {
|
||||||
|
local timestamp prefix prefix_length line_length i
|
||||||
|
printf -v timestamp '%(%H:%M:%S)T' -1
|
||||||
|
prefix="$timestamp ├"
|
||||||
|
prefix_length=${#prefix}
|
||||||
|
line_length=$(( ${COLUMNS:-80} - prefix_length ))
|
||||||
|
|
||||||
|
printf '%s' "$prefix"
|
||||||
|
for ((i = 0; i < line_length; i++)); do printf '─'; done
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
_CACHED_USER_HOST="$USER@$HOSTNAME"
|
||||||
|
_CACHED_USER_HOST_LENGTH=${#_CACHED_USER_HOST}
|
||||||
|
|
||||||
|
calculate_git_alignment() {
|
||||||
|
[[ -z "$GITSTATUS_PROMPT" ]] && { GIT_ALIGNMENT_PADDING=""; return; }
|
||||||
|
|
||||||
|
local cleaned branch_name needed_padding
|
||||||
|
cleaned=$(echo "$GITSTATUS_PROMPT" | sed -e 's/\x01//g' -e 's/\x02//g' -e 's/\x1b\[[0-9;]*m//g')
|
||||||
|
branch_name="${cleaned%% *}"
|
||||||
|
needed_padding=$((_CACHED_USER_HOST_LENGTH - ${#branch_name}))
|
||||||
|
[[ $needed_padding -lt 8 ]] && needed_padding=8
|
||||||
|
printf -v GIT_ALIGNMENT_PADDING '%*s' "$needed_padding" ''
|
||||||
|
}
|
||||||
|
|
||||||
|
append_new_history() {
|
||||||
|
history -a
|
||||||
|
}
|
||||||
|
|
||||||
|
[ -r "$HOME/.config/bash/gitstatus-custom.sh" ] && . "$HOME/.config/bash/gitstatus-custom.sh"
|
||||||
|
|
||||||
|
PROMPT_COMMAND="append_new_history; draw_prompt_divider; my_gitstatus_prompt_update; calculate_git_alignment"
|
||||||
|
|
||||||
|
command_not_found_handle() {
|
||||||
|
printf '\033[01;31mbash: %s: command not found\033[00m\n' "$1" >&2
|
||||||
|
return 127
|
||||||
|
}
|
||||||
|
|
||||||
|
_error_block='██████'
|
||||||
|
PS1='\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[1;34m\]\w\[\033[00m\]\n${GITSTATUS_PROMPT:+$GIT_ALIGNMENT_PADDING$GITSTATUS_PROMPT\n}$([ "$?" -eq 0 ] && echo "" || echo "\[\033[01;31m\]$_error_block\[\033[00m\] ")\$ \[\e]0;\u@\h: \w\a\]'
|
||||||
75
bashrc.d/20-greeting.bash
Normal file
75
bashrc.d/20-greeting.bash
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
show_date() {
|
||||||
|
local dotfile selected_adjective adjective classification
|
||||||
|
local today day_of_week day_of_month month_name year day_suffix text_color full_date
|
||||||
|
local -a adjectives
|
||||||
|
|
||||||
|
dotfile="$HOME/.adjective_of_the_day"
|
||||||
|
today=$(date +%F)
|
||||||
|
|
||||||
|
if [[ -f "$dotfile" && $(date -r "$dotfile" +%F) == "$today" ]]; then
|
||||||
|
selected_adjective=$(cat "$dotfile")
|
||||||
|
else
|
||||||
|
adjectives=(
|
||||||
|
"beautiful:positive"
|
||||||
|
"engaging:positive"
|
||||||
|
"majestic:positive"
|
||||||
|
"distinguished:positive"
|
||||||
|
"venerable:positive"
|
||||||
|
"formal:positive"
|
||||||
|
"elegant:positive"
|
||||||
|
"serene:positive"
|
||||||
|
"graceful:positive"
|
||||||
|
"regal:positive"
|
||||||
|
"noble:positive"
|
||||||
|
"miserable:negative"
|
||||||
|
"worthless:negative"
|
||||||
|
"depressing:negative"
|
||||||
|
"soulless:negative"
|
||||||
|
"desolate:negative"
|
||||||
|
"archaic:negative"
|
||||||
|
"grim:negative"
|
||||||
|
"dreadful:negative"
|
||||||
|
"forlorn:negative"
|
||||||
|
"wretched:negative"
|
||||||
|
"neutral:neutral"
|
||||||
|
"ordinary:neutral"
|
||||||
|
"common:neutral"
|
||||||
|
"antique:neutral"
|
||||||
|
"ceremonial:neutral"
|
||||||
|
"timeless:neutral"
|
||||||
|
"classic:neutral"
|
||||||
|
"historic:neutral"
|
||||||
|
"ancient:neutral"
|
||||||
|
)
|
||||||
|
|
||||||
|
selected_adjective="${adjectives[$RANDOM % ${#adjectives[@]}]}"
|
||||||
|
printf '%s\n' "$selected_adjective" > "$dotfile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS=':' read -r adjective classification <<< "$selected_adjective"
|
||||||
|
day_of_week=$(date '+%A')
|
||||||
|
day_of_month=$(date '+%d')
|
||||||
|
month_name=$(date '+%B')
|
||||||
|
year=$(date '+%Y')
|
||||||
|
|
||||||
|
case "$day_of_month" in
|
||||||
|
1[0-9]) day_suffix="th" ;;
|
||||||
|
*1) day_suffix="st" ;;
|
||||||
|
*2) day_suffix="nd" ;;
|
||||||
|
*3) day_suffix="rd" ;;
|
||||||
|
*) day_suffix="th" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$classification" in
|
||||||
|
positive) text_color="$_BRIGHT_GREEN" ;;
|
||||||
|
negative) text_color="$_BRIGHT_RED" ;;
|
||||||
|
*) text_color="" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
full_date="Pray, be informed, on this ${text_color}${adjective}${_NC} day,\n${_BLUE}${day_of_week}${_NC} the ${_BLUE}${day_of_month}${day_suffix}${_NC} day of ${_BLUE}${month_name}${_NC}, in the year of our Lord ${_BLUE}${year}${_NC}!"
|
||||||
|
printf '%b\n\n' "$full_date"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_date
|
||||||
16
bashrc.d/30-integrations.bash
Normal file
16
bashrc.d/30-integrations.bash
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
export NVM_DIR="$HOME/.nvm"
|
||||||
|
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
|
||||||
|
\. "$NVM_DIR/nvm.sh"
|
||||||
|
nvm use default >/dev/null
|
||||||
|
[[ -s "$NVM_DIR/bash_completion" ]] && \. "$NVM_DIR/bash_completion"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# https://github.com/skywind3000/z.lua
|
||||||
|
if command -v lua >/dev/null 2>&1; then
|
||||||
|
eval "$(lua "$HOME/.z.lua/z.lua" --init bash enhanced once echo)"
|
||||||
|
fi >/dev/null
|
||||||
90
bashrc.d/40-status.bash
Normal file
90
bashrc.d/40-status.bash
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
_mem_available=$(awk '/MemAvailable/ { printf "%.1f \n", $2/1024/1024 }' /proc/meminfo)
|
||||||
|
_package_status_cache="${XDG_CACHE_HOME:-$HOME/.cache}/package-status/status"
|
||||||
|
_package_status_attempt="${XDG_CACHE_HOME:-$HOME/.cache}/package-status/last-attempt"
|
||||||
|
_package_status_max_age=3600
|
||||||
|
_package_status_retry_delay=300
|
||||||
|
_package_status_version=""
|
||||||
|
_package_status_checked_at=""
|
||||||
|
_package_status_pacman_log_signature=""
|
||||||
|
_updates_available="0"
|
||||||
|
_orphans_available="0"
|
||||||
|
|
||||||
|
if [[ -r "$_package_status_cache" ]]; then
|
||||||
|
while IFS='=' read -r _package_status_key _package_status_value; do
|
||||||
|
case "$_package_status_key" in
|
||||||
|
version) _package_status_version="$_package_status_value" ;;
|
||||||
|
updates) _updates_available="$_package_status_value" ;;
|
||||||
|
orphans) _orphans_available="$_package_status_value" ;;
|
||||||
|
checked_at) _package_status_checked_at="$_package_status_value" ;;
|
||||||
|
pacman_log_signature) _package_status_pacman_log_signature="$_package_status_value" ;;
|
||||||
|
esac
|
||||||
|
done < "$_package_status_cache"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_package_status_now=$(date +%s)
|
||||||
|
_package_status_current_pacman_log_signature=$(stat -c '%Y:%s:%i' /var/log/pacman.log 2>/dev/null || echo '0:0:0')
|
||||||
|
|
||||||
|
if ! [[ "$_package_status_version" == "1" \
|
||||||
|
&& "$_updates_available" =~ ^[0-9]+$ \
|
||||||
|
&& "$_orphans_available" =~ ^[0-9]+$ \
|
||||||
|
&& "$_package_status_checked_at" =~ ^[0-9]+$ \
|
||||||
|
&& "$_package_status_pacman_log_signature" =~ ^[0-9]+:[0-9]+:[0-9]+$ \
|
||||||
|
&& $_package_status_now -ge $_package_status_checked_at \
|
||||||
|
&& $((_package_status_now - _package_status_checked_at)) -le $_package_status_max_age \
|
||||||
|
&& "$_package_status_pacman_log_signature" == "$_package_status_current_pacman_log_signature" ]]; then
|
||||||
|
_updates_available="0"
|
||||||
|
_orphans_available="0"
|
||||||
|
|
||||||
|
_package_status_attempt_time=$(stat -c %Y "$_package_status_attempt" 2>/dev/null || echo 0)
|
||||||
|
if ! [[ "$_package_status_attempt_time" =~ ^[0-9]+$ \
|
||||||
|
&& $_package_status_now -ge $_package_status_attempt_time \
|
||||||
|
&& $((_package_status_now - _package_status_attempt_time)) -lt $_package_status_retry_delay ]]; then
|
||||||
|
systemctl --user start --no-block package-status-refresh.service >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if declare -F _command_reminder >/dev/null 2>&1; then
|
||||||
|
printf '%s\n' 'Remember commands:'
|
||||||
|
printf '%b' "$_WHITE"
|
||||||
|
_command_reminder
|
||||||
|
printf '%b\n\n' "$_NC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${_mem_available%.*} -lt 5 ]]; then
|
||||||
|
printf 'Memory available: %b' "$_YELLOW"
|
||||||
|
[[ ${_mem_available%.*} -lt 3 ]] && printf '%b' "$_RED"
|
||||||
|
printf '%sGB%b\n' "$_mem_available" "$_NC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $_updates_available -gt 0 ]]; then
|
||||||
|
update_color="$_BRIGHT_WHITE"
|
||||||
|
if [[ $_updates_available -gt 29 ]]; then
|
||||||
|
update_color="$_RED"
|
||||||
|
elif [[ $_updates_available -gt 15 ]]; then
|
||||||
|
update_color="$_YELLOW"
|
||||||
|
fi
|
||||||
|
printf 'Updates available: %b%s%b [ update with: %bupdate%b ]\n' \
|
||||||
|
"$update_color" "$_updates_available" "$_NC" "$update_color" "$_NC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $_orphans_available -gt 0 ]]; then
|
||||||
|
orphan_color="$_BRIGHT_WHITE"
|
||||||
|
if [[ $_orphans_available -gt 9 ]]; then
|
||||||
|
orphan_color="$_RED"
|
||||||
|
elif [[ $_orphans_available -gt 4 ]]; then
|
||||||
|
orphan_color="$_YELLOW"
|
||||||
|
fi
|
||||||
|
printf 'Orphaned packages: %b%s%b [ remove with: %bsudo pacman -Rns $(pacman -Qdtq)%b ]\n' \
|
||||||
|
"$orphan_color" "$_orphans_available" "$_NC" "$orphan_color" "$_NC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '\nRemember "%bTODO.md%b" (%bet%b) and "%bautonote.md%b" (%bea%b) files have content automatically displayed.\n\n' \
|
||||||
|
"$_BLUE" "$_NC" "$_BLUE" "$_NC" "$_BLUE" "$_NC" "$_BLUE" "$_NC"
|
||||||
|
|
||||||
|
unset _mem_available _updates_available _orphans_available update_color orphan_color
|
||||||
|
unset _package_status_cache _package_status_attempt _package_status_max_age
|
||||||
|
unset _package_status_retry_delay _package_status_attempt_time _package_status_version
|
||||||
|
unset _package_status_checked_at _package_status_pacman_log_signature _package_status_now
|
||||||
|
unset _package_status_current_pacman_log_signature _package_status_key _package_status_value
|
||||||
7
bashrc.d/50-completions.bash
Normal file
7
bashrc.d/50-completions.bash
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
[ -r "$HOME/.config/bash/cheat.bash" ] && . "$HOME/.config/bash/cheat.bash"
|
||||||
|
|
||||||
|
if command -v codex >/dev/null 2>&1; then
|
||||||
|
eval "$(codex completion bash)"
|
||||||
|
fi
|
||||||
28
bashrc.d/60-directory-notes.bash
Normal file
28
bashrc.d/60-directory-notes.bash
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
check_todo() {
|
||||||
|
if [[ -f TODO.md ]]; then
|
||||||
|
echo
|
||||||
|
printf '%bTODO.md%b\n' "$_DIM_RED" "$_NC"
|
||||||
|
printf '%s\n' '---------------------------'
|
||||||
|
if command -v mdcat >/dev/null 2>&1; then mdcat TODO.md; else cat TODO.md; fi
|
||||||
|
printf '%s\n\n' '---------------------------'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_autonote() {
|
||||||
|
if [[ -f .autonote.md ]]; then
|
||||||
|
echo
|
||||||
|
printf '%bautonote.md%b\n' "$_DIM_RED" "$_NC"
|
||||||
|
printf '%s\n' '---------------------------'
|
||||||
|
if command -v mdcat >/dev/null 2>&1; then mdcat .autonote.md; else cat .autonote.md; fi
|
||||||
|
printf '%s\n\n' '---------------------------'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cd() {
|
||||||
|
builtin cd "$@" || return
|
||||||
|
check_todo
|
||||||
|
check_autonote
|
||||||
|
return 0
|
||||||
|
}
|
||||||
16
bashrc.d/70-development.bash
Normal file
16
bashrc.d/70-development.bash
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
case ":$PATH:" in
|
||||||
|
*":$HOME/.opencode/bin:"*) ;;
|
||||||
|
*) export PATH="$HOME/.opencode/bin:$PATH" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
export PYENV_ROOT="$HOME/.pyenv"
|
||||||
|
case ":$PATH:" in
|
||||||
|
*":$PYENV_ROOT/bin:"*) ;;
|
||||||
|
*) export PATH="$PYENV_ROOT/bin:$PATH" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -z ${PYENV_SHELL:-} ]] && command -v pyenv >/dev/null 2>&1; then
|
||||||
|
eval "$(pyenv init -)"
|
||||||
|
fi
|
||||||
Loading…
Add table
Add a link
Reference in a new issue