Namespaces and Rake Command Completion 2

Posted by Lee Marlow Wed, 30 Aug 2006 21:34:00 GMT

Update: Now using rake and caching

I got some basic rake command line completion working today using Jon Baer’s comment. Very simple, very easy:

complete -W '`rake—silent—tasks | cut -d ” ” -f 2`' -o default rake

However this didn’t work for the namespaced tasks in a rails app like rake test:units. Searching a little further I found a reference to some code Nicholas Seckar wrote on project.ioni.st. This used ruby to find the possible tasks for command completion. This looked promising, but it still didn’t work for namespaced tasks. A little more googling led me to what looked like the perfect link: Rake-completion script that handles namespaces. Alas, it only handled one level of namespacing. It worked nicely for rake test:units, but rake tmp:ses<TAB> would complete to rake tmp:clear instead of rake tmp:sessions:clear. Also, rake test:units <TAB> would complete to rake test:units units instead of giving me all the tasks again, just in case you want to run multiple tasks form the command line.

So, now what? Stand on the shoulders of others, naturally. Here is what I’m using now that handles multiple namespaces and multiple tasks per command line:

#!/usr/bin/env ruby

# Complete rake tasks script for bash
# Save it somewhere and then add
# complete -C path/to/script -o default rake
# to your ~/.bashrc
# Nicholas Seckar <nseckar@gmail.com>
# Saimon Moore <saimon@webtypes.com>
# http://www.webtypes.com/2006/03/31/rake-completion-script-that-handles-namespaces

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

after_match = $'
task_match = (after_match.empty? || after_match =~ /\s$/) ? nil : after_match.split.last
tasks = `rake --silent --tasks`.split("\n")[1..-1].collect {|line| line.split[1]}
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.collect { |t| (t =~ /^#{Regexp.escape upto_last_colon}([-\w:]+)$/) ? "#{$1}" : t }
end

puts tasks
exit 0

Enjoy

Comments

Leave a response

  1. Saimon Moore Fri, 22 Sep 2006 07:54:17 GMT

    Hi Lee,

    Great improvement on the script. A lot quicker as well. Thanks.

    I’ve updated my entry to point people to your version.

  2. Nikos D. Thu, 17 Apr 2008 13:55:36 GMT
    Hmm… I think I found a bug. In line 16 you say :
    tasks = rake_silent_tasks.split("\n")[1..-1].map { |line| line.split[1] }
    
    I guess that you DO want the first result to show up, so what you want is :
    tasks = rake_silent_tasks.split("\n")[0..-1].map { |line| line.split[1] }
    

    Cheers! Really handy script :)

Comments