331 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			331 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| #compdef todo
 | |
| 
 | |
| # {{{ sub commands common options variables
 | |
| local common_options_help=(
 | |
| 	'(- :)--help[Show a help message and exit]'
 | |
| )
 | |
| local common_options_start=(
 | |
| 	{-s,--start=}'[When the task starts]:DATE:__todo_date'
 | |
| )
 | |
| local common_options_due=(
 | |
| 	{-d,--due=}'[When the task is due]:DATE:__todo_date'
 | |
| )
 | |
| local common_options_priority=(
 | |
| 	'--priority=[The priority for this todo]:PRIORITY:("low" "medium" "high")'
 | |
| )
 | |
| local common_options_interactive=(
 | |
| 	{-i,--interactive}'[Go into interactive mode before saving the task]'
 | |
| )
 | |
| local common_options_location=(
 | |
| 	'--location=[The location where this todo takes place]:LOCATION:'
 | |
| )
 | |
| # }}}
 | |
| # {{{ option helper: color mode
 | |
| __color_mode(){
 | |
| 	local modes=(
 | |
| 		"always:enable regardless of stdout"
 | |
| 		"auto:enable only when not on tty (default)"
 | |
| 		"never:disable colored output entirely"
 | |
| 	)
 | |
| 	_describe "mode" modes
 | |
| }
 | |
| # }}}
 | |
| # {{{ general helper: set variable of path to configuration file
 | |
| __todo_set_conf(){
 | |
| 	todoman_configuration_file=${XDG_CONFIG_DIR:-${HOME}/.config}/todoman/todoman.conf
 | |
| 	if [[ -f $todoman_configuration_file ]]; then
 | |
| 		return 0
 | |
| 	else
 | |
| 		return 1
 | |
| 	fi
 | |
| }
 | |
| # }}}
 | |
| # {{{ general helper: set variable main.path from configuration file
 | |
| __todo_set_conf_path(){
 | |
| 	if __todo_set_conf; then
 | |
| 		tasks_lists_path="$(sed -n -e 's/^[^#]\s*path\s*=\s*\(.*\)$/\1/p' $todoman_configuration_file 2>/dev/null)"
 | |
| 		# the eval echo is needed since the path may contain ~ which should be evalueated to $HOME
 | |
| 		tasks_lists_dir="$(eval echo ${tasks_lists_path%/\**})"
 | |
| 		if [[ -z "${tasks_lists_path}" || ! -d "${tasks_lists_dir}" ]]; then
 | |
| 			return 1
 | |
| 		else
 | |
| 			return 0
 | |
| 		fi
 | |
| 	else
 | |
| 		return 1
 | |
| 	fi
 | |
| }
 | |
| # }}}
 | |
| # {{{ general helper: set variables related to date and time formats for __todo_date
 | |
| __todo_set_conf_dt(){
 | |
| 	if __todo_set_conf; then
 | |
| 		date_format="$(eval echo $(sed -n -e 's/^[^#]\s*date_format\s*=\s*\(.*\)$/\1/p' $todoman_configuration_file 2>/dev/null))"
 | |
| 		dt_separator="$(eval echo $(sed -n -e 's/^[^#]\s*dt_separator\s*=\s*\(.*\)$/\1/p' $todoman_configuration_file 2>/dev/null))"
 | |
| 		time_format="$(eval echo $(sed -n -e 's/^[^#]\s*time_format\s*=\s*\(.*\)$/\1/p' $todoman_configuration_file 2>/dev/null))"
 | |
| 		# default value according to documentation: https://todoman.readthedocs.io/en/stable/configure.html
 | |
| 		if [[ -z "${date_format}" ]]; then
 | |
| 			date_format="%x"
 | |
| 		fi
 | |
| 		if [[ -z "${dt_separator}" ]]; then
 | |
| 			dt_separator=""
 | |
| 		fi
 | |
| 		if [[ -z "${time_format}" ]]; then
 | |
| 			time_format="%x"
 | |
| 		fi
 | |
| 		return 0
 | |
| 	else
 | |
| 		return 1
 | |
| 	fi
 | |
| }
 | |
