Skip to content

Instantly share code, notes, and snippets.

@gurgeous
Created May 26, 2021 21:16
Show Gist options
  • Save gurgeous/2aea9f096a7801215ff38cd031e17dd4 to your computer and use it in GitHub Desktop.
Save gurgeous/2aea9f096a7801215ff38cd031e17dd4 to your computer and use it in GitHub Desktop.
Improved zsh rake autocomplete
#
# Improved rake autocomplete. It completes three different items:
#
# (1) options like "rake --trace" or "rake --verbose"
# (2) tasks like "rake db:migrate"
# (3) files like "rake test/lib/util.rb"
#
# Options and tasks are defined using the variables below. This doesn't try to
# build a task name cache or anything like that.
#
# I know very little about zsh, so I commented this file heavily to help myself
# out later. These were useful:
#
# https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org
# man zshbuiltins
# man zshcompsys
# man zshcompwid
# /usr/share/zsh/5.7.1/functions
# /usr/local/share/zsh-completions
#
# To view existing completions:
#
# echo $_comps[rg] # show function name
# echo $functions[_rg] # show function
# whence -v $_comps[foo] # show where it came from
#
_rake () {
# Common incantations required when using _arguments with ->. -A means
# associative array.
local context state state_descr line
local -A opt_args
# Return value for this function. The convention is that zero means we
# generated completions. I am not sure if this is required, but it's certainly
# encouraged. Default to failure.
local ret=1
#
# First round of completion. Declare an array (-a) $args that contains a list
# of completions.
#
local -a args=(
# 'option[explanation]'
# {a,b,c}'xyz' is just a fancy zsh trick that expands to axyz bxyz cxyz
{--describe,-D}'[Describe the tasks, then exit]'
{--dry-run,-n}'[Do a dry run without executing actions]'
{--help,-h,-H}'[Display help message]'
{--quiet,-q}'[Do not log messages to standard output]'
{--silent,-s}"[Like --quiet, but also suppresses the 'in directory' announcement]"
{--tasks,-T}'[Display the tasks with descriptions, then exit]'
{--trace,-t}'[Turn on invoke/execute tracing, enable full backtrace]'
{--verbose,-v}'[Log message to standard output]'
{--version,-V}'[Display the program version]'
# 'pattern:message:action'. This is our fallback action for non-option
# arguments. Message ' ' is not used since we are only setting a state.
# ->fallback sets $state to fallback. We look for $state later and take
# further action.
": :->fallback"
)
# Call _arguments to do the completion. -s enables stacking single-letter
# options. ':' indicates that the spec follows. If _arguments succeeds, set
# our return value to zero.
_arguments -s : $args && ret=0
#
# Second round of completions if the first round failed. Declare an array (-a)
# $tasks that contains our rake tasks.
#
local -a tasks=(
# gems
build clean doc install lint pry rdoc release rubocop test watch
# rails
about assets:precompile db:create db:drop db:migrate db:prepare db:reset db:rollback db:setup log:clear middleware middleware tmp:clear
)
# $state will be present if the fallback action above fires.
if [[ -n "$state" ]]; then
# _alternative tries specs one at a time and presents all possible
# completions. Many forms are possible, but we only use
# 'tag:message:action'. As far as I can tell, tag must be present and must
# be unique. message is the header for this section.
local -a alternatives=(
# Completes ruby files (for "rake test/abc.rb"). It should come first to
# take priority over the "rake test" task.
'file:test file:_files -g "*.rb"'
# Completes $tasks. Many examples use _values for this purpose, but that
# doesn't play nicely with rake task names since they often contain a
# colon.
"task:rake task:compadd $tasks"
)
# Call _alternative to do the completions. If _alternative succeeds, set our
# return value to zero.
_alternative $alternatives && ret=0
fi
# Return value zero indicates that arguments were generated.
return ret
}
# Tell zsh to complete rake with our function _rake.
compdef _rake rake
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment