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