pry 0.10.3 → 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 +439 -16
- data/LICENSE +1 -1
- data/README.md +362 -302
- 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 +84 -97
- data/lib/pry/code/code_file.rb +37 -26
- data/lib/pry/code/code_range.rb +7 -5
- data/lib/pry/code/loc.rb +26 -13
- data/lib/pry/code.rb +42 -31
- data/lib/pry/code_object.rb +53 -28
- data/lib/pry/color_printer.rb +46 -35
- data/lib/pry/command.rb +197 -369
- data/lib/pry/command_set.rb +89 -114
- 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 -72
- data/lib/pry/commands/cat/file_formatter.rb +56 -46
- data/lib/pry/commands/cat/input_expression_formatter.rb +35 -30
- data/lib/pry/commands/cat.rb +62 -54
- data/lib/pry/commands/cd.rb +40 -35
- data/lib/pry/commands/change_inspector.rb +29 -22
- data/lib/pry/commands/change_prompt.rb +48 -23
- 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 +34 -23
- data/lib/pry/commands/edit.rb +185 -157
- 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 -16
- data/lib/pry/commands/find_method.rb +168 -162
- data/lib/pry/commands/fix_indent.rb +16 -12
- data/lib/pry/commands/help.rb +140 -133
- data/lib/pry/commands/hist.rb +151 -149
- 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 +35 -28
- data/lib/pry/commands/ls/constants.rb +59 -31
- data/lib/pry/commands/ls/formatter.rb +42 -36
- data/lib/pry/commands/ls/globals.rb +38 -36
- data/lib/pry/commands/ls/grep.rb +17 -15
- data/lib/pry/commands/ls/instance_vars.rb +29 -28
- data/lib/pry/commands/ls/interrogatable.rb +18 -12
- data/lib/pry/commands/ls/jruby_hacks.rb +47 -41
- data/lib/pry/commands/ls/local_names.rb +26 -24
- data/lib/pry/commands/ls/local_vars.rb +38 -30
- data/lib/pry/commands/ls/ls_entity.rb +47 -52
- data/lib/pry/commands/ls/methods.rb +49 -51
- data/lib/pry/commands/ls/methods_helper.rb +46 -42
- data/lib/pry/commands/ls/self_methods.rb +23 -21
- data/lib/pry/commands/ls.rb +124 -103
- data/lib/pry/commands/nesting.rb +21 -17
- data/lib/pry/commands/play.rb +92 -82
- data/lib/pry/commands/pry_backtrace.rb +22 -17
- 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 +60 -48
- data/lib/pry/commands/reset.rb +16 -12
- data/lib/pry/commands/ri.rb +57 -42
- data/lib/pry/commands/save_file.rb +45 -43
- data/lib/pry/commands/shell_command.rb +56 -29
- data/lib/pry/commands/shell_mode.rb +22 -18
- data/lib/pry/commands/show_doc.rb +80 -70
- data/lib/pry/commands/show_info.rb +194 -155
- data/lib/pry/commands/show_input.rb +16 -11
- data/lib/pry/commands/show_source.rb +110 -42
- data/lib/pry/commands/stat.rb +35 -31
- data/lib/pry/commands/switch_to.rb +21 -15
- data/lib/pry/commands/toggle_color.rb +20 -16
- data/lib/pry/commands/watch_expression/expression.rb +32 -27
- data/lib/pry/commands/watch_expression.rb +89 -84
- data/lib/pry/commands/whereami.rb +156 -141
- 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 +310 -20
- data/lib/pry/control_d_handler.rb +28 -0
- data/lib/pry/core_extensions.rb +22 -9
- data/lib/pry/editor.rb +56 -34
- data/lib/pry/env.rb +18 -0
- data/lib/pry/exception_handler.rb +43 -0
- data/lib/pry/exceptions.rb +13 -18
- data/lib/pry/forwardable.rb +27 -0
- data/lib/pry/helpers/base_helpers.rb +20 -62
- data/lib/pry/helpers/command_helpers.rb +52 -62
- data/lib/pry/helpers/documentation_helpers.rb +21 -12
- 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 -85
- data/lib/pry/helpers.rb +3 -0
- data/lib/pry/history.rb +81 -55
- data/lib/pry/hooks.rb +60 -110
- data/lib/pry/indent.rb +74 -68
- data/lib/pry/input_completer.rb +199 -158
- data/lib/pry/input_lock.rb +7 -10
- data/lib/pry/inspector.rb +36 -24
- data/lib/pry/last_exception.rb +45 -45
- data/lib/pry/method/disowned.rb +19 -5
- data/lib/pry/method/patcher.rb +14 -8
- data/lib/pry/method/weird_method_locator.rb +79 -45
- data/lib/pry/method.rb +178 -124
- data/lib/pry/object_path.rb +37 -28
- data/lib/pry/output.rb +102 -16
- data/lib/pry/pager.rb +187 -174
- data/lib/pry/prompt.rb +213 -25
- data/lib/pry/pry_class.rb +119 -98
- data/lib/pry/pry_instance.rb +261 -224
- data/lib/pry/repl.rb +83 -29
- data/lib/pry/repl_file_loader.rb +27 -22
- 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} +35 -32
- data/lib/pry/wrapped_module.rb +68 -63
- data/lib/pry.rb +133 -149
- metadata +58 -69
- 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 -32
- 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 -101
- data/lib/pry/commands/install_command.rb +0 -53
- data/lib/pry/commands/list_prompts.rb +0 -35
- data/lib/pry/commands/simple_prompt.rb +0 -22
- data/lib/pry/commands.rb +0 -6
- data/lib/pry/config/behavior.rb +0 -139
- data/lib/pry/config/convenience.rb +0 -25
- data/lib/pry/config/default.rb +0 -161
- data/lib/pry/history_array.rb +0 -121
- data/lib/pry/plugins.rb +0 -103
- data/lib/pry/rbx_path.rb +0 -22
- data/lib/pry/rubygem.rb +0 -82
- data/lib/pry/terminal.rb +0 -79
- data/lib/pry/test/helper.rb +0 -170
data/lib/pry/output.rb
CHANGED
@@ -1,50 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Pry
|
2
4
|
class Output
|
3
|
-
|
5
|
+
# @return [Array<Integer>] default terminal screen size [rows, cols]
|
6
|
+
DEFAULT_SIZE = [27, 80].freeze
|
7
|
+
|
8
|
+
attr_reader :pry_instance
|
4
9
|
|
5
|
-
def initialize(
|
6
|
-
@
|
10
|
+
def initialize(pry_instance)
|
11
|
+
@output = pry_instance.config.output
|
12
|
+
@color = pry_instance.config.color
|
7
13
|
end
|
8
14
|
|
9
15
|
def puts(*objs)
|
10
16
|
return print "\n" if objs.empty?
|
11
17
|
|
12
18
|
objs.each do |obj|
|
13
|
-
if ary = Array.try_convert(obj)
|
19
|
+
if (ary = Array.try_convert(obj))
|
14
20
|
puts(*ary)
|
15
21
|
else
|
16
22
|
print "#{obj.to_s.chomp}\n"
|
17
23
|
end
|
18
24
|
end
|
19
|
-
|
20
25
|
nil
|
21
26
|
end
|
22
27
|
|
23
28
|
def print(*objs)
|
24
29
|
objs.each do |obj|
|
25
|
-
|
30
|
+
@output.print decolorize_maybe(obj.to_s)
|
26
31
|
end
|
27
|
-
|
28
32
|
nil
|
29
33
|
end
|
30
34
|
alias << print
|
31
35
|
alias write print
|
32
36
|
|
33
|
-
|
34
|
-
|
35
|
-
|
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)
|
37
44
|
else
|
38
|
-
|
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.
|
39
106
|
end
|
40
107
|
end
|
41
108
|
|
42
|
-
def
|
43
|
-
|
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)
|
44
130
|
end
|
45
131
|
|
46
|
-
def
|
47
|
-
|
132
|
+
def nonzero_column?(size)
|
133
|
+
size[1].to_i > 0
|
48
134
|
end
|
49
135
|
end
|
50
136
|
end
|
data/lib/pry/pager.rb
CHANGED
@@ -1,236 +1,249 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# A pager is an `IO`-like object that accepts text and either prints it
|
4
4
|
# immediately, prints it one page at a time, or streams it to an external
|
5
5
|
# program to print one page at a time.
|
6
|
-
class Pry
|
7
|
-
class
|
8
|
-
|
9
|
-
|
10
|
-
attr_reader :_pry_
|
11
|
-
|
12
|
-
def initialize(_pry_)
|
13
|
-
@_pry_ = _pry_
|
14
|
-
end
|
15
|
-
|
16
|
-
# Send the given text through the best available pager (if `Pry.config.pager` is
|
17
|
-
# enabled).
|
18
|
-
# If you want to send text through in chunks as you generate it, use `open` to
|
19
|
-
# get a writable object instead.
|
20
|
-
# @param [String] text A piece of text to run through a pager.
|
21
|
-
# @param [IO] output (`$stdout`) An object to send output to.
|
22
|
-
def page(text)
|
23
|
-
open do |pager|
|
24
|
-
pager << text
|
6
|
+
class Pry
|
7
|
+
class Pager
|
8
|
+
class StopPaging < StandardError
|
25
9
|
end
|
26
|
-
end
|
27
10
|
|
28
|
-
|
29
|
-
# pagers accept output with `#puts`, `#print`, `#write`, and `#<<`.
|
30
|
-
# @param [IO] output (`$stdout`) An object to send output to.
|
31
|
-
def open
|
32
|
-
pager = best_available
|
33
|
-
yield pager
|
34
|
-
rescue StopPaging
|
35
|
-
ensure
|
36
|
-
pager.close if pager
|
37
|
-
end
|
11
|
+
attr_reader :pry_instance
|
38
12
|
|
39
|
-
|
40
|
-
|
41
|
-
def enabled?; !!@enabled; end
|
42
|
-
|
43
|
-
def output; @output; end
|
44
|
-
|
45
|
-
# Return an instance of the "best" available pager class -- `SystemPager` if
|
46
|
-
# possible, `SimplePager` if `SystemPager` isn't available, and `NullPager`
|
47
|
-
# if the user has disabled paging. All pagers accept output with `#puts`,
|
48
|
-
# `#print`, `#write`, and `#<<`. You must call `#close` when you're done
|
49
|
-
# writing output to a pager, and you must rescue `Pry::Pager::StopPaging`.
|
50
|
-
# These requirements can be avoided by using `.open` instead.
|
51
|
-
# @param [#<<] output ($stdout) An object to send output to.
|
52
|
-
def best_available
|
53
|
-
if !_pry_.config.pager
|
54
|
-
NullPager.new(_pry_.output)
|
55
|
-
elsif !SystemPager.available? || Pry::Helpers::BaseHelpers.jruby?
|
56
|
-
SimplePager.new(_pry_.output)
|
57
|
-
else
|
58
|
-
SystemPager.new(_pry_.output)
|
13
|
+
def initialize(pry_instance)
|
14
|
+
@pry_instance = pry_instance
|
59
15
|
end
|
60
|
-
end
|
61
16
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
67
29
|
end
|
68
30
|
|
69
|
-
|
70
|
-
|
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
|
71
39
|
end
|
72
40
|
|
73
|
-
|
74
|
-
write str
|
75
|
-
end
|
76
|
-
alias << print
|
41
|
+
private
|
77
42
|
|
78
|
-
def
|
79
|
-
|
43
|
+
def enabled?
|
44
|
+
!!@enabled
|
80
45
|
end
|
81
46
|
|
82
|
-
|
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)
|
63
|
+
end
|
83
64
|
end
|
84
65
|
|
85
|
-
|
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
|
86
72
|
|
87
|
-
|
88
|
-
|
89
|
-
|
73
|
+
def puts(str)
|
74
|
+
print "#{str.chomp}\n"
|
75
|
+
end
|
90
76
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
95
89
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
90
|
+
def height
|
91
|
+
@height ||= @out.height
|
92
|
+
end
|
93
|
+
|
94
|
+
def width
|
95
|
+
@width ||= @out.width
|
96
|
+
end
|
102
97
|
end
|
103
98
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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?
|
108
113
|
|
109
|
-
if @tracker.page?
|
110
114
|
@out.print "\n"
|
111
115
|
@out.print "\e[0m"
|
112
116
|
@out.print "<page break> --- Press enter to continue " \
|
113
117
|
"( q<enter> to break ) --- <page break>\n"
|
114
118
|
raise StopPaging if Readline.readline("").chomp == "q"
|
119
|
+
|
115
120
|
@tracker.reset
|
116
121
|
end
|
117
122
|
end
|
118
123
|
end
|
119
|
-
end
|
120
124
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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'] || ''
|
127
132
|
|
128
|
-
|
129
|
-
|
130
|
-
pager = "less -R -F -X"
|
131
|
-
end
|
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/
|
132
136
|
|
133
|
-
|
134
|
-
|
137
|
+
pager
|
138
|
+
end
|
135
139
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
144
158
|
end
|
145
|
-
else
|
146
|
-
@system_pager
|
147
159
|
end
|
148
|
-
end
|
149
160
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
161
|
+
def initialize(*)
|
162
|
+
super
|
163
|
+
@tracker = PageTracker.new(height, width)
|
164
|
+
@buffer = ""
|
165
|
+
@pager = nil
|
166
|
+
end
|
155
167
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
168
|
+
def write(str)
|
169
|
+
if invoked_pager?
|
170
|
+
write_to_pager str
|
171
|
+
else
|
172
|
+
@tracker.record str
|
173
|
+
@buffer += str
|
162
174
|
|
163
|
-
|
164
|
-
write_to_pager @buffer
|
175
|
+
write_to_pager @buffer if @tracker.page?
|
165
176
|
end
|
177
|
+
rescue Errno::EPIPE
|
178
|
+
raise StopPaging
|
166
179
|
end
|
167
|
-
rescue Errno::EPIPE
|
168
|
-
raise StopPaging
|
169
|
-
end
|
170
180
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
181
|
+
def close
|
182
|
+
if invoked_pager?
|
183
|
+
pager.close
|
184
|
+
else
|
185
|
+
@out.puts @buffer
|
186
|
+
end
|
176
187
|
end
|
177
|
-
end
|
178
188
|
|
179
|
-
|
189
|
+
private
|
180
190
|
|
181
|
-
|
182
|
-
|
183
|
-
|
191
|
+
def write_to_pager(text)
|
192
|
+
pager.write @out.decolorize_maybe(text)
|
193
|
+
end
|
184
194
|
|
185
|
-
|
186
|
-
|
187
|
-
|
195
|
+
def invoked_pager?
|
196
|
+
@pager
|
197
|
+
end
|
188
198
|
|
189
|
-
|
190
|
-
|
199
|
+
def pager
|
200
|
+
@pager ||= IO.popen(self.class.default_pager, 'w')
|
201
|
+
end
|
191
202
|
end
|
192
|
-
end
|
193
203
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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
|
207
219
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
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
|
215
228
|
end
|
216
229
|
end
|
217
|
-
end
|
218
230
|
|
219
|
-
|
220
|
-
|
221
|
-
|
231
|
+
def page?
|
232
|
+
@row >= @rows
|
233
|
+
end
|
222
234
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
235
|
+
def reset
|
236
|
+
@row = 0
|
237
|
+
@col = 0
|
238
|
+
end
|
227
239
|
|
228
|
-
|
240
|
+
private
|
229
241
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
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
|
246
|
+
end
|
234
247
|
end
|
235
248
|
end
|
236
249
|
end
|