# Completion script for hledger. # Created using a Makefile and real hledger. # No set -e because this file is sourced and is not supposed to quit the current shell. set -o pipefail # Note: grep "^$wordToComplete" is (functional) not safe to use if the word # contains regex special chars. But it might be no problem because of # COMP_WORDBREAKS. # Note: compgen and compopt is pretty complicated. Piping to # grep "^$wordToComplete" # seems like a hack - I'd rather use # compgen ... -- "$wordToComplete" # But what options to use? I don't want to use -W because it may exceed the # maximum command line length. -C "cat file" is not working either. It would be # best if compgen could read from stdin but it does not. # Note: Working with bash arrays is nasty compared to editing a text file. # Consider for example grepping an array or mapping a substitution on it. # Therefore, we create temp files in RAM for completion suggestions (see below). readonly _HLEDGER_COMPLETION_TEMPDIR=$(mktemp -d) _hledger_completion_function() { #declare cmd=$1 declare wordToComplete=$2 declare precedingWord=$3 declare subcommand for subcommand in "${COMP_WORDS[@]}"; do if grep -Fxqe "$subcommand" "$_HLEDGER_COMPLETION_TEMPDIR/commands.txt"; then COMPREPLY+=( $(grep -h "^$wordToComplete" -- "$_HLEDGER_COMPLETION_TEMPDIR/options-$subcommand.txt") ) break fi subcommand= done if [[ -z $subcommand ]]; then declare completeFiles filenameSoFar case $precedingWord in -f|--file|--rules-file) completeFiles=1 filenameSoFar=$wordToComplete ;; =) completeFiles=1 filenameSoFar=$wordToComplete ;; esac if [[ -n $completeFiles ]]; then #COMP_WORDBREAKS='= ' declare -a files # This does not work because assignment to 'files' in the "pipe # subshell" has no effect! #compgen -df | grep "^$filenameSoFar" | readarray -t files compopt -o filenames -o dirnames readarray -t files < <(compgen -f -- "$filenameSoFar") COMPREPLY=( "${files[@]}" ) else COMPREPLY+=( $(grep -h "^$wordToComplete" -- "$_HLEDGER_COMPLETION_TEMPDIR/commands.txt" "$_HLEDGER_COMPLETION_TEMPDIR/generic-options.txt") ) fi else # Almost all subcommands accept [QUERY] # -> always add accounts to completion list # TODO Get ledger file from -f --file arguments from COMP_WORDS and pass it to # the 'hledger accounts' call. Note that --rules-file - if present - must also # be passed! declare -a accounts readarray -t accounts < <({ cat "$_HLEDGER_COMPLETION_TEMPDIR/query-filters.txt"; hledger accounts --flat; } | grep "^$wordToComplete") compopt -o nospace COMPREPLY+=( "${accounts[@]}" ) # Special characters (e.g. '-', ':') are allowed in account names. # Account names with spaces must be still be quoted (e.g. '"Expens') # for completion. Setting COMP_WORDBREAKS='' would not help here! COMP_WORDBREAKS=' ' fi } _hledger_extension_completion_function() { declare cmd=$1 # Change parameters and arguments and call the # normal hledger completion function. declare extensionName=${cmd#*-} export -a COMP_WORDS=( "hledger" "$extensionName" "${COMP_WORDS[@]:1}" ) #echo; echo "debug: ${COMP_WORDS[@]}" shift _hledger_completion_function "hledger" "$@" } # Register completion function for hledger: complete -F _hledger_completion_function hledger # Register completion functions for hledger extensions: complete -F _hledger_extension_completion_function hledger-ui complete -F _hledger_extension_completion_function hledger-web # Include lists of commands and options generated by the Makefile using the # m4 macro processor. # Included files must have exactly one newline at EOF to prevent weired errors. cat < "$_HLEDGER_COMPLETION_TEMPDIR/commands.txt" include(`commands.txt')dnl TEXT cat < "$_HLEDGER_COMPLETION_TEMPDIR/query-filters.txt" include(`query-filters.txt')dnl TEXT cat < "$_HLEDGER_COMPLETION_TEMPDIR/generic-options.txt" include(`generic-options.txt')dnl TEXT include(`foreach2.m4') foreach(`cmd', (include(`commands-list.txt')), ` cat < "$_HLEDGER_COMPLETION_TEMPDIR/options-cmd.txt" include(options-cmd.txt)dnl TEXT ')