| # }}}
 | |
| # {{{ option helper: due and start date
 | |
| __todo_date(){
 | |
| 	if __todo_set_conf_dt; then
 | |
| 		_message "date in format ${date_format//\%/%%}${dt_separator//\%/%%}${time_format//\%/%%}"
 | |
| 	else
 | |
| 		_message "date format (couldn't read configuration file and extract date and time formats)"
 | |
| 	fi
 | |
| }
 | |
| # }}}
 | |
| # {{{ argument helper: sub-command choice
 | |
| __todo_command(){
 | |
| 	local commands=(
 | |
| 		'cancel:Cancel one or more tasks'
 | |
| 		'copy:Copy tasks to another list'
 | |
| 		'delete:Delete tasks'
 | |
| 		'done:Mark one or more tasks as done'
 | |
| 		'edit:Edit the task with id ID'
 | |
| 		'flush:Delete done tasks'
 | |
| 		'list:List tasks'
 | |
| 		'move:Move tasks to another list'
 | |
| 		'new:Create a new task with SUMMARY'
 | |
| 		'show:Show details about a task'
 | |
| 	)
 | |
| 	_describe "command" commands
 | |
| }
 | |
| # }}}
 | |
| # {{{ argument helper: available tasks choice
 | |
| __todo_tasks(){
 | |
| 	# checking if the command jq exists and it's version
 | |
| 	# credit: http://stackoverflow.com/a/592649/4935114
 | |
| 	jq_version=$(jq --version 2>/dev/null)
 | |
| 	if [ ${${jq_version#jq\-}//./} -lt 15 ]; then
 | |
| 		_message "we can't complete tasks unless you'll install the latest version of jq: https://stedolan.github.io/jq/"
 | |
| 		return
 | |
| 	fi
 | |
| 	# $1 is a comma-seperated list of statuses to show when trying to complete this
 | |
| 	local status_search_query="$1"
 | |
| 	local -a tasks
 | |
| 	IFS=$'\n'
 | |
| 	for task_and_description in $(todo --porcelain list --status "${status_search_query}" | jq --raw-output '.[] | .id,":\"@",.list," ",.summary,"\"\\0"' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n//g' -e 's/\\0/\n/g'); do
 | |
| 		tasks+="$(eval echo ${task_and_description})"
 | |
| 	done
 | |
| 	_describe tasks tasks
 | |
| }
 | |
| # }}}
 | |
| # {{{ todo available lists cache policy
 | |
| __todo_lists_cache_policy(){
 | |
| 	# the number of seconds since 1970-01-01 the directory
 | |
| 	local tasks_lists_dir_last_date_modified="$(date -r ${tasks_lists_dir} +%s 2>/dev/null)"
 | |
| 	# the number of seconds since 1970-01-01 the cache file was modified
 | |
| 	local cache_last_date_modified="$(date -r $1 +%s 2>/dev/null)"
 | |
| 	if [[ ! -z ${cache_last_date_modified} && ! -z ${tasks_lists_dir_last_date_modified} ]]; then
 | |
| 		# if the manifest file is newer then the cache:
 | |
| 		if [ ${tasks_lists_dir_last_date_modified} -ge ${cache_last_date_modified} ]; then
 | |
| 			(( 1 ))
 | |
| 		else
 | |
| 			(( 0 ))
 | |
| 		fi
 | |
| 	else
 | |
| 		(( 1 ))
 | |
| 	fi
 | |
| }
 | |
| # }}}
 | |
| # {{{ option helper: available lists
 | |
| __todo_lists(){
 | |
| 	if __todo_set_conf_path; then
 | |
| 		local update_policy
 | |
| 		zstyle -s ":completion:${curcontext}:" cache-policy update_policy
 | |
| 		if [[ -z "$update_policy" ]]; then
 | |
| 			zstyle ":completion:${curcontext}:" cache-policy __todo_lists_cache_policy
 | |
| 		fi
 | |
| 		local -a tasks_lists
 | |
| 		if _cache_invalid todoman_lists; then
 | |
| 			if [[ ${tasks_lists_path} =~ '/*$' ]]; then
 | |
| 				for dir in $(eval echo ${tasks_lists_path}); do
 | |
| 					if grep "VTODO" -q -R "${dir}"; then
 | |
| 						list_name="${dir##*/}"
 | |
| 						tasks_lists+=("${list_name}")
 | |
| 					fi
 | |
| 				done
 | |
| 			fi
 | |
| 			_store_cache todoman_lists tasks_lists
 | |
| 		else
 | |
| 			_retrieve_cache todoman_lists
 | |
| 		fi
 | |
| 		if [[ "${#tasks_lists[@]}" == 1 ]]; then
 | |
| 			_message "only one list was detected: (\"${tasks_lists[1]}\")"
 | |
| 			return
 | |
| 		else
 | |
| 			_describe "available lists" tasks_lists
 | |
| 			return
 | |
| 		fi
 | |
| 	else
 | |
| 		_message -e "no 'path = ' string was found in todoman's default configuration file ($todoman_configuration_file)"
 | |
| 		return
 | |
| 	fi
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `cancel`
 | |
| _todo_cancel(){
 | |
| 	_arguments \
 | |
| 		"${common_options_help[@]}" \
 | |
| 		'*: :{__todo_tasks "IN-PROCESS,NEEDS-ACTION"}'
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `copy`
 | |
| local _command_copy_options=(
 | |
| 	"${common_options_help[@]}"
 | |
| 	{-l,--list=}'[The list to copy the tasks to]:TEXT:__todo_lists'
 | |
| )
 | |
| _todo_copy(){
 | |
| 	_arguments \
 | |
| 		"${_command_copy_options[@]}" \
 | |
| 		'*: :{__todo_tasks "IN-PROCESS,NEEDS-ACTION"}'
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `delete`
 | |
| local _command_delete_options=(
 | |
| 	"${common_options_help[@]}"
 | |
| 	"--yes[Don't ask for permission before deleting]"
 | |
| )
 | |
| _todo_delete(){
 | |
| 	_arguments \
 | |
| 		"${_command_delete_options[@]}" \
 | |
| 		'*: :{__todo_tasks "IN-PROCESS,NEEDS-ACTION"}'
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `done`
 | |
| local _command_done_options=(
 | |
| 	"${common_options_help[@]}"
 | |
| )
 | |
| _todo_done(){
 | |
| 	_arguments \
 | |
| 		"${_command_done_options[@]}" \
 | |
| 		'*: :{__todo_tasks "IN-PROCESS,NEEDS-ACTION"}'
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `edit`
 | |
| local _command_edit_options=(
 | |
| 	"${common_options_help[@]}"
 | |
| 	"${common_options_start[@]}"
 | |
| 	"${common_options_due[@]}"
 | |
| 	"${common_options_priority[@]}"
 | |
| 	"${common_options_location[@]}"
 | |
| 	"${common_options_interactive[@]}"
 | |
| )
 | |
| _todo_edit(){
 | |
| 	_arguments \
 | |
| 		"${_command_edit_options[@]}" \
 | |
| 		'*: :{__todo_tasks "IN-PROCESS,NEEDS-ACTION"}'
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `flush`
 | |
| _todo_flush(){
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `list`
 | |
| _command_list_options=(
 | |
| 	"${common_options_location[@]}"
 | |
| 	'--category=[Only show tasks with category containg TEXT]:TEXT:__todo_existing_categories'
 | |
| 	'--grep=[Only show tasks with message containg TEXT]:TEXT:'
 | |
| 	'--sort=[Sort tasks using these fields]:TEXT:(description location status summary uid rrule percent_complete priority sequence categories completed_at created_at dtstamp start due last_modified)'
 | |
| 	'(--reverse --no-reverse)'{--reverse,--no-reverse}'[sort tasks in reverse order (see --sort)]'
 | |
| 	"${common_options_start[@]}"
 | |
| 	"${common_options_due[@]}"
 | |
| 	'--priority[Only show tasks with priority at least as high as TEXT]:TEXT:("low", "medium", "high")'
 | |
| 	'--startable[Show only todos which should can be started today]'
 | |
| 	{-s,--status=}'[Show only todos with the provided comma-separated statuses]:STATUS:{_values -s , "status" "NEEDS-ACTION" "CANCELLED" "COMPLETED" "IN-PROCESS" "ANY"}'
 | |
| 	"${common_options_help[@]}"
 | |
| )
 | |
| _todo_list(){
 | |
| 	_arguments \
 | |
| 		"${_command_list_options[@]}" \
 | |
| 		'1: :__todo_lists' \
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `move`
 | |
| _todo_move(){
 | |
| 	_todo_copy
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `new`
 | |
| local _command_new_options=(
 | |
| 	"${common_options_start[@]}"
 | |
| 	"${common_options_due[@]}"
 | |
| 	"${common_options_help[@]}"
 | |
| 	{-l,--list=}'[The list to move the tasks to]:TEXT:__todo_lists'
 | |
| 	'--location[The location where this todo takes place.]:TEXT:__todo_existing_locations'
 | |
| 	"${common_options_priority[@]}"
 | |
| 	"${common_options_interactive[@]}"
 | |
| )
 | |
| _todo_new(){
 | |
| 	_arguments \
 | |
| 		"${_command_new_options[@]}" \
 | |
| 		'*: :{_message "summary"}'
 | |
| }
 | |
| # }}}
 | |
| # {{{ command `show`
 | |
| _todo_show(){
 | |
| 	_todo_done
 | |
| }
 | |
| # }}}
 | |
| 
 | |
| # The real thing
 | |
| _arguments -C -A "-*" \
 | |
| 	{-v,--verbosity=}'[Set verbosity to the given level]:MODE(CRITICAL ERROR WARNING INFO DEBUG)' \
 | |
| 	'--color=[Set colored output mode]:MODE:__color_mode' \
 | |
| 	'--porcelain[Use a JSON format that will remain stable regadless of configuration or version]' \
 | |
| 	{-h,--humanize}'[Format all dates and times in a human friendly way]' \
 | |
| 	'(- :)--version[Show the version and exit]' \
 | |
| 	"${common_options_help[@]}" \
 | |
| 	'1: :__todo_command' \
 | |
| 	'*::arg:->args'
 | |
| 
 | |
| case $state in
 | |
| 	(args)
 | |
| 		curcontext="${curcontext%:*:*}:todo_$words[1]:"
 | |
| 		case "${words[1]}" in
 | |
| 			cancel)
 | |
| 				_todo_cancel
 | |
| 				;;
 | |
| 			copy)
 | |
| 				_todo_copy
 | |
| 				;;
 | |
| 			delete)
 | |
| 				_todo_delete
 | |
| 				;;
 | |
| 			done)
 | |
| 				_todo_done
 | |
| 				;;
 | |
| 			edit)
 | |
| 				_todo_edit
 | |
| 				;;
 | |
| 			flush)
 | |
| 				_todo_flush
 | |
| 				;;
 | |
| 			list)
 | |
| 				_todo_list
 | |
| 				;;
 | |
| 			move)
 | |
| 				_todo_move
 | |
| 				;;
 | |
| 			new)
 | |
| 				_todo_new
 | |
| 				;;
 | |
| 			show)
 | |
| 				_todo_show
 | |
| 				;;
 | |
| 		esac
 | |
| 		;;
 | |
| esac
 | 
