Tab completion for Capistrano tasks in bash

I love tab completion for rake tasks, and tonight I got annoyed that I didn’t have the same thing for Capistrano tasks. Here’s what I came up with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env ruby

# Save this somewhere, chmod 755 it, then add
#   complete -C path/to/this/script -o default cap
# to your ~/.bashrc or ~/.bash_login
#
# If you update your tasks, just $ rm ~/.captabs*
#
# Originally adapted from 
# http://onrails.org/articles/2006/08/30/namespaces-and-rake-command-completion

exit 0 unless File.file?(File.join(Dir.pwd, 'config', 'deploy.rb'))
exit 0 unless /^cap\b/ =~ ENV["COMP_LINE"]

def cap_tasks
  if File.exists?(dotcache = File.join(File.expand_path('~'), ".captabs-#{Dir.pwd.hash}"))
    File.read(dotcache)
  else
    tasks = `cap show_tasks 2>/dev/null|tail +3|cut -c 1-30|grep "[a-z]"|grep -v "^after_"|sort`
    File.open(dotcache, 'w') { |f| f.puts tasks }
    tasks
  end
end

after_match = $'
task_match = (after_match.empty? || after_match =~ /\s$/) ? nil : after_match.split.last
tasks = cap_tasks.split("\n").map { |t| t.gsub(/\s/, '') }
tasks = tasks.select { |t| /^#{Regexp.escape task_match}/ =~ t } if task_match

puts tasks
exit 0

Enjoy.

Update: I switched to Capistrano 2.0. Here’s the new tab completion code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env ruby

# Save this somewhere, chmod 755 it, then add
#   complete -C path/to/this/script -o default cap
# to your ~/.bashrc
#
# If you update your tasks, just $ rm ~/.captabs*
#
# Adapted from 
# http://onrails.org/articles/2006/08/30/namespaces-and-rake-command-completion

exit 0 unless File.file?(File.join(Dir.pwd, 'config', 'deploy.rb'))
exit 0 unless /^cap\b/ =~ ENV["COMP_LINE"]

def cap_tasks
  if File.exists?(dotcache = File.join(File.expand_path('~'), ".captabs-#{Dir.pwd.hash}"))
    File.read(dotcache)
  else
    tasks = `cap -T|grep "^cap"|cut -d " " -f 2`
    File.open(dotcache, 'w') { |f| f.puts tasks }
    tasks
  end
end

after_match = $'
task_match = (after_match.empty? || after_match =~ /\s$/) ? nil : after_match.split.last
tasks = cap_tasks.split("\n").map { |t| t.gsub(/\s/, '') }
tasks = tasks.select { |t| /^#{Regexp.escape task_match}/ =~ t } if task_match

# handle namespaces
if task_match =~ /^([-\w:]+:)/
  upto_last_colon = $1
  after_match = $'
  tasks = tasks.map { |t| (t =~ /^#{Regexp.escape upto_last_colon}([-\w:]+)$/) ? "#{$1}" : t }
end

puts tasks
exit 0

0 Responses to “Tab completion for Capistrano tasks in bash”