Add files for bash completion
This commit is contained in:
		
							parent
							
								
									50175a9698
								
							
						
					
					
						commit
						dc73b55b7b
					
				
							
								
								
									
										28
									
								
								shell-completion/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								shell-completion/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | 
 | ||||||
|  | .PHONY: commands clean | ||||||
|  | 
 | ||||||
|  | all: generic-options.txt commands hledger-completion.bash | ||||||
|  | 
 | ||||||
|  | generic-options.txt: | ||||||
|  | 	hledger -h | ./output-options.sh > $@ | ||||||
|  | 
 | ||||||
|  | commands.txt: | ||||||
|  | 	hledger | ./output-commands.sh > $@ | ||||||
|  | 
 | ||||||
|  | commands-list.txt: commands.txt | ||||||
|  | 	paste -sd, $^ | tr -d '\n' > $@ | ||||||
|  | 
 | ||||||
|  | commands: commands.txt | ||||||
|  | 	#parallel 'touch {}.command' < commands.txt | ||||||
|  | 	parallel 'hledger {} -h | ./output-options.sh > options-{}.txt' < commands.txt | ||||||
|  | 
 | ||||||
|  | # It's possible to call this rule explicitly but it's not invoked automatically.
 | ||||||
|  | # Better generate *-options.txt with the 'commands' phony rule.
 | ||||||
|  | %-options.txt: %.command | ||||||
|  | 	hledger $* -h | ./output-options.sh > $@ | ||||||
|  | 
 | ||||||
|  | hledger-completion.bash: hledger-completion.bash.m4 commands-list.txt | ||||||
|  | 	m4 hledger-completion.bash.m4 > $@ | ||||||
|  | 
 | ||||||
|  | clean: | ||||||
|  | 	rm -f *.commands *.txt hledger-completion.bash | ||||||
							
								
								
									
										10
									
								
								shell-completion/foreach2.m4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								shell-completion/foreach2.m4
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | include(`quote.m4')dnl | ||||||
|  | divert(`-1') | ||||||
|  | # foreach(x, (item_1, item_2, ..., item_n), stmt) | ||||||
|  | #   parenthesized list, improved version | ||||||
|  | define(`foreach', `pushdef(`$1')_$0(`$1', | ||||||
|  |   (dquote(dquote_elt$2)), `$3')popdef(`$1')') | ||||||
|  | define(`_arg1', `$1') | ||||||
|  | define(`_foreach', `ifelse(`$2', `(`')', `', | ||||||
|  |   `define(`$1', _arg1$2)$3`'$0(`$1', (dquote(shift$2)), `$3')')') | ||||||
|  | divert`'dnl | ||||||
							
								
								
									
										94
									
								
								shell-completion/hledger-completion.bash.m4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								shell-completion/hledger-completion.bash.m4
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | # 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 | ||||||
|  | 
 | ||||||
|  | # TODO grep "^$wordToComplete" is not safe to use if the word contains regex | ||||||
|  | # special chars. But it might be no problem because of COMP_WORDBREAKS. | ||||||
|  | 
 | ||||||
|  | # TODO Try to get file from -f --file arguments from COMP_WORDS and pass it to | ||||||
|  | # the 'hledger accounts' call. | ||||||
|  | 
 | ||||||
|  | # Working with bash arrays is nasty compared to editing a text file. Consider | ||||||
|  | # for example grepping an array or map a substitution on it. | ||||||
|  | # Therefore, we create temp files in RAM for completion suggestions (see below). | ||||||
|  | 
 | ||||||
|  | declare -g HLEDGER_COMPLETION_TEMPDIR | ||||||
|  | HLEDGER_COMPLETION_TEMPDIR=$(mktemp -d) | ||||||
|  | 
 | ||||||
|  | hledgerCompletionFunction() { | ||||||
|  |     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 | ||||||
|  | 	    #declare -a options | ||||||
|  | 	    #readarray -t options <(grep "^$wordToComplete" "$HLEDGER_COMPLETION_TEMPDIR/options-$subcommand.txt") | ||||||
|  | 	    #COMPREPLY+=( "${options[@]}" ) | ||||||
|  | 	    COMPREPLY+=( $(grep -h "^$wordToComplete" -- "$HLEDGER_COMPLETION_TEMPDIR/options-$subcommand.txt") ) | ||||||
|  | 	    break | ||||||
|  | 	fi | ||||||
|  | 	subcommand= | ||||||
|  |     done | ||||||
|  | 
 | ||||||
|  |     if [[ -z $subcommand ]]; then | ||||||
|  | 
 | ||||||
|  | 	declare completeFiles filenameSoFar | ||||||
|  | 	case $wordToComplete in | ||||||
|  | 	    --file=*|--rules-file=*) | ||||||
|  | 		completeFiles=1 | ||||||
|  | 		filenameSoFar=${wordToComplete#*=} | ||||||
|  | 		;; | ||||||
|  | 	esac | ||||||
|  | 	case $precedingWord in | ||||||
|  | 	    -f|--file|--rules-file) | ||||||
|  | 		completeFiles=1 | ||||||
|  | 		filenameSoFar=$wordToComplete | ||||||
|  | 		;; | ||||||
|  | 	esac | ||||||
|  | 
 | ||||||
|  | 	if [[ -n $completeFiles ]]; then | ||||||
|  | 	    : | ||||||
|  | 	    #COMP_WORDBREAKS='= ' | ||||||
|  | 	    COMPREPLY+=( $(compgen -df | grep "^$filenameSoFar") ) | ||||||
|  | 
 | ||||||
|  | 	else | ||||||
|  | 	    COMPREPLY+=( $(grep -h "^$wordToComplete" -- "$HLEDGER_COMPLETION_TEMPDIR/commands.txt" "$HLEDGER_COMPLETION_TEMPDIR/generic-options.txt") ) | ||||||
|  | 	fi | ||||||
|  | 
 | ||||||
|  |     else | ||||||
|  | 
 | ||||||
|  | 	# Almost all subcommands accpt [QUERY] -> always add accounts to completion list | ||||||
|  | 
 | ||||||
|  | 	COMP_WORDBREAKS=' ' | ||||||
|  | 	COMPREPLY+=( $(hledger accounts --flat | grep "^$wordToComplete") ) | ||||||
|  | 
 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | complete -F hledgerCompletionFunction hledger | ||||||
|  | 
 | ||||||
|  | # Include lists of commands and options generated by the Makefile using m4 | ||||||
|  | # macro processor. | ||||||
|  | # Included files must have exactly one newline at EOF to prevent weired errors. | ||||||
|  | 
 | ||||||
|  | cat <<TEXT > "$HLEDGER_COMPLETION_TEMPDIR/commands.txt" | ||||||
|  | include(`commands.txt')dnl | ||||||
|  | TEXT | ||||||
|  | 
 | ||||||
|  | cat <<TEXT > "$HLEDGER_COMPLETION_TEMPDIR/generic-options.txt" | ||||||
|  | include(`generic-options.txt')dnl | ||||||
|  | TEXT | ||||||
|  | 
 | ||||||
|  | include(`foreach2.m4') | ||||||
|  | 
 | ||||||
|  | foreach(`cmd', (include(`commands-list.txt')), ` | ||||||
|  | cat <<TEXT > "$HLEDGER_COMPLETION_TEMPDIR/options-cmd.txt" | ||||||
|  | include(options-cmd.txt)dnl | ||||||
|  | TEXT | ||||||
|  | ') | ||||||
							
								
								
									
										65
									
								
								shell-completion/hledger-completion.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								shell-completion/hledger-completion.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | # Completion script for hledger. | ||||||
|  | # Created using a Makefile and real hledger. | ||||||
|  | 
 | ||||||
|  | #set -eo pipefail | ||||||
|  | 
 | ||||||
|  | completeFunction() { | ||||||
|  |     declare cmd=$1 | ||||||
|  |     declare wordToComplete=$2 | ||||||
|  |     declare precedingWord=$3 | ||||||
|  | 
 | ||||||
|  |     declare subcommand | ||||||
|  |     for subcommand in "${COMP_WORDS[@]}"; do | ||||||
|  | 	if grep -Fxq "$subcommand" commands.txt; then | ||||||
|  | 	    #declare -a options | ||||||
|  | 	    #readarray -t options <(grep "^$wordToComplete" "$subcommand-options.txt") | ||||||
|  | 	    #COMPREPLY+=( "${options[@]}" ) | ||||||
|  | 	    COMPREPLY+=( $(cat "$subcommand-options.txt" | grep "^$wordToComplete") ) | ||||||
|  | 	    break | ||||||
|  | 	fi | ||||||
|  | 	subcommand= | ||||||
|  |     done | ||||||
|  | 
 | ||||||
|  |     if [[ -z $subcommand ]]; then | ||||||
|  | 
 | ||||||
|  | 	# echo;echo no subcommand | ||||||
|  | 
 | ||||||
|  | 	case $precedingWord in | ||||||
|  | 	    -f|--file|--rules-file) | ||||||
|  | 		# COMPREPLY+=( $(compgen -df | grep "^$wordToComplete") ) | ||||||
|  | 		: | ||||||
|  | 		;; | ||||||
|  | 	    *) | ||||||
|  | 		# echo "completing sub commands and general options" | ||||||
|  | 		COMPREPLY+=( $(cat commands.txt generic-options.txt | grep "^$wordToComplete") ) | ||||||
|  | 		;; | ||||||
|  | 	esac | ||||||
|  | 
 | ||||||
|  |     else | ||||||
|  | 	: | ||||||
|  | 	# echo;echo subcommand is $subcommand | ||||||
|  | 
 | ||||||
|  | 	# if grep -Eqv '\b(register|reg|r)\b' <<< "$COMP_LINE"; then | ||||||
|  | 	#     return | ||||||
|  | 	# fi | ||||||
|  | 	# case $precedingWord in | ||||||
|  | 	    # register|reg|r) : ;; | ||||||
|  | 	    # *) return 1 ;; | ||||||
|  | 	# esac | ||||||
|  | 
 | ||||||
|  | 	declare journalFile | ||||||
|  | 	# TODO try to get file from -f --file first | ||||||
|  | 	if [[ -n $HLEDGER_FILE ]]; then | ||||||
|  | 	    journalFile=$HLEDGER_FILE | ||||||
|  | 	else | ||||||
|  | 	    journalFile=~/.hledger.journal | ||||||
|  | 	fi | ||||||
|  | 	COMP_WORDBREAKS=' ' | ||||||
|  | 	COMPREPLY+=( $(sed -rn 's/^ +([-_:a-zA-Z0-9]+).*/\1/p' "$journalFile" | grep "^$wordToComplete") ) | ||||||
|  | 
 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | complete -F completeFunction hledger | ||||||
							
								
								
									
										21
									
								
								shell-completion/output-commands.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								shell-completion/output-commands.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | # Output subcommands from man/usage text | ||||||
|  | 
 | ||||||
|  | set -o errexit -o pipefail -o nounset | ||||||
|  | 
 | ||||||
|  | printCommands() { | ||||||
|  |     declare tmp=$1 | ||||||
|  |     sed -rn 's/^ ([-a-z]+).*/\1/gp' "$tmp" | ||||||
|  |     sed -rn 's/^ .*\(([a-z]+)\).*/\1/gp' "$tmp" | ||||||
|  |     # TODO missing: (reg, r)  (multiple aliases) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main() { | ||||||
|  |     declare tmp | ||||||
|  |     tmp=$(mktemp) | ||||||
|  |     cat > "$tmp" | ||||||
|  | 
 | ||||||
|  |     printCommands "$tmp" | grep -v ^hledger | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main "$@" | ||||||
							
								
								
									
										17
									
								
								shell-completion/output-options.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								shell-completion/output-options.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | # Output short and long options from man/usage text | ||||||
|  | 
 | ||||||
|  | set -o errexit -o pipefail -o nounset | ||||||
|  | 
 | ||||||
|  | main() { | ||||||
|  |     declare tmp | ||||||
|  |     tmp=$(mktemp) | ||||||
|  |     cat > "$tmp" | ||||||
|  |     sed -rn 's/.* (-[a-zA-Z0-9]).*/\1/gp' < "$tmp" | ||||||
|  | 
 | ||||||
|  |     # Do not print '=' after long options with arg because it makes completion | ||||||
|  |     # for option arguments harder. | ||||||
|  |     sed -rn 's/.* (--[-a-zA-Z0-9]+)=?.*/\1/gp' < "$tmp" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main "$@" | ||||||
							
								
								
									
										9
									
								
								shell-completion/quote.m4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								shell-completion/quote.m4
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | divert(`-1') | ||||||
|  | # quote(args) - convert args to single-quoted string | ||||||
|  | define(`quote', `ifelse(`$#', `0', `', ``$*'')') | ||||||
|  | # dquote(args) - convert args to quoted list of quoted strings | ||||||
|  | define(`dquote', ``$@'') | ||||||
|  | # dquote_elt(args) - convert args to list of double-quoted strings | ||||||
|  | define(`dquote_elt', `ifelse(`$#', `0', `', `$#', `1', ```$1''', | ||||||
|  |                              ```$1'',$0(shift($@))')') | ||||||
|  | divert`'dnl | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user