feat(completion): add bash completion
Still missing a few options and cannot complete dates inside string delimiters, but mostly works.
This commit is contained in:
6
Makefile
6
Makefile
@@ -7,11 +7,13 @@ PREFIX := /usr/local
|
|||||||
install: ./agenda.1.gz
|
install: ./agenda.1.gz
|
||||||
install -m 755 -D ./agenda $(PREFIX)/bin/agenda
|
install -m 755 -D ./agenda $(PREFIX)/bin/agenda
|
||||||
install -m 644 -D ./agenda.1.gz $(PREFIX)/share/man/man1/agenda.1.gz
|
install -m 644 -D ./agenda.1.gz $(PREFIX)/share/man/man1/agenda.1.gz
|
||||||
|
install -m 644 -D ./completion.bash $(PREFIX)/share/bash-completion/completions/agenda
|
||||||
|
|
||||||
.PHONY: uninstall
|
.PHONY: uninstall
|
||||||
uninstall:
|
uninstall:
|
||||||
rm $(PREFIX)/bin/agenda
|
rm -f $(PREFIX)/bin/agenda
|
||||||
rm $(PREFIX)/share/man/man1/agenda.1.gz
|
rm -f $(PREFIX)/share/man/man1/agenda.1.gz
|
||||||
|
rm -f $(PREFIX)/share/bash-completion/completions/agenda
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
190
completion.bash
Normal file
190
completion.bash
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Bash completion script for the agenda(1) script.
|
||||||
|
|
||||||
|
# TODO: Maybe its easier to add an api to the agenda script to query for the
|
||||||
|
# available -t option values?
|
||||||
|
if [ -z "$AGENDA_DIR" ]; then
|
||||||
|
if type xdg-user-dir >/dev/null 2>&1; then
|
||||||
|
AGENDA_DIR="$(xdg-user-dir DOCUMENTS)/agenda"
|
||||||
|
else
|
||||||
|
AGENDA_DIR="$HOME/.agenda"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AGENDA_COMP_DATE_MOD=("next" "last")
|
||||||
|
AGENDA_COMP_DATE_UNIT=("day" "week" "month" "year")
|
||||||
|
AGENDA_COMP_DATE_DAY=("monday" "tuesday" "wednesday" "thursday" "friday" "saturday" "sunday")
|
||||||
|
AGENDA_COMP_DATE_REL=("yesterday" "today" "tomorrow")
|
||||||
|
|
||||||
|
AGENDA_COMP_DATE=(
|
||||||
|
"${AGENDA_COMP_DATE_MOD[@]}"
|
||||||
|
"${AGENDA_COMP_DATE_UNIT[@]}"
|
||||||
|
"${AGENDA_COMP_DATE_DAY[@]}"
|
||||||
|
"${AGENDA_COMP_DATE_REL[@]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
__agenda_comp() {
|
||||||
|
# Pointer to current and last completion words.
|
||||||
|
local cur last
|
||||||
|
|
||||||
|
cur=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
last=${COMP_WORDS[COMP_CWORD - 1]}
|
||||||
|
|
||||||
|
# All subcommands take a date (or parts of a date) as their final arguments.
|
||||||
|
if __agenda_comp_is_date_word "${COMP_WORDS[-2]}"; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if __agenda_comp_is_date_mod "$last"; then
|
||||||
|
local words=("${AGENDA_COMP_DATE_UNIT[@]}" "${AGENDA_COMP_DATE_DAY[@]}")
|
||||||
|
mapfile -t COMPREPLY < <(compgen -W "${words[*]}" -- "$cur")
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
case ${COMP_WORDS[1]} in
|
||||||
|
"edit")
|
||||||
|
mapfile -t COMPREPLY < <(__agenda_comp_edit "$last" "$cur")
|
||||||
|
;;
|
||||||
|
"list"|"ls")
|
||||||
|
mapfile -t COMPREPLY < <(__agenda_comp_list "$last" "$cur")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if (( COMP_CWORD == 1 )); then
|
||||||
|
local dates
|
||||||
|
mapfile -t dates < <(__agenda_comp_iso_date "$cur")
|
||||||
|
|
||||||
|
local words=(
|
||||||
|
"edit"
|
||||||
|
"list"
|
||||||
|
"${dates[@]}"
|
||||||
|
"${AGENDA_COMP_DATE[@]}"
|
||||||
|
"${AGENDA_COMP_DATE_DAY[@]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
mapfile -t COMPREPLY < <(compgen -W "${words[*]}" -- "${COMP_WORDS[1]}")
|
||||||
|
else
|
||||||
|
# The "edit" subcommand is implicit.
|
||||||
|
mapfile -t COMPREPLY < <(__agenda_comp_edit "$last" "$cur")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
complete -F __agenda_comp agenda
|
||||||
|
|
||||||
|
__agenda_comp_edit() {
|
||||||
|
local last="$1" cur="$2"
|
||||||
|
|
||||||
|
case $last in
|
||||||
|
"-"*"t")
|
||||||
|
compgen -W "$(__agenda_comp_names)" -- "$cur"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
__agenda_comp_opt "c" "$cur"
|
||||||
|
__agenda_comp_opt "E" "$cur"
|
||||||
|
__agenda_comp_opt "t" "$cur"
|
||||||
|
|
||||||
|
compgen -W "${AGENDA_COMP_DATE[*]} $(__agenda_comp_iso_date "$cur")" -- "$cur"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
__agenda_comp_list() {
|
||||||
|
local last="$1" cur="$2"
|
||||||
|
|
||||||
|
case $last in
|
||||||
|
# TODO: Somehow complete date wrapped in a string?
|
||||||
|
"-"*"u")
|
||||||
|
local year
|
||||||
|
year=$(printf '%(%Y)T' -1)
|
||||||
|
compgen -W "$(__agenda_comp_iso_date "$cur" "$year")" -- "$cur"
|
||||||
|
;;
|
||||||
|
"-"*"t")
|
||||||
|
compgen -W "$(__agenda_comp_names)" -- "$cur"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
__agenda_comp_opt "a" "$cur"
|
||||||
|
__agenda_comp_opt "c" "$cur"
|
||||||
|
__agenda_comp_opt "u" "$cur"
|
||||||
|
__agenda_comp_opt "t" "$cur"
|
||||||
|
|
||||||
|
compgen -W "${AGENDA_COMP_DATE[*]} $(__agenda_comp_iso_date "$cur")" -- "$cur"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
__agenda_comp_is_date_mod() {
|
||||||
|
[[ $last == "next" ]] || [[ $last == "last" ]] || [[ $last =~ ^[-+]?[0-9]+$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
__agenda_comp_is_date_word() {
|
||||||
|
local word words=(
|
||||||
|
"${AGENDA_COMP_DATE_DAY[@]}"
|
||||||
|
"${AGENDA_COMP_DATE_UNIT[@]}"
|
||||||
|
"${AGENDA_COMP_DATE_REL[@]}"
|
||||||
|
)
|
||||||
|
for word in "${words[@]}"; do
|
||||||
|
if [[ $1 == "$word" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $1 =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
__agenda_comp_names() {
|
||||||
|
local dir
|
||||||
|
for dir in "$AGENDA_DIR"/*; do
|
||||||
|
if [ -e "$dir" ]; then
|
||||||
|
echo "${dir##*/}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: Complete years only without appending a space on completion (If
|
||||||
|
# possible, idk)?
|
||||||
|
__agenda_comp_iso_date() {
|
||||||
|
local year month day
|
||||||
|
|
||||||
|
if [[ $1 =~ ^[0-9]{4}-? ]]; then
|
||||||
|
year=${1%%-*}
|
||||||
|
elif [[ -n ${2:-} ]]; then
|
||||||
|
year=$2
|
||||||
|
else
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
for month in {1..12}; do
|
||||||
|
case $month in
|
||||||
|
1|3|5|7|8|10|12)
|
||||||
|
for day in {1..31}; do
|
||||||
|
printf "%04d-%02d-%02d\n" "$year" "$month" "$day"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
4|6|9|11)
|
||||||
|
for day in {1..30}; do
|
||||||
|
printf "%04d-%02d-%02d\n" "$year" "$month" "$day"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
# TODO: Leap years.
|
||||||
|
for day in {1..28}; do
|
||||||
|
printf "%04d-%02d-%02d\n" "$year" "$month" "$day"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
__agenda_comp_opt() {
|
||||||
|
local regex="^.*[[:space:]]-.*$1.*.*$"
|
||||||
|
if ! [[ $COMP_LINE =~ $regex ]]; then
|
||||||
|
compgen -W "-$1" -- "$2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# vi: noet sts=4 sw=4 tw=84
|
||||||
Reference in New Issue
Block a user