diff --git a/lib/pry/commands.rb b/lib/pry/commands.rb index 79672616..cfd86e97 100644 --- a/lib/pry/commands.rb +++ b/lib/pry/commands.rb @@ -272,10 +272,10 @@ e.g: gist -d my_method command "shell-mode", "Toggle shell mode. Bring in pwd prompt and file completion." do case Pry.active_instance.prompt when Pry::SHELL_PROMPT - Pry.active_instance.prompt = Pry::DEFAULT_PROMPT + Pry.active_instance.pop_prompt Pry.active_instance.custom_completions = Pry::DEFAULT_CUSTOM_COMPLETIONS else - Pry.active_instance.prompt = Pry::SHELL_PROMPT + Pry.active_instance.push_prompt Pry::SHELL_PROMPT Pry.active_instance.custom_completions = Pry::FILE_COMPLETIONS Readline.completion_proc = Pry::InputCompleter.build_completion_proc target, Pry.active_instance.instance_eval(&Pry::FILE_COMPLETIONS) diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 0a6ed4f0..807da7e3 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -30,7 +30,7 @@ class Pry default_options.merge!(options) CONFIG_OPTIONS.each do |key| - instance_variable_set("@#{key}", default_options[key]) + send "#{key}=", default_options[key] end @command_processor = CommandProcessor.new(self) @@ -320,6 +320,63 @@ class Pry end end + # the array that the prompt stack is stored in + def prompt_stack + @prompt_stack ||= Array.new + end + private :prompt_stack + + # The current prompt, this is the prompt at the top of the prompt stack. + # @return [Array] Current prompt. + # @example + # push_prompt(Pry::SIMPLE_PROMPT) + # prompt # => Pry::SIMPLE_PROMPT + def prompt + prompt_stack.last + end + + # Replaces the current prompt with the new prompt. + # Does not change the rest of the prompt stack. + # @param [Array] new_prompt + # @return [Array] new_prompt + # @example + # pry.prompt = Pry::SIMPLE_PROMPT # => Pry::SIMPLE_PROMPT + # pry.prompt # => Pry::SIMPLE_PROMPT + def prompt=(new_prompt) + if prompt_stack.empty? + push_prompt new_prompt + else + prompt_stack[-1] = new_prompt + end + end + + # Pushes the current prompt onto a stack that it can be restored from later. + # Use this if you wish to temporarily change the prompt. + # @param [Array] new_prompt + # @return [Array] new_prompt + # @example + # new_prompt = [ proc { '>' }, proc { '>>' } ] + # push_prompt(new_prompt) # => new_prompt + def push_prompt(new_prompt) + prompt_stack.push new_prompt + end + + # Pops the current prompt off of the prompt stack. + # If the prompt you are popping is the last prompt, it will not be popped. + # Use this to restore the previous prompt. + # @return [Array] Prompt being popped. + # @example + # prompt1 = [ proc { '>' }, proc { '>>' } ] + # prompt2 = [ proc { '$' }, proc { '>' } ] + # pry = Pry.new :prompt => prompt1 + # pry.push_prompt(prompt2) + # pry.pop_prompt # => prompt2 + # pry.pop_prompt # => prompt1 + # pry.pop_prompt # => prompt1 + def pop_prompt + if prompt_stack.size > 1 then prompt_stack.pop else prompt end + end + if RUBY_VERSION =~ /1.9/ && RUBY_ENGINE == "ruby" require 'ripper' diff --git a/test/test_pry.rb b/test/test_pry.rb index 1421a99e..95c33449 100644 --- a/test/test_pry.rb +++ b/test/test_pry.rb @@ -708,6 +708,67 @@ describe Pry do Pry.new.select_prompt(true, 0).should == "test prompt> " Pry.new.select_prompt(false, 0).should == "test prompt* " end + + describe 'storing and restoring the prompt' do + before do + make = lambda do |name,i| + prompt = [ proc { "#{i}>" } , proc { "#{i+1}>" } ] + (class << prompt; self; end).send(:define_method, :inspect) { "" } + prompt + end + @a , @b , @c = make[:a,0] , make[:b,1] , make[:c,2] + @pry = Pry.new :prompt => @a + end + it 'should have a prompt stack' do + @pry.push_prompt @b + @pry.push_prompt @c + @pry.prompt.should == @c + @pry.pop_prompt + @pry.prompt.should == @b + @pry.pop_prompt + @pry.prompt.should == @a + end + + it 'should restore overridden prompts when returning from file-mode' do + pry = Pry.new :input => InputTester.new('shell-mode', 'shell-mode'), + :prompt => [ proc { 'P>' } ] * 2 + pry.select_prompt(true, 0).should == "P>" + pry.re + pry.select_prompt(true, 0).should =~ /\Apry .* \$ \z/ + pry.re + pry.select_prompt(true, 0).should == "P>" + end + + it '#pop_prompt should return the popped prompt' do + @pry.push_prompt @b + @pry.push_prompt @c + @pry.pop_prompt.should == @c + @pry.pop_prompt.should == @b + end + + it 'should not pop the last prompt' do + @pry.push_prompt @b + @pry.pop_prompt.should == @b + @pry.pop_prompt.should == @a + @pry.pop_prompt.should == @a + @pry.prompt.should == @a + end + + describe '#prompt= should replace the current prompt with the new prompt' do + it 'when only one prompt on the stack' do + @pry.prompt = @b + @pry.prompt.should == @b + @pry.pop_prompt.should == @b + @pry.pop_prompt.should == @b + end + it 'when several prompts on the stack' do + @pry.push_prompt @b + @pry.prompt = @c + @pry.pop_prompt.should == @c + @pry.pop_prompt.should == @a + end + end + end end it 'should set the hooks default, and the default should be overridable' do