diff --git a/lib/pry/command.rb b/lib/pry/command.rb index 30890d00..1913dff0 100644 --- a/lib/pry/command.rb +++ b/lib/pry/command.rb @@ -392,6 +392,12 @@ class Pry @dependencies_met ||= command_dependencies_met?(command_options) end + # Generate completions for this command + # + # @param [String] search The line typed so far + # @return [Array] Completion words + def complete(search); Bond::DefaultMission.completions; end + private # Run the `#call` method and all the registered hooks. @@ -499,6 +505,15 @@ class Pry end end + # Generate shell completions + # @param [String] search The line typed so far + # @return [Array] the words to complete + def complete(search) + slop.map do |opt| + [opt.long && "--#{opt.long}" || opt.short && "-#{opt.short}"] + end.flatten(1).compact + super + end + # A function called just before `options(opt)` as part of `call`. # # This function can be used to set up any context your command needs to run, for example diff --git a/lib/pry/command_set.rb b/lib/pry/command_set.rb index a38f36d5..900ff162 100644 --- a/lib/pry/command_set.rb +++ b/lib/pry/command_set.rb @@ -348,6 +348,20 @@ class Pry command.new(context).call_safely(*args) end + # Generate completions for the user's search. + # @param [String] search The line to search for + # @param [Hash] context The context to create the command with + # @return [Array] + def complete(search, context={}) + if command = find_command(search) + command.new(context).complete(search) + else + commands.keys.select do |x| + String === x && x.start_with?(search) + end + Bond::DefaultMission.completions + end + end + private def default_options(match) diff --git a/lib/pry/commands/edit.rb b/lib/pry/commands/edit.rb index 36e4ed8f..424ef406 100644 --- a/lib/pry/commands/edit.rb +++ b/lib/pry/commands/edit.rb @@ -26,6 +26,10 @@ class Pry opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)" end + def complete(search) + super + Bond::Rc.files(search.split(" ").last || '') + end + def process if [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), !args.empty?].count(true) > 1 raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified." diff --git a/lib/pry/completion.rb b/lib/pry/completion.rb index ba871ec3..fe5258c8 100644 --- a/lib/pry/completion.rb +++ b/lib/pry/completion.rb @@ -3,11 +3,16 @@ class Pry module BondCompleter + def self.build_completion_proc(target, pry=nil, commands=[""]) - Bond.start - Bond.complete(:on => %r/^edit\s/) do |input| - ::Readline::FILENAME_COMPLETION_PROC.call(input) || [] + Bond.restart(:eval_binding => lambda{ pry.current_context }) + Bond.complete(:on => /\A/) do |input| + Pry.commands.complete(input.line, + :pry_instance => pry, + :target => pry.current_context, + :command_set => pry.commands) end + proc{ |*a| Bond.agent.call(*a) } end end diff --git a/test/test_command.rb b/test/test_command.rb index 66dee88b..64f62d3b 100644 --- a/test/test_command.rb +++ b/test/test_command.rb @@ -696,6 +696,20 @@ describe "Pry::Command" do end end + describe 'complete' do + it 'should return the arguments that are defined' do + @set.create_command "torrid" do + def options(opt) + opt.on :test + opt.on :lest + opt.on :pests + end + end + + @set.complete('torrid ').should.include('--test') + end + end + describe 'group' do before do @set.import( diff --git a/test/test_command_set.rb b/test/test_command_set.rb index f0cdf439..40676154 100644 --- a/test/test_command_set.rb +++ b/test/test_command_set.rb @@ -610,4 +610,16 @@ describe Pry::CommandSet do @set.process_line('nannnnnny oggggg') end end + + describe '.complete' do + it "should list all command names" do + @set.create_command('susan'){ } + @set.complete('sus').should.include 'susan' + end + + it "should delegate to commands" do + @set.create_command('susan'){ def complete(search); ['--foo']; end } + @set.complete('susan ').should == ['--foo'] + end + end end