pry 0.9.12.2 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1141 -0
- data/LICENSE +2 -2
- data/README.md +466 -0
- data/bin/pry +4 -7
- data/lib/pry/basic_object.rb +10 -0
- data/lib/pry/block_command.rb +22 -0
- data/lib/pry/class_command.rb +194 -0
- data/lib/pry/cli.rb +97 -92
- data/lib/pry/code/code_file.rb +114 -0
- data/lib/pry/code/code_range.rb +7 -4
- data/lib/pry/code/loc.rb +27 -14
- data/lib/pry/code.rb +62 -90
- data/lib/pry/code_object.rb +83 -39
- data/lib/pry/color_printer.rb +66 -0
- data/lib/pry/command.rb +202 -371
- data/lib/pry/command_set.rb +151 -133
- data/lib/pry/command_state.rb +31 -0
- data/lib/pry/commands/amend_line.rb +86 -82
- data/lib/pry/commands/bang.rb +18 -14
- data/lib/pry/commands/bang_pry.rb +15 -11
- data/lib/pry/commands/cat/abstract_formatter.rb +23 -18
- data/lib/pry/commands/cat/exception_formatter.rb +85 -73
- data/lib/pry/commands/cat/file_formatter.rb +56 -63
- data/lib/pry/commands/cat/input_expression_formatter.rb +35 -30
- data/lib/pry/commands/cat.rb +64 -47
- data/lib/pry/commands/cd.rb +42 -26
- data/lib/pry/commands/change_inspector.rb +34 -0
- data/lib/pry/commands/change_prompt.rb +51 -0
- data/lib/pry/commands/clear_screen.rb +20 -0
- data/lib/pry/commands/code_collector.rb +148 -131
- data/lib/pry/commands/disable_pry.rb +23 -19
- data/lib/pry/commands/easter_eggs.rb +23 -34
- data/lib/pry/commands/edit/exception_patcher.rb +21 -17
- data/lib/pry/commands/edit/file_and_line_locator.rb +33 -24
- data/lib/pry/commands/edit.rb +183 -167
- data/lib/pry/commands/exit.rb +40 -35
- data/lib/pry/commands/exit_all.rb +24 -20
- data/lib/pry/commands/exit_program.rb +20 -17
- data/lib/pry/commands/find_method.rb +167 -167
- data/lib/pry/commands/fix_indent.rb +16 -12
- data/lib/pry/commands/help.rb +140 -133
- data/lib/pry/commands/hist.rb +153 -132
- data/lib/pry/commands/import_set.rb +20 -15
- data/lib/pry/commands/jump_to.rb +25 -21
- data/lib/pry/commands/list_inspectors.rb +42 -0
- data/lib/pry/commands/ls/constants.rb +75 -0
- data/lib/pry/commands/ls/formatter.rb +55 -0
- data/lib/pry/commands/ls/globals.rb +50 -0
- data/lib/pry/commands/ls/grep.rb +23 -0
- data/lib/pry/commands/ls/instance_vars.rb +40 -0
- data/lib/pry/commands/ls/interrogatable.rb +24 -0
- data/lib/pry/commands/ls/jruby_hacks.rb +55 -0
- data/lib/pry/commands/ls/local_names.rb +37 -0
- data/lib/pry/commands/ls/local_vars.rb +47 -0
- data/lib/pry/commands/ls/ls_entity.rb +65 -0
- data/lib/pry/commands/ls/methods.rb +55 -0
- data/lib/pry/commands/ls/methods_helper.rb +50 -0
- data/lib/pry/commands/ls/self_methods.rb +34 -0
- data/lib/pry/commands/ls.rb +100 -303
- data/lib/pry/commands/nesting.rb +21 -17
- data/lib/pry/commands/play.rb +93 -49
- data/lib/pry/commands/pry_backtrace.rb +22 -18
- data/lib/pry/commands/pry_version.rb +15 -11
- data/lib/pry/commands/raise_up.rb +33 -27
- data/lib/pry/commands/reload_code.rb +57 -48
- data/lib/pry/commands/reset.rb +16 -12
- data/lib/pry/commands/ri.rb +57 -38
- data/lib/pry/commands/save_file.rb +45 -43
- data/lib/pry/commands/shell_command.rb +66 -34
- data/lib/pry/commands/shell_mode.rb +22 -20
- data/lib/pry/commands/show_doc.rb +80 -65
- data/lib/pry/commands/show_info.rb +193 -159
- data/lib/pry/commands/show_input.rb +16 -11
- data/lib/pry/commands/show_source.rb +113 -33
- data/lib/pry/commands/stat.rb +35 -31
- data/lib/pry/commands/switch_to.rb +21 -15
- data/lib/pry/commands/toggle_color.rb +21 -13
- data/lib/pry/commands/watch_expression/expression.rb +43 -0
- data/lib/pry/commands/watch_expression.rb +110 -0
- data/lib/pry/commands/whereami.rb +157 -134
- data/lib/pry/commands/wtf.rb +78 -40
- data/lib/pry/config/attributable.rb +22 -0
- data/lib/pry/config/lazy_value.rb +29 -0
- data/lib/pry/config/memoized_value.rb +34 -0
- data/lib/pry/config/value.rb +24 -0
- data/lib/pry/config.rb +290 -220
- data/lib/pry/control_d_handler.rb +28 -0
- data/lib/pry/core_extensions.rb +50 -27
- data/lib/pry/editor.rb +130 -102
- data/lib/pry/env.rb +18 -0
- data/lib/pry/exception_handler.rb +43 -0
- data/lib/pry/exceptions.rb +73 -0
- data/lib/pry/forwardable.rb +27 -0
- data/lib/pry/helpers/base_helpers.rb +22 -151
- data/lib/pry/helpers/command_helpers.rb +55 -63
- data/lib/pry/helpers/documentation_helpers.rb +21 -13
- data/lib/pry/helpers/options_helpers.rb +15 -8
- data/lib/pry/helpers/platform.rb +55 -0
- data/lib/pry/helpers/table.rb +44 -32
- data/lib/pry/helpers/text.rb +96 -86
- data/lib/pry/helpers.rb +3 -0
- data/lib/pry/history.rb +101 -70
- data/lib/pry/hooks.rb +67 -137
- data/lib/pry/indent.rb +79 -73
- data/lib/pry/input_completer.rb +283 -0
- data/lib/pry/input_lock.rb +129 -0
- data/lib/pry/inspector.rb +39 -0
- data/lib/pry/last_exception.rb +61 -0
- data/lib/pry/method/disowned.rb +19 -5
- data/lib/pry/{commands/edit/method_patcher.rb → method/patcher.rb} +51 -42
- data/lib/pry/method/weird_method_locator.rb +80 -44
- data/lib/pry/method.rb +225 -176
- data/lib/pry/object_path.rb +91 -0
- data/lib/pry/output.rb +136 -0
- data/lib/pry/pager.rb +227 -68
- data/lib/pry/prompt.rb +214 -0
- data/lib/pry/pry_class.rb +216 -289
- data/lib/pry/pry_instance.rb +438 -500
- data/lib/pry/repl.rb +256 -0
- data/lib/pry/repl_file_loader.rb +34 -35
- data/lib/pry/ring.rb +89 -0
- data/lib/pry/slop/LICENSE +20 -0
- data/lib/pry/slop/commands.rb +190 -0
- data/lib/pry/slop/option.rb +210 -0
- data/lib/pry/slop.rb +672 -0
- data/lib/pry/syntax_highlighter.rb +26 -0
- data/lib/pry/system_command_handler.rb +17 -0
- data/lib/pry/testable/evalable.rb +24 -0
- data/lib/pry/testable/mockable.rb +22 -0
- data/lib/pry/testable/pry_tester.rb +88 -0
- data/lib/pry/testable/utility.rb +34 -0
- data/lib/pry/testable/variables.rb +52 -0
- data/lib/pry/testable.rb +68 -0
- data/lib/pry/version.rb +3 -1
- data/lib/pry/warning.rb +20 -0
- data/lib/pry/{module_candidate.rb → wrapped_module/candidate.rb} +36 -43
- data/lib/pry/wrapped_module.rb +102 -103
- data/lib/pry.rb +135 -261
- metadata +94 -283
- data/.document +0 -2
- data/.gitignore +0 -16
- data/.travis.yml +0 -21
- data/.yardopts +0 -1
- data/CHANGELOG +0 -534
- data/CONTRIBUTORS +0 -55
- data/Gemfile +0 -9
- data/Guardfile +0 -62
- data/README.markdown +0 -400
- data/Rakefile +0 -140
- data/TODO +0 -117
- data/lib/pry/commands/disabled_commands.rb +0 -2
- data/lib/pry/commands/gem_cd.rb +0 -26
- data/lib/pry/commands/gem_install.rb +0 -29
- data/lib/pry/commands/gem_list.rb +0 -33
- data/lib/pry/commands/gem_open.rb +0 -29
- data/lib/pry/commands/gist.rb +0 -102
- data/lib/pry/commands/install_command.rb +0 -51
- data/lib/pry/commands/simple_prompt.rb +0 -22
- data/lib/pry/commands.rb +0 -6
- data/lib/pry/completion.rb +0 -304
- data/lib/pry/custom_completions.rb +0 -6
- data/lib/pry/history_array.rb +0 -116
- data/lib/pry/plugins.rb +0 -103
- data/lib/pry/rbx_method.rb +0 -13
- data/lib/pry/rbx_path.rb +0 -22
- data/lib/pry/rubygem.rb +0 -74
- data/lib/pry/terminal.rb +0 -78
- data/lib/pry/test/helper.rb +0 -185
- data/man/pry.1 +0 -195
- data/man/pry.1.html +0 -204
- data/man/pry.1.ronn +0 -141
- data/pry.gemspec +0 -30
- data/spec/Procfile +0 -3
- data/spec/cli_spec.rb +0 -78
- data/spec/code_object_spec.rb +0 -277
- data/spec/code_spec.rb +0 -219
- data/spec/command_helpers_spec.rb +0 -29
- data/spec/command_integration_spec.rb +0 -644
- data/spec/command_set_spec.rb +0 -627
- data/spec/command_spec.rb +0 -821
- data/spec/commands/amend_line_spec.rb +0 -247
- data/spec/commands/bang_spec.rb +0 -19
- data/spec/commands/cat_spec.rb +0 -164
- data/spec/commands/cd_spec.rb +0 -250
- data/spec/commands/disable_pry_spec.rb +0 -25
- data/spec/commands/edit_spec.rb +0 -727
- data/spec/commands/exit_all_spec.rb +0 -34
- data/spec/commands/exit_program_spec.rb +0 -19
- data/spec/commands/exit_spec.rb +0 -34
- data/spec/commands/find_method_spec.rb +0 -70
- data/spec/commands/gem_list_spec.rb +0 -26
- data/spec/commands/gist_spec.rb +0 -79
- data/spec/commands/help_spec.rb +0 -56
- data/spec/commands/hist_spec.rb +0 -181
- data/spec/commands/jump_to_spec.rb +0 -15
- data/spec/commands/ls_spec.rb +0 -181
- data/spec/commands/play_spec.rb +0 -140
- data/spec/commands/raise_up_spec.rb +0 -56
- data/spec/commands/save_file_spec.rb +0 -177
- data/spec/commands/show_doc_spec.rb +0 -510
- data/spec/commands/show_input_spec.rb +0 -17
- data/spec/commands/show_source_spec.rb +0 -782
- data/spec/commands/whereami_spec.rb +0 -203
- data/spec/completion_spec.rb +0 -239
- data/spec/control_d_handler_spec.rb +0 -58
- data/spec/documentation_helper_spec.rb +0 -73
- data/spec/editor_spec.rb +0 -79
- data/spec/exception_whitelist_spec.rb +0 -21
- data/spec/fixtures/candidate_helper1.rb +0 -11
- data/spec/fixtures/candidate_helper2.rb +0 -8
- data/spec/fixtures/example.erb +0 -5
- data/spec/fixtures/example_nesting.rb +0 -33
- data/spec/fixtures/show_source_doc_examples.rb +0 -15
- data/spec/fixtures/testrc +0 -2
- data/spec/fixtures/testrcbad +0 -2
- data/spec/fixtures/whereami_helper.rb +0 -6
- data/spec/helper.rb +0 -34
- data/spec/helpers/bacon.rb +0 -86
- data/spec/helpers/mock_pry.rb +0 -43
- data/spec/helpers/table_spec.rb +0 -105
- data/spec/history_array_spec.rb +0 -67
- data/spec/hooks_spec.rb +0 -522
- data/spec/indent_spec.rb +0 -301
- data/spec/input_stack_spec.rb +0 -90
- data/spec/method_spec.rb +0 -482
- data/spec/prompt_spec.rb +0 -60
- data/spec/pry_defaults_spec.rb +0 -419
- data/spec/pry_history_spec.rb +0 -99
- data/spec/pry_output_spec.rb +0 -95
- data/spec/pry_spec.rb +0 -504
- data/spec/run_command_spec.rb +0 -25
- data/spec/sticky_locals_spec.rb +0 -157
- data/spec/syntax_checking_spec.rb +0 -81
- data/spec/wrapped_module_spec.rb +0 -261
- data/wiki/Customizing-pry.md +0 -397
- data/wiki/Home.md +0 -4
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
class Pry
|
6
|
+
# `ObjectPath` implements the resolution of "object paths", which are strings
|
7
|
+
# that are similar to filesystem paths but meant for traversing Ruby objects.
|
8
|
+
# Examples of valid object paths include:
|
9
|
+
#
|
10
|
+
# x
|
11
|
+
# @foo/@bar
|
12
|
+
# "string"/upcase
|
13
|
+
# Pry/Method
|
14
|
+
#
|
15
|
+
# Object paths are mostly relevant in the context of the `cd` command.
|
16
|
+
# @see https://github.com/pry/pry/wiki/State-navigation
|
17
|
+
class ObjectPath
|
18
|
+
SPECIAL_TERMS = ["", "::", ".", ".."].freeze
|
19
|
+
|
20
|
+
# @param [String] path_string The object path expressed as a string.
|
21
|
+
# @param [Array<Binding>] current_stack The current state of the binding
|
22
|
+
# stack.
|
23
|
+
def initialize(path_string, current_stack)
|
24
|
+
@path_string = path_string
|
25
|
+
@current_stack = current_stack
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Array<Binding>] a new stack resulting from applying the given
|
29
|
+
# path to the current stack.
|
30
|
+
def resolve
|
31
|
+
scanner = StringScanner.new(@path_string.strip)
|
32
|
+
stack = @current_stack.dup
|
33
|
+
|
34
|
+
loop do
|
35
|
+
begin
|
36
|
+
next_segment = ""
|
37
|
+
|
38
|
+
loop do
|
39
|
+
# Scan for as long as we don't see a slash
|
40
|
+
next_segment += scanner.scan(%r{[^/]*})
|
41
|
+
|
42
|
+
if complete?(next_segment) || scanner.eos?
|
43
|
+
scanner.getch # consume the slash
|
44
|
+
break
|
45
|
+
else
|
46
|
+
next_segment += scanner.getch # append the slash
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
case next_segment.chomp
|
51
|
+
when ""
|
52
|
+
stack = [stack.first]
|
53
|
+
when "::"
|
54
|
+
stack.push(TOPLEVEL_BINDING)
|
55
|
+
when "."
|
56
|
+
next
|
57
|
+
when ".."
|
58
|
+
stack.pop unless stack.size == 1
|
59
|
+
else
|
60
|
+
stack.push(Pry.binding_for(stack.last.eval(next_segment)))
|
61
|
+
end
|
62
|
+
rescue RescuableException => e
|
63
|
+
return handle_failure(next_segment, e)
|
64
|
+
end
|
65
|
+
|
66
|
+
break if scanner.eos?
|
67
|
+
end
|
68
|
+
|
69
|
+
stack
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def complete?(segment)
|
75
|
+
SPECIAL_TERMS.include?(segment) || Pry::Code.complete_expression?(segment)
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_failure(context, err)
|
79
|
+
msg = [
|
80
|
+
"Bad object path: #{@path_string.inspect}",
|
81
|
+
"Failed trying to resolve: #{context.inspect}",
|
82
|
+
"Exception: #{err.inspect}"
|
83
|
+
].join("\n")
|
84
|
+
|
85
|
+
command_error = CommandError.new(msg)
|
86
|
+
command_error.set_backtrace(err.backtrace)
|
87
|
+
|
88
|
+
raise command_error
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/pry/output.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
class Output
|
5
|
+
# @return [Array<Integer>] default terminal screen size [rows, cols]
|
6
|
+
DEFAULT_SIZE = [27, 80].freeze
|
7
|
+
|
8
|
+
attr_reader :pry_instance
|
9
|
+
|
10
|
+
def initialize(pry_instance)
|
11
|
+
@output = pry_instance.config.output
|
12
|
+
@color = pry_instance.config.color
|
13
|
+
end
|
14
|
+
|
15
|
+
def puts(*objs)
|
16
|
+
return print "\n" if objs.empty?
|
17
|
+
|
18
|
+
objs.each do |obj|
|
19
|
+
if (ary = Array.try_convert(obj))
|
20
|
+
puts(*ary)
|
21
|
+
else
|
22
|
+
print "#{obj.to_s.chomp}\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def print(*objs)
|
29
|
+
objs.each do |obj|
|
30
|
+
@output.print decolorize_maybe(obj.to_s)
|
31
|
+
end
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
alias << print
|
35
|
+
alias write print
|
36
|
+
|
37
|
+
def tty?
|
38
|
+
@output.respond_to?(:tty?) && @output.tty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(method_name, *args, &block)
|
42
|
+
if @output.respond_to?(method_name)
|
43
|
+
@output.__send__(method_name, *args, &block)
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def respond_to_missing?(method_name, include_private = false)
|
50
|
+
@output.respond_to?(method_name, include_private)
|
51
|
+
end
|
52
|
+
|
53
|
+
def decolorize_maybe(str)
|
54
|
+
return str if @color
|
55
|
+
|
56
|
+
Pry::Helpers::Text.strip_color(str)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Array<Integer>] a pair of [rows, columns] which gives the size of
|
60
|
+
# the window. If the window size cannot be determined, the default value.
|
61
|
+
def size
|
62
|
+
rows, cols = actual_screen_size
|
63
|
+
return [rows.to_i, cols.to_i] if rows.to_i != 0 && cols.to_i != 0
|
64
|
+
|
65
|
+
DEFAULT_SIZE
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return a screen width or the default if that fails.
|
69
|
+
def width
|
70
|
+
size.last
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return a screen height or the default if that fails.
|
74
|
+
def height
|
75
|
+
size.first
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def actual_screen_size
|
81
|
+
# The best way, if possible (requires non-jruby >=1.9 or io-console gem).
|
82
|
+
io_console_size ||
|
83
|
+
# Fall back to the old standby, though it might be stale.
|
84
|
+
env_size ||
|
85
|
+
# Fall further back, though this one is also out of date without
|
86
|
+
# something calling Readline.set_screen_size.
|
87
|
+
readline_size ||
|
88
|
+
# Windows users can otherwise run ansicon and get a decent answer.
|
89
|
+
ansicon_env_size
|
90
|
+
end
|
91
|
+
|
92
|
+
def io_console_size
|
93
|
+
return if Pry::Helpers::Platform.jruby?
|
94
|
+
|
95
|
+
begin
|
96
|
+
require 'io/console'
|
97
|
+
|
98
|
+
begin
|
99
|
+
@output.winsize if tty? && @output.respond_to?(:winsize)
|
100
|
+
rescue Errno::EOPNOTSUPP # rubocop:disable Lint/HandleExceptions
|
101
|
+
# Output is probably a socket, which doesn't support #winsize.
|
102
|
+
end
|
103
|
+
rescue LoadError # rubocop:disable Lint/HandleExceptions
|
104
|
+
# They probably don't have the io/console stdlib or the io-console gem.
|
105
|
+
# We'll keep trying.
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def env_size
|
110
|
+
size = [Pry::Env['LINES'] || Pry::Env['ROWS'], Pry::Env['COLUMNS']]
|
111
|
+
size if nonzero_column?(size)
|
112
|
+
end
|
113
|
+
|
114
|
+
def readline_size
|
115
|
+
return unless defined?(Readline) && Readline.respond_to?(:get_screen_size)
|
116
|
+
|
117
|
+
size = Readline.get_screen_size
|
118
|
+
size if nonzero_column?(size)
|
119
|
+
rescue Java::JavaLang::NullPointerException
|
120
|
+
# This rescue won't happen on jrubies later than:
|
121
|
+
# https://github.com/jruby/jruby/pull/436
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def ansicon_env_size
|
126
|
+
return unless Pry::Env['ANSICON'] =~ /\((.*)x(.*)\)/
|
127
|
+
|
128
|
+
size = [Regexp.last_match(2), Regexp.last_match(1)]
|
129
|
+
size if nonzero_column?(size)
|
130
|
+
end
|
131
|
+
|
132
|
+
def nonzero_column?(size)
|
133
|
+
size[1].to_i > 0
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/pry/pager.rb
CHANGED
@@ -1,89 +1,248 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# really means is that JRuby and systems that do not have
|
10
|
-
# access to 'less' will run through the pure ruby pager.
|
11
|
-
def self.page(text, pager = nil)
|
12
|
-
case pager
|
13
|
-
when nil
|
14
|
-
no_pager = !SystemPager.available?
|
15
|
-
if no_pager || Pry::Helpers::BaseHelpers.jruby?
|
16
|
-
SimplePager.new(text).page
|
17
|
-
else
|
18
|
-
SystemPager.new(text).page
|
19
|
-
end
|
20
|
-
when :simple
|
21
|
-
SimplePager.new(text).page
|
22
|
-
when :system
|
23
|
-
SystemPager.new(text).page
|
24
|
-
else
|
25
|
-
raise "'#{pager}' is not a recognized pager."
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# A pager is an `IO`-like object that accepts text and either prints it
|
4
|
+
# immediately, prints it one page at a time, or streams it to an external
|
5
|
+
# program to print one page at a time.
|
6
|
+
class Pry
|
7
|
+
class Pager
|
8
|
+
class StopPaging < StandardError
|
26
9
|
end
|
27
|
-
end
|
28
10
|
|
29
|
-
|
30
|
-
@page_size ||= Pry::Terminal.height!
|
31
|
-
end
|
11
|
+
attr_reader :pry_instance
|
32
12
|
|
33
|
-
|
34
|
-
|
35
|
-
|
13
|
+
def initialize(pry_instance)
|
14
|
+
@pry_instance = pry_instance
|
15
|
+
end
|
36
16
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
17
|
+
# Send the given text through the best available pager (if
|
18
|
+
# `Pry.config.pager` is enabled). If you want to send text through in
|
19
|
+
# chunks as you generate it, use `open` to get a writable object
|
20
|
+
# instead.
|
21
|
+
#
|
22
|
+
# @param [String] text
|
23
|
+
# Text to run through a pager.
|
24
|
+
#
|
25
|
+
def page(text)
|
26
|
+
open do |pager|
|
27
|
+
pager << text
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Yields a pager object (`NullPager`, `SimplePager`, or `SystemPager`).
|
32
|
+
# All pagers accept output with `#puts`, `#print`, `#write`, and `#<<`.
|
33
|
+
def open
|
34
|
+
pager = best_available
|
35
|
+
yield pager
|
36
|
+
rescue StopPaging # rubocop:disable Lint/HandleExceptions
|
37
|
+
ensure
|
38
|
+
pager.close if pager
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def enabled?
|
44
|
+
!!@enabled
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_reader :output
|
48
|
+
|
49
|
+
# Return an instance of the "best" available pager class --
|
50
|
+
# `SystemPager` if possible, `SimplePager` if `SystemPager` isn't
|
51
|
+
# available, and `NullPager` if the user has disabled paging. All
|
52
|
+
# pagers accept output with `#puts`, `#print`, `#write`, and `#<<`. You
|
53
|
+
# must call `#close` when you're done writing output to a pager, and
|
54
|
+
# you must rescue `Pry::Pager::StopPaging`. These requirements can be
|
55
|
+
# avoided by using `.open` instead.
|
56
|
+
def best_available
|
57
|
+
if !pry_instance.config.pager
|
58
|
+
NullPager.new(pry_instance.output)
|
59
|
+
elsif !SystemPager.available? || Helpers::Platform.jruby?
|
60
|
+
SimplePager.new(pry_instance.output)
|
61
|
+
else
|
62
|
+
SystemPager.new(pry_instance.output)
|
50
63
|
end
|
51
64
|
end
|
52
|
-
end
|
53
65
|
|
54
|
-
|
55
|
-
|
56
|
-
|
66
|
+
# `NullPager` is a "pager" that actually just prints all output as it
|
67
|
+
# comes in. Used when `Pry.config.pager` is false.
|
68
|
+
class NullPager
|
69
|
+
def initialize(out)
|
70
|
+
@out = out
|
71
|
+
end
|
57
72
|
|
58
|
-
|
59
|
-
|
60
|
-
pager = "less -R -S -F -X"
|
73
|
+
def puts(str)
|
74
|
+
print "#{str.chomp}\n"
|
61
75
|
end
|
62
76
|
|
63
|
-
|
77
|
+
def print(str)
|
78
|
+
write str
|
79
|
+
end
|
80
|
+
alias << print
|
81
|
+
|
82
|
+
def write(str)
|
83
|
+
@out.write str
|
84
|
+
end
|
85
|
+
|
86
|
+
def close; end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def height
|
91
|
+
@height ||= @out.height
|
92
|
+
end
|
93
|
+
|
94
|
+
def width
|
95
|
+
@width ||= @out.width
|
96
|
+
end
|
64
97
|
end
|
65
98
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
99
|
+
# `SimplePager` is a straightforward pure-Ruby pager. We use it on
|
100
|
+
# JRuby and when we can't find a usable external pager.
|
101
|
+
class SimplePager < NullPager
|
102
|
+
def initialize(*)
|
103
|
+
super
|
104
|
+
@tracker = PageTracker.new(height - 3, width)
|
105
|
+
end
|
106
|
+
|
107
|
+
def write(str)
|
108
|
+
str.lines.each do |line|
|
109
|
+
@out.print line
|
110
|
+
@tracker.record line
|
111
|
+
|
112
|
+
next unless @tracker.page?
|
113
|
+
|
114
|
+
@out.print "\n"
|
115
|
+
@out.print "\e[0m"
|
116
|
+
@out.print "<page break> --- Press enter to continue " \
|
117
|
+
"( q<enter> to break ) --- <page break>\n"
|
118
|
+
raise StopPaging if Readline.readline("").chomp == "q"
|
119
|
+
|
120
|
+
@tracker.reset
|
73
121
|
end
|
74
|
-
else
|
75
|
-
@system_pager
|
76
122
|
end
|
77
123
|
end
|
78
124
|
|
79
|
-
|
80
|
-
|
81
|
-
|
125
|
+
# `SystemPager` buffers output until we're pretty sure it's at least a
|
126
|
+
# page long, then invokes an external pager and starts streaming output
|
127
|
+
# to it. If `#close` is called before then, it just prints out the
|
128
|
+
# buffered content.
|
129
|
+
class SystemPager < NullPager
|
130
|
+
def self.default_pager
|
131
|
+
pager = Pry::Env['PAGER'] || ''
|
132
|
+
|
133
|
+
# Default to less, and make sure less is being passed the correct
|
134
|
+
# options
|
135
|
+
pager = "less -R -F -X" if pager.strip.empty? || pager =~ /^less\b/
|
136
|
+
|
137
|
+
pager
|
138
|
+
end
|
139
|
+
|
140
|
+
@system_pager = nil
|
141
|
+
|
142
|
+
def self.available?
|
143
|
+
if @system_pager.nil?
|
144
|
+
@system_pager =
|
145
|
+
begin
|
146
|
+
pager_executable = default_pager.split(' ').first
|
147
|
+
if Helpers::Platform.windows? || Helpers::Platform.windows_ansi?
|
148
|
+
`where /Q #{pager_executable}`
|
149
|
+
else
|
150
|
+
`which #{pager_executable}`
|
151
|
+
end
|
152
|
+
$CHILD_STATUS.success?
|
153
|
+
rescue StandardError
|
154
|
+
false
|
155
|
+
end
|
156
|
+
else
|
157
|
+
@system_pager
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def initialize(*)
|
162
|
+
super
|
163
|
+
@tracker = PageTracker.new(height, width)
|
164
|
+
@buffer = ""
|
165
|
+
@pager = nil
|
166
|
+
end
|
167
|
+
|
168
|
+
def write(str)
|
169
|
+
if invoked_pager?
|
170
|
+
write_to_pager str
|
171
|
+
else
|
172
|
+
@tracker.record str
|
173
|
+
@buffer += str
|
174
|
+
|
175
|
+
write_to_pager @buffer if @tracker.page?
|
176
|
+
end
|
177
|
+
rescue Errno::EPIPE
|
178
|
+
raise StopPaging
|
179
|
+
end
|
180
|
+
|
181
|
+
def close
|
182
|
+
if invoked_pager?
|
183
|
+
pager.close
|
184
|
+
else
|
185
|
+
@out.puts @buffer
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def write_to_pager(text)
|
192
|
+
pager.write @out.decolorize_maybe(text)
|
193
|
+
end
|
194
|
+
|
195
|
+
def invoked_pager?
|
196
|
+
@pager
|
197
|
+
end
|
198
|
+
|
199
|
+
def pager
|
200
|
+
@pager ||= IO.popen(self.class.default_pager, 'w')
|
201
|
+
end
|
82
202
|
end
|
83
203
|
|
84
|
-
|
85
|
-
|
86
|
-
|
204
|
+
# `PageTracker` tracks output to determine whether it's likely to take
|
205
|
+
# up a whole page. This doesn't need to be super precise, but we can
|
206
|
+
# use it for `SimplePager` and to avoid invoking the system pager
|
207
|
+
# unnecessarily.
|
208
|
+
#
|
209
|
+
# One simplifying assumption is that we don't need `#page?` to return
|
210
|
+
# `true` on the basis of an incomplete line. Long lines should be
|
211
|
+
# counted as multiple lines, but we don't have to transition from
|
212
|
+
# `false` to `true` until we see a newline.
|
213
|
+
class PageTracker
|
214
|
+
def initialize(rows, cols)
|
215
|
+
@rows = rows
|
216
|
+
@cols = cols
|
217
|
+
reset
|
218
|
+
end
|
219
|
+
|
220
|
+
def record(str)
|
221
|
+
str.lines.each do |line|
|
222
|
+
if line.end_with? "\n"
|
223
|
+
@row += ((@col + line_length(line) - 1) / @cols) + 1
|
224
|
+
@col = 0
|
225
|
+
else
|
226
|
+
@col += line_length(line)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def page?
|
232
|
+
@row >= @rows
|
233
|
+
end
|
234
|
+
|
235
|
+
def reset
|
236
|
+
@row = 0
|
237
|
+
@col = 0
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
# Approximation of the printable length of a given line, without the
|
243
|
+
# newline and without ANSI color codes.
|
244
|
+
def line_length(line)
|
245
|
+
line.chomp.gsub(/\e\[[\d;]*m/, '').length
|
87
246
|
end
|
88
247
|
end
|
89
248
|
end
|