This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Pry
|
||||
class Command
|
||||
class Hist < Pry::ClassCommand
|
||||
match 'hist'
|
||||
group 'Editing'
|
||||
description 'Show and replay Readline history.'
|
||||
|
||||
banner <<-'BANNER'
|
||||
Usage: hist [--head|--tail]
|
||||
hist --all
|
||||
hist --head N
|
||||
hist --tail N
|
||||
hist --show START..END
|
||||
hist --grep PATTERN
|
||||
hist --clear
|
||||
hist --replay START..END
|
||||
hist --save [START..END] FILE
|
||||
Aliases: history
|
||||
|
||||
Show and replay Readline history.
|
||||
BANNER
|
||||
|
||||
def options(opt)
|
||||
opt.on :a, :all, "Display all history"
|
||||
opt.on :H, :head, "Display the first N items",
|
||||
optional_argument: true, as: Integer
|
||||
opt.on :T, :tail, "Display the last N items",
|
||||
optional_argument: true, as: Integer
|
||||
opt.on :s, :show, "Show the given range of lines",
|
||||
optional_argument: true, as: Range
|
||||
opt.on :G, :grep, "Show lines matching the given pattern",
|
||||
argument: true, as: String
|
||||
opt.on :c, :clear, "Clear the current session's history"
|
||||
opt.on :r, :replay, "Replay a line or range of lines",
|
||||
argument: true, as: Range
|
||||
opt.on :save, "Save history to a file", argument: true, as: Range
|
||||
opt.on :e, :'exclude-pry', "Exclude Pry commands from the history"
|
||||
opt.on :n, :'no-numbers', "Omit line numbers"
|
||||
end
|
||||
|
||||
def process
|
||||
@history = find_history
|
||||
|
||||
@history = @history.between(opts[:show]) if opts.present?(:show)
|
||||
|
||||
@history = @history.grep(opts[:grep]) if opts.present?(:grep)
|
||||
|
||||
@history =
|
||||
if opts.present?(:head)
|
||||
@history.take_lines(1, opts[:head] || 10)
|
||||
elsif opts.present?(:tail)
|
||||
@history.take_lines(-(opts[:tail] || 10), opts[:tail] || 10)
|
||||
else
|
||||
@history
|
||||
end
|
||||
|
||||
if opts.present?(:'exclude-pry')
|
||||
@history = @history.reject do |loc|
|
||||
command_set.valid_command?(loc.line)
|
||||
end
|
||||
end
|
||||
|
||||
if opts.present?(:save)
|
||||
process_save
|
||||
elsif opts.present?(:clear)
|
||||
process_clear
|
||||
elsif opts.present?(:replay)
|
||||
process_replay
|
||||
else
|
||||
process_display
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_display
|
||||
@history = @history.with_line_numbers unless opts.present?(:'no-numbers')
|
||||
|
||||
pry_instance.pager.open do |pager|
|
||||
@history.print_to_output(pager, true)
|
||||
end
|
||||
end
|
||||
|
||||
def process_save
|
||||
case opts[:save]
|
||||
when Range
|
||||
@history = @history.between(opts[:save])
|
||||
|
||||
raise CommandError, "Must provide a file name." unless args.first
|
||||
|
||||
file_name = File.expand_path(args.first)
|
||||
when String
|
||||
file_name = File.expand_path(opts[:save])
|
||||
end
|
||||
|
||||
output.puts "Saving history in #{file_name}..."
|
||||
|
||||
File.open(file_name, 'w') { |f| f.write(@history.raw) }
|
||||
|
||||
output.puts "History saved."
|
||||
end
|
||||
|
||||
def process_clear
|
||||
Pry.history.clear
|
||||
output.puts "History cleared."
|
||||
end
|
||||
|
||||
def process_replay
|
||||
@history = @history.between(opts[:r])
|
||||
replay_sequence = @history.raw
|
||||
|
||||
# If we met follow-up "hist" call, check for the "--replay" option
|
||||
# presence. If "hist" command is called with other options, proceed
|
||||
# further.
|
||||
check_for_juxtaposed_replay(replay_sequence)
|
||||
|
||||
replay_sequence.lines.each do |line|
|
||||
pry_instance.eval line, generated: true
|
||||
end
|
||||
end
|
||||
|
||||
# Checks +replay_sequence+ for the presence of neighboring replay calls.
|
||||
# @example
|
||||
# [1] pry(main)> hist --show 46894
|
||||
# 46894: hist --replay 46675..46677
|
||||
# [2] pry(main)> hist --show 46675..46677
|
||||
# 46675: 1+1
|
||||
# 46676: a = 100
|
||||
# 46677: hist --tail
|
||||
# [3] pry(main)> hist --replay 46894
|
||||
# Error: Replay index 46894 points out to another replay call:
|
||||
# `hist -r 46675..46677`
|
||||
# [4] pry(main)>
|
||||
#
|
||||
# @raise [Pry::CommandError] If +replay_sequence+ contains another
|
||||
# "hist --replay" call
|
||||
# @param [String] replay_sequence The sequence of commands to be replayed
|
||||
# (per saltum)
|
||||
# @return [Boolean] `false` if +replay_sequence+ does not contain another
|
||||
# "hist --replay" call
|
||||
def check_for_juxtaposed_replay(replay_sequence)
|
||||
if replay_sequence =~ /\Ahist(?:ory)?\b/
|
||||
# Create *fresh* instance of Options for parsing of "hist" command.
|
||||
slop_instance = slop
|
||||
slop_instance.parse(replay_sequence.split(' ')[1..-1])
|
||||
|
||||
if slop_instance.present?(:r)
|
||||
replay_sequence = replay_sequence.split("\n").join('; ')
|
||||
index = opts[:r]
|
||||
index = index.min if index.min == index.max || index.max.nil?
|
||||
|
||||
raise CommandError,
|
||||
"Replay index #{index} points out to another replay call: " \
|
||||
"`#{replay_sequence}`"
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Finds history depending on the given switch.
|
||||
#
|
||||
# @return [Pry::Code] if it finds `--all` (or `-a`) switch, returns all
|
||||
# entries in history. Without the switch returns only the entries from the
|
||||
# current Pry session.
|
||||
def find_history
|
||||
h = if opts.present?(:all)
|
||||
Pry.history.to_a
|
||||
else
|
||||
Pry.history.to_a.last(Pry.history.session_line_count)
|
||||
end
|
||||
|
||||
Pry::Code(Pry.history.filter(h[0..-2]))
|
||||
end
|
||||
end
|
||||
|
||||
Pry::Commands.add_command(Pry::Command::Hist)
|
||||
Pry::Commands.alias_command 'history', 'hist'
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user