2011-09-05 04:45:58 -04:00
|
|
|
class Pry
|
2012-12-28 20:50:06 -05:00
|
|
|
# The History class is responsible for maintaining the user's input history,
|
|
|
|
# both internally and within Readline.
|
2011-09-05 04:46:16 -04:00
|
|
|
class History
|
2019-01-03 03:20:10 -05:00
|
|
|
attr_accessor :loader, :saver
|
2011-12-02 00:03:36 -05:00
|
|
|
|
2012-07-12 07:13:13 -04:00
|
|
|
# @return [Fixnum] Number of lines in history when Pry first loaded.
|
|
|
|
attr_reader :original_lines
|
|
|
|
|
2018-11-04 04:34:24 -05:00
|
|
|
def initialize(options = {})
|
2019-01-03 03:20:10 -05:00
|
|
|
@history = options[:history] || []
|
2012-12-28 19:57:30 -05:00
|
|
|
@file_path = options[:file_path]
|
2019-01-03 03:20:10 -05:00
|
|
|
@original_lines = 0
|
2014-02-02 22:51:39 -05:00
|
|
|
@loader = method(:read_from_file)
|
2019-01-02 14:02:49 -05:00
|
|
|
@saver = method(:save_to_file)
|
2011-09-05 04:45:58 -04:00
|
|
|
end
|
|
|
|
|
2011-12-02 00:03:36 -05:00
|
|
|
# Load the input history using `History.loader`.
|
2011-09-05 16:52:49 -04:00
|
|
|
# @return [Integer] The number of lines loaded
|
2011-12-02 00:03:36 -05:00
|
|
|
def load
|
|
|
|
@loader.call do |line|
|
2018-10-09 08:24:55 -04:00
|
|
|
next if invalid_readline_line?(line)
|
|
|
|
|
2011-09-05 04:45:58 -04:00
|
|
|
@history << line.chomp
|
2013-03-17 04:18:52 -04:00
|
|
|
@original_lines += 1
|
2011-09-05 04:45:58 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-12-02 00:26:22 -05:00
|
|
|
# Add a line to the input history, ignoring blank and duplicate lines.
|
2011-09-05 16:52:49 -04:00
|
|
|
# @param [String] line
|
|
|
|
# @return [String] The same line that was passed in
|
2011-09-05 04:45:58 -04:00
|
|
|
def push(line)
|
2019-01-03 03:20:10 -05:00
|
|
|
return line if line.empty? || invalid_readline_line?(line)
|
2018-10-09 08:24:55 -04:00
|
|
|
|
2019-01-03 03:20:10 -05:00
|
|
|
begin
|
|
|
|
last_line = @history[-1]
|
|
|
|
rescue IndexError
|
|
|
|
last_line = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
return line if line == last_line
|
|
|
|
|
|
|
|
@history << line
|
2019-03-01 19:03:35 -05:00
|
|
|
@saver.call(line) if !should_ignore?(line) && Pry.config.history.should_save
|
2019-01-03 03:20:10 -05:00
|
|
|
|
2011-09-05 04:45:58 -04:00
|
|
|
line
|
|
|
|
end
|
|
|
|
alias << push
|
|
|
|
|
2012-12-28 20:50:06 -05:00
|
|
|
# Clear this session's history. This won't affect the contents of the
|
2016-02-11 17:51:32 -05:00
|
|
|
# history file.
|
2011-09-05 04:45:58 -04:00
|
|
|
def clear
|
2019-01-03 03:20:10 -05:00
|
|
|
@history.clear
|
2015-01-10 13:54:27 -05:00
|
|
|
@original_lines = 0
|
2011-09-05 04:45:58 -04:00
|
|
|
end
|
|
|
|
|
2012-07-12 07:13:13 -04:00
|
|
|
# @return [Fixnum] The number of lines in history.
|
|
|
|
def history_line_count
|
|
|
|
@history.count
|
|
|
|
end
|
|
|
|
|
2012-12-28 20:50:06 -05:00
|
|
|
# @return [Fixnum] The number of lines in history from just this session.
|
2012-07-12 07:13:13 -04:00
|
|
|
def session_line_count
|
|
|
|
@history.count - @original_lines
|
|
|
|
end
|
|
|
|
|
2011-12-02 00:26:22 -05:00
|
|
|
# Return an Array containing all stored history.
|
2011-09-05 16:52:49 -04:00
|
|
|
# @return [Array<String>] An Array containing all lines of history loaded
|
|
|
|
# or entered by the user in the current session.
|
2011-09-05 04:45:58 -04:00
|
|
|
def to_a
|
2019-01-03 03:20:10 -05:00
|
|
|
@history.to_a
|
2011-09-05 04:45:58 -04:00
|
|
|
end
|
2011-12-02 00:03:36 -05:00
|
|
|
|
2015-10-25 12:39:42 -04:00
|
|
|
# Filter the history with the histignore options
|
2016-02-11 13:47:02 -05:00
|
|
|
# @return [Array<String>] An array containing all the lines that are not
|
|
|
|
# included in the histignore.
|
2015-10-25 12:39:42 -04:00
|
|
|
def filter(history)
|
2016-02-10 22:07:06 -05:00
|
|
|
history.select { |l| l unless should_ignore?(l) }
|
2015-10-25 12:39:42 -04:00
|
|
|
end
|
|
|
|
|
2011-12-02 00:03:36 -05:00
|
|
|
private
|
2012-12-28 20:50:06 -05:00
|
|
|
|
2016-02-11 13:47:02 -05:00
|
|
|
# Check if the line match any option in the histignore
|
2016-02-11 17:51:32 -05:00
|
|
|
# [Pry.config.history.histignore]
|
2016-02-11 13:47:02 -05:00
|
|
|
# @return [Boolean] a boolean that notifies if the line was found in the
|
|
|
|
# histignore array.
|
2016-02-10 22:07:06 -05:00
|
|
|
def should_ignore?(line)
|
|
|
|
hist_ignore = Pry.config.history.histignore
|
|
|
|
return false if hist_ignore.nil? || hist_ignore.empty?
|
2015-10-25 12:39:42 -04:00
|
|
|
|
2016-02-11 17:51:32 -05:00
|
|
|
hist_ignore.any? { |p| line.to_s.match(p) }
|
2015-10-25 12:39:42 -04:00
|
|
|
end
|
|
|
|
|
2011-12-02 00:03:36 -05:00
|
|
|
# The default loader. Yields lines from `Pry.history.config.file`.
|
|
|
|
def read_from_file
|
2014-07-06 18:20:03 -04:00
|
|
|
path = history_file_path
|
2012-12-28 20:50:06 -05:00
|
|
|
|
2019-03-01 19:03:35 -05:00
|
|
|
File.foreach(path) { |line| yield(line) } if File.exist?(path)
|
2018-02-11 15:15:34 -05:00
|
|
|
rescue SystemCallError => error
|
|
|
|
warn "Unable to read history file: #{error.message}"
|
2011-12-02 00:03:36 -05:00
|
|
|
end
|
|
|
|
|
2012-12-28 20:50:06 -05:00
|
|
|
# The default saver. Appends the given line to `Pry.history.config.file`.
|
2012-12-28 20:35:04 -05:00
|
|
|
def save_to_file(line)
|
|
|
|
history_file.puts line if history_file
|
|
|
|
end
|
|
|
|
|
2012-12-28 20:50:06 -05:00
|
|
|
# The history file, opened for appending.
|
2012-12-28 19:57:30 -05:00
|
|
|
def history_file
|
2012-12-28 20:50:06 -05:00
|
|
|
if defined?(@history_file)
|
|
|
|
@history_file
|
|
|
|
else
|
2019-03-03 10:37:58 -05:00
|
|
|
unless File.exist?(history_file_path)
|
|
|
|
FileUtils.mkdir_p(File.dirname(history_file_path))
|
|
|
|
end
|
2019-03-02 05:07:44 -05:00
|
|
|
@history_file = File.open(history_file_path, 'a', 0o600).tap do |file|
|
2014-07-06 18:20:03 -04:00
|
|
|
file.sync = true
|
|
|
|
end
|
2012-12-28 19:57:30 -05:00
|
|
|
end
|
2018-02-11 15:15:34 -05:00
|
|
|
rescue SystemCallError => error
|
|
|
|
warn "Unable to write history file: #{error.message}"
|
2012-12-28 20:50:06 -05:00
|
|
|
@history_file = false
|
2012-12-28 19:57:30 -05:00
|
|
|
end
|
|
|
|
|
2014-07-06 18:20:03 -04:00
|
|
|
def history_file_path
|
|
|
|
File.expand_path(@file_path || Pry.config.history.file)
|
2012-12-28 19:57:30 -05:00
|
|
|
end
|
2018-10-09 08:24:55 -04:00
|
|
|
|
|
|
|
def invalid_readline_line?(line)
|
|
|
|
# `Readline::HISTORY << line` raises an `ArgumentError` if `line`
|
|
|
|
# includes a null byte
|
|
|
|
line.include?("\0")
|
|
|
|
end
|
2011-09-05 04:45:58 -04:00
|
|
|
end
|
|
|
|
end
|