Skip to content

Instantly share code, notes, and snippets.

@ldotlopez
Last active July 19, 2025 11:46
Show Gist options
  • Select an option

  • Save ldotlopez/bc76bb40e662a2fa026326d0d389d842 to your computer and use it in GitHub Desktop.

Select an option

Save ldotlopez/bc76bb40e662a2fa026326d0d389d842 to your computer and use it in GitHub Desktop.
Bash module to show README's on changing into directory.
#!/bin/bash
if [[ ${BASH_VERSINFO[0]} -lt 4 ]]; then
echo "[on-cd] You are using an ancient bash version" >&2
echo "[on-cd] bash >= 4 is required to use this shlib" >&2
return
fi
#
# User configurable variables
#
ON_CD_PAGER="head -n 10"
ON_CD_DEBUG=""
ON_CD_TTL=$((60 * 60 * 8)) # 8 hours
#
# Don't change variables unless you know what are you doing
#
# In case of not running on "modern-ish" Linux
XDG_CACHE_HOME="${XDG_CACHE_HOME:-"$HOME/.cache"}"
ON_CD_CACHE_DIR="$XDG_CACHE_HOME/on-cd"
ON_CD_TIMESTAMPS_FILE="$ON_CD_CACHE_DIR/timestamps"
declare -A _ON_CD_TIMESTAMPS
function cd() {
# Store the arguments passed to the custom cd function.
local args=("$@")
# Get the current directory before changing.
# local old_pwd="$PWD"
# Execute the built-in 'cd' command with the provided arguments.
# This ensures the actual directory change happens.
debug "Executing builtin cd -- " "${args[@]}"
builtin cd "${args[@]}" || return $? # If 'cd' fails, exit the function.
debug "Running post cd on '$PWD'"
post_cd "$PWD"
}
function post_cd {
local dirpath="${1:-"$PWD"}"
local notefile
local notets
local now
# Check for dirpath note
notepath="$(get_dirnote "$dirpath" || true)"
[[ -f "$notepath" ]] || {
debug "$dirpath: No note found"
return
}
notets=$(get_timestamp_of "$notepath")
debug "$dirpath: Found '$notepath' (ts=$notets)"
# FIXME: Replace `date` call with a build-in solution
now="$(date +%s)"
if [[ $((now - notets)) -le $ON_CD_TTL ]]; then
debug "$notepath: was recently displayed. skipping."
return
fi
debug "$notepath: was not displayed, showing it."
# shellcheck disable=SC1009
$ON_CD_PAGER "$notepath"
set_timestamp_of "$notepath" "$now"
}
function get_dirnote {
local dirpath="${1:-"$PWD"}"
for basename in "README" "TODO" "WARNING" "INFO"; do
for ext in "md" "txt"; do
# Don't use a loop to here avoid inner calls to 'tr' and also
# delegate the real 'print' of the filename to check_filepath
check_filepath "${dirpath}/${basename}.${ext}" && return 0
check_filepath "${dirpath}/${basename}" && return 0
check_filepath "${dirpath}/${basename}.${ext^^}" && return 0
check_filepath "${dirpath}/${basename,,}.${ext}" && return 0
done
done
return 1
}
function check_filepath() {
[[ -f "$1" ]] && {
printf "%s" "$1"
return 0
} || return 1
}
function set_timestamp_of {
local filepath="$1"
local ts="$2"
_ON_CD_TIMESTAMPS[$filepath]="$ts"
dump_timestamps
}
function get_timestamp_of {
local notefile="$1"
local ts
load_timestamps
ts=${_ON_CD_TIMESTAMPS["$notefile"]}
[[ -z "$ts" ]] && ts=0
printf "%s" "$ts"
}
function load_timestamps() {
# Check if the timestamp file exists. If not, create it.
[[ -d "$ON_CD_CACHE_DIR" ]] || mkdir -p "$ON_CD_CACHE_DIR"
[[ -f "$ON_CD_TIMESTAMPS_FILE" ]] || touch "$ON_CD_TIMESTAMPS_FILE"
# Read each line from the timestamp file.
# Each line is expected to be in the format: timestamp:/path/to/directory
while IFS=: read -r timestamp file; do
# Store the directory and its timestamp in the associative array.
_ON_CD_TIMESTAMPS["$file"]="$timestamp"
done <"$ON_CD_TIMESTAMPS_FILE"
# debug "[timestamps]"
# # shellcheck disable=SC2068
# for key in ${!_ON_CD_TIMESTAMPS[@]}; do
# debug "${key}: ${_ON_CD_TIMESTAMPS[${key}]}"
# done
# debug "[/timestamps]"
}
# Function to save the current state of the associative array back to the file.
function dump_timestamps() {
# Clear the file content before writing to ensure only current data is present.
: >"$ON_CD_TIMESTAMPS_FILE"
# Iterate over all key-value pairs in the associative array.
for file in "${!_ON_CD_TIMESTAMPS[@]}"; do
# Write each directory and its timestamp to the file.
builtin printf "%s:%s\n" "${_ON_CD_TIMESTAMPS[$file]}" "$file" >>"$ON_CD_TIMESTAMPS_FILE"
done
}
function debug {
[[ -z "$ON_CD_DEBUG" ]] && return
builtin printf "[debug] %s\n" "${@}" >&2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment