diff --git a/lib/boxen/autocomplete.rb b/lib/boxen/autocomplete.rb new file mode 100755 index 0000000..24acf87 --- /dev/null +++ b/lib/boxen/autocomplete.rb @@ -0,0 +1,37 @@ +#!/usr/bin/env ruby + +module Boxen + module Autocomplete + # refresh options via: ruby -e 'puts `boxen -h 2>/dev/null`.scan(/\-+[a-z\?-]+/).inspect' + OPTIONS = ["--debug", "--pretend", "--noop", "--report", "--env", "-h", "-?", "--help", "--disable-service", "--enable-service", "--restart-service", "--disable-services", "--enable-services", "--restart-services", "--list-services", "--homedir", "--logfile", "--login", "--no-fde", "--no-pull", "--no-issue", "--stealth", "--token", "--profile", "--future-parser", "--projects", "--srcdir", "--user", "--no-color"] + SERVICE_OPTIONS = OPTIONS.select { |o| o.end_with?("-service") } + DIR_OPTIONS = ["--logfile", "--homedir"] + + class << self + def complete(typed) + if part = after(typed, SERVICE_OPTIONS) + available_services.select { |s| s.start_with?(part) } + elsif after(typed, DIR_OPTIONS) + [] + else + OPTIONS.select { |o| o.start_with?(typed[/([a-z-]*)$/,1].to_s) } + end + end + + private + + def after(typed, kind) + typed[/(#{kind.join("|")})\s+([^\s]*)?$/, 2] + end + + # keep in sync with boxen/service.rb + def available_services + Dir["/Library/LaunchDaemons/dev.*.plist"].map { |f| f[/dev\.(.*)\.plist/, 1] } + end + end + end +end + +if $0 == __FILE__ + puts Boxen::Autocomplete.complete(ENV["COMP_LINE"]) +end diff --git a/manifests/environment.pp b/manifests/environment.pp index 15f3ac0..6ee150a 100644 --- a/manifests/environment.pp +++ b/manifests/environment.pp @@ -38,5 +38,8 @@ ensure => $relative_bin_on_path_ensure, source => 'puppet:///modules/boxen/relative_bin_on_path.sh', priority => 'lowest' ; + 'boxen_autocomplete': + content => template('boxen/boxen_autocomplete.sh.erb'), + priority => 'lowest' ; } } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d3923f8..f33f19b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,7 @@ fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures')) RSpec.configure do |c| + c.mock_framework = :rspec c.module_path = File.join(fixture_path, 'modules') c.manifest_dir = File.join(fixture_path, 'manifests') end diff --git a/spec/unit/boxen/autocomplete_spec.rb b/spec/unit/boxen/autocomplete_spec.rb new file mode 100644 index 0000000..c9b6114 --- /dev/null +++ b/spec/unit/boxen/autocomplete_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' +require 'boxen/autocomplete' + +describe Boxen::Autocomplete do + describe ".complete" do + def call(string) + Boxen::Autocomplete.complete(string) + end + + let(:available_services) { ["mysql", "myother", "nginx"] } + + before do + Boxen::Autocomplete.stub(:available_services).and_return(available_services) + end + + it "completes from nothing" do + call("boxen ").should include "-h" + end + + it "completes from partial option" do + call("boxen --res").should == ["--restart-service", "--restart-services"] + end + + it "completes from end of service" do + call("boxen --restart-service").should == ["--restart-service", "--restart-services"] + end + + it "completes from after service" do + call("boxen --restart-service ").should == available_services + end + + it "completes from partial service name" do + call("boxen --restart-service my").should == (available_services - ["nginx"]) + end + + it "completes from after service name" do + call("boxen --restart-service nginx ").should include "-h" + end + + it "completes files after file options" do + call("boxen --logfile ").should == [] + call("boxen --homedir ").should == [] + end + end +end diff --git a/templates/boxen_autocomplete.sh.erb b/templates/boxen_autocomplete.sh.erb new file mode 100644 index 0000000..abb5670 --- /dev/null +++ b/templates/boxen_autocomplete.sh.erb @@ -0,0 +1,4 @@ +# Autocomplete for boxen + +<% script = File.expand_path("../../lib/boxen/autocomplete.rb", __FILE__) %> +type complete >/dev/null && complete -C <%= script %> -o default boxen