From 226f1ae816290f85b1c417b2a4ea355fe42d66ed Mon Sep 17 00:00:00 2001 From: Ryan Fitzgerald Date: Mon, 5 Sep 2011 01:45:58 -0700 Subject: [PATCH] replace direct Readline interface with InputHistory --- lib/pry.rb | 1 + lib/pry/default_commands/input.rb | 6 ++-- lib/pry/input_history.rb | 44 ++++++++++++++++++++++++ lib/pry/pry_class.rb | 31 ++++------------- lib/pry/pry_instance.rb | 21 ++--------- test/test_default_commands/test_input.rb | 4 +-- test/test_pry_history.rb | 26 +++++++------- 7 files changed, 73 insertions(+), 60 deletions(-) create mode 100644 lib/pry/input_history.rb diff --git a/lib/pry.rb b/lib/pry.rb index b6eade01..02846e27 100644 --- a/lib/pry.rb +++ b/lib/pry.rb @@ -130,6 +130,7 @@ end require "pry/version" require "pry/history_array" require "pry/helpers" +require "pry/input_history" require "pry/command_set" require "pry/commands" require "pry/command_context" diff --git a/lib/pry/default_commands/input.rb b/lib/pry/default_commands/input.rb index 4eac7a46..7c2f1582 100644 --- a/lib/pry/default_commands/input.rb +++ b/lib/pry/default_commands/input.rb @@ -97,7 +97,7 @@ e.g amend-line puts 'hello again' # no line number modifies immediately preced command "hist", "Show and replay Readline history. Type `hist --help` for more info. Aliases: history" do |*args| # exclude the current command from history. - history = Readline::HISTORY.to_a[0..-2] + history = Pry.input_history.to_a[0..-2] opts = Slop.parse!(args) do |opt| opt.banner "Usage: hist [--replay START..END] [--clear] [--grep PATTERN] [--head N] [--tail N] [--help] [--save [START..END] file.txt]\n" @@ -132,7 +132,7 @@ e.g amend-line puts 'hello again' # no line number modifies immediately preced :unless => :grep do |limit| limit ||= 10 - offset = history.size-limit + offset = history.size - limit offset = offset < 0 ? 0 : offset list = history.last limit @@ -170,7 +170,7 @@ e.g amend-line puts 'hello again' # no line number modifies immediately preced opt.on "save", "Save history to a file. --save [start..end] output.txt. Pry commands are excluded from saved history.", true, :as => Range opt.on :c, :clear, 'Clear the history', :unless => :grep do - Readline::HISTORY.shift until Readline::HISTORY.empty? + Pry.input_history.clear output.puts 'History cleared.' end diff --git a/lib/pry/input_history.rb b/lib/pry/input_history.rb new file mode 100644 index 00000000..9f0d8074 --- /dev/null +++ b/lib/pry/input_history.rb @@ -0,0 +1,44 @@ +class Pry + class InputHistory + def initialize + @history = [] + @first_new_line = 0 # TODO: rename this + end + + def load(filename) + File.foreach(filename) do |line| + Readline::HISTORY << line.chomp + @history << line.chomp + end + @first_new_line = @history.length + end + + def save(filename) + history_to_save = @history[@first_new_line..-1] + File.open(filename, 'a') do |f| + history_to_save.each { |ln| f.puts ln } + end + @first_new_line = @history.length + end + + def push(line) + line = line.to_s + unless line.empty? || (@history.last && line.strip == @history.last.strip) + Readline::HISTORY << line + @history << line + end + line + end + alias << push + + def clear + Readline::HISTORY.shift until Readline::HISTORY.empty? + @history = [] + @first_new_line = 0 + end + + def to_a + @history.dup + end + end +end diff --git a/lib/pry/pry_class.rb b/lib/pry/pry_class.rb index 73fc5752..ba34bb10 100644 --- a/lib/pry/pry_class.rb +++ b/lib/pry/pry_class.rb @@ -38,6 +38,9 @@ class Pry # @return [OpenStruct] Return Pry's config object. attr_accessor :config + # @return [InputHistory] TODO: put something here + attr_accessor :input_history + # @return [Boolean] Whether Pry was activated from the command line. attr_accessor :cli @@ -123,33 +126,12 @@ class Pry # Load Readline history if required. def self.load_history - @loaded_history = [] - if File.exists?(history_file) - File.foreach(history_file) do |line| - Readline::HISTORY << line.chomp - @loaded_history << line.chomp - end - end + Pry.input_history.load(history_file) if File.exists?(history_file) end # Save new lines of Readline history if required. def self.save_history - history_to_save = Readline::HISTORY.to_a - - # Omit any history we read from the file.This check is needed because - # `hist --clear` would otherwise cause us to not save history in this - # session. - if history_to_save[0...@loaded_history.size] == @loaded_history - history_to_save = history_to_save[@loaded_history.size..-1] - end - - File.open(history_file, 'a') do |f| - f.puts history_to_save.join("\n") if history_to_save.size > 0 - end - - # Update @loaded_history so that future calls to save_history - # will do the right thing. - @loaded_history = Readline::HISTORY.to_a + Pry.input_history.save(history_file) end # Get the full path of the history_path for pry. @@ -249,8 +231,9 @@ class Pry # Basic initialization. def self.init @plugin_manager ||= PluginManager.new - self.config ||= Config.new + self.input_history ||= InputHistory.new + reset_defaults locate_plugins end diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 5e1597d6..5372dbb7 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -356,20 +356,6 @@ class Pry Pry.line_buffer.push(*code.each_line) Pry.current_line += code.each_line.count end - if Readline::HISTORY.size > 0 - - # all this fluff is to get around annoying bug in libedit on - # ruby 1.8.7 - final_index = -1 - begin - Readline::HISTORY[-1] - rescue IndexError - final_index = -2 - end - last = Readline::HISTORY[final_index].strip - prev = Readline::HISTORY.size > 1 ? Readline::HISTORY[final_index - 1].strip : '' - Readline::HISTORY.pop if last && (last.empty? || last == prev) - end end # @return [Boolean] True if the last result is an exception that was raised, @@ -386,10 +372,9 @@ class Pry def readline(current_prompt="> ") if input == Readline - - # Readline must be treated differently - # as it has a second parameter. - input.readline(current_prompt, true) + line = input.readline(current_prompt, false) + Pry.input_history << line + line else begin if input.method(:readline).arity == 1 diff --git a/test/test_default_commands/test_input.rb b/test/test_default_commands/test_input.rb index 44389eb6..2eb45265 100644 --- a/test/test_default_commands/test_input.rb +++ b/test/test_default_commands/test_input.rb @@ -202,8 +202,8 @@ describe "Pry::DefaultCommands::Input" do end before do - Readline::HISTORY.shift until Readline::HISTORY.empty? - @hist = Readline::HISTORY + Pry.input_history.clear + @hist = Pry.input_history end it 'should display the correct history' do diff --git a/test/test_pry_history.rb b/test/test_pry_history.rb index 6d529f61..98c5d57f 100644 --- a/test/test_pry_history.rb +++ b/test/test_pry_history.rb @@ -4,7 +4,7 @@ require 'tempfile' describe Pry do before do - Readline::HISTORY.shift while Readline::HISTORY.length > 0 + Pry.input_history.clear @hist = Tempfile.new(["tmp", ".pry_history"]).tap(&:close).path File.open(@hist, 'w') {|f| f << "1\n2\n3\n" } @old_hist = Pry.config.history.file @@ -19,13 +19,13 @@ describe Pry do describe ".load_history" do it "should read the contents of the file" do - Readline::HISTORY.to_a[-2..-1].should === ["2", "3"] + Pry.input_history.to_a[-2..-1].should === ["2", "3"] end end describe ".save_history" do it "should include a trailing newline" do - Readline::HISTORY << "4" + Pry.input_history << "4" Pry.save_history File.read(@hist).should =~ /4\n\z/ end @@ -37,45 +37,45 @@ describe Pry do end it "should append new lines to the file" do - Readline::HISTORY << "4" + Pry.input_history << "4" Pry.save_history File.read(@hist).should == "1\n2\n3\n4\n" end it "should not clobber lines written by other Pry's in the meantime" do - Readline::HISTORY << "5" + Pry.input_history << "5" File.open(@hist, 'a') {|f| f << "4\n" } Pry.save_history - Readline::HISTORY.to_a[-3..-1].should == ["2", "3", "5"] + Pry.input_history.to_a[-3..-1].should == ["2", "3", "5"] File.read(@hist).should == "1\n2\n3\n4\n5\n" end it "should not delete lines from the file if this session's history was cleared" do - Readline::HISTORY.pop while Readline::HISTORY.size > 0 + Pry.input_history.clear Pry.save_history File.read(@hist).should == "1\n2\n3\n" end it "should save new lines that are added after the history was cleared" do - Readline::HISTORY.pop while Readline::HISTORY.size > 0 - Readline::HISTORY << "4" + Pry.input_history.clear + Pry.input_history << "4" # doing this twice as libedit on 1.8.7 has bugs and sometimes ignores the # first line in history - Readline::HISTORY << "4" + Pry.input_history << "4" Pry.save_history File.read(@hist).should =~ /1\n2\n3\n4\n/ end it "should only append new lines the second time it is saved" do - Readline::HISTORY << "4" + Pry.input_history << "4" Pry.save_history File.open(@hist, 'a') {|f| f << "5\n" } - Readline::HISTORY << "6" + Pry.input_history << "6" Pry.save_history - Readline::HISTORY.to_a[-4..-1].should == ["2", "3", "4", "6"] + Pry.input_history.to_a[-4..-1].should == ["2", "3", "4", "6"] File.read(@hist).should == "1\n2\n3\n4\n5\n6\n" end end