byebug 3.5.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.rubocop.yml +18 -1
  4. data/.travis.yml +21 -1
  5. data/CHANGELOG.md +356 -308
  6. data/CONTRIBUTING.md +31 -15
  7. data/GUIDE.md +859 -475
  8. data/Gemfile +8 -10
  9. data/LICENSE +1 -1
  10. data/README.md +41 -45
  11. data/Rakefile +30 -28
  12. data/byebug.gemspec +18 -18
  13. data/ext/byebug/breakpoint.c +88 -75
  14. data/ext/byebug/byebug.c +253 -252
  15. data/ext/byebug/byebug.h +53 -53
  16. data/ext/byebug/context.c +188 -159
  17. data/ext/byebug/extconf.rb +9 -6
  18. data/ext/byebug/locker.c +53 -11
  19. data/ext/byebug/threads.c +137 -39
  20. data/lib/byebug/attacher.rb +7 -2
  21. data/lib/byebug/breakpoint.rb +30 -0
  22. data/lib/byebug/command.rb +36 -32
  23. data/lib/byebug/commands/break.rb +49 -48
  24. data/lib/byebug/commands/catch.rb +64 -0
  25. data/lib/byebug/commands/condition.rb +13 -9
  26. data/lib/byebug/commands/continue.rb +8 -4
  27. data/lib/byebug/commands/delete.rb +10 -4
  28. data/lib/byebug/commands/display.rb +33 -25
  29. data/lib/byebug/commands/edit.rb +18 -13
  30. data/lib/byebug/commands/enable_disable.rb +26 -24
  31. data/lib/byebug/commands/eval.rb +77 -35
  32. data/lib/byebug/commands/finish.rb +9 -5
  33. data/lib/byebug/commands/frame.rb +66 -125
  34. data/lib/byebug/commands/help.rb +14 -21
  35. data/lib/byebug/commands/history.rb +5 -1
  36. data/lib/byebug/commands/info.rb +41 -106
  37. data/lib/byebug/commands/interrupt.rb +6 -2
  38. data/lib/byebug/commands/irb.rb +5 -2
  39. data/lib/byebug/commands/kill.rb +6 -2
  40. data/lib/byebug/commands/list.rb +21 -14
  41. data/lib/byebug/commands/method.rb +17 -9
  42. data/lib/byebug/commands/pry.rb +13 -3
  43. data/lib/byebug/commands/quit.rb +10 -5
  44. data/lib/byebug/commands/restart.rb +12 -19
  45. data/lib/byebug/commands/save.rb +10 -6
  46. data/lib/byebug/commands/set.rb +15 -14
  47. data/lib/byebug/commands/show.rb +8 -8
  48. data/lib/byebug/commands/source.rb +14 -8
  49. data/lib/byebug/commands/stepping.rb +15 -29
  50. data/lib/byebug/commands/threads.rb +73 -49
  51. data/lib/byebug/commands/tracevar.rb +56 -0
  52. data/lib/byebug/commands/undisplay.rb +8 -4
  53. data/lib/byebug/commands/untracevar.rb +38 -0
  54. data/lib/byebug/commands/var.rb +107 -0
  55. data/lib/byebug/context.rb +78 -42
  56. data/lib/byebug/core.rb +78 -40
  57. data/lib/byebug/helper.rb +58 -42
  58. data/lib/byebug/history.rb +12 -1
  59. data/lib/byebug/interface.rb +91 -11
  60. data/lib/byebug/interfaces/local_interface.rb +12 -19
  61. data/lib/byebug/interfaces/remote_interface.rb +12 -15
  62. data/lib/byebug/interfaces/script_interface.rb +14 -18
  63. data/lib/byebug/interfaces/test_interface.rb +54 -0
  64. data/lib/byebug/printers/base.rb +64 -0
  65. data/lib/byebug/printers/plain.rb +53 -0
  66. data/lib/byebug/processor.rb +20 -1
  67. data/lib/byebug/processors/command_processor.rb +57 -172
  68. data/lib/byebug/processors/control_command_processor.rb +16 -43
  69. data/lib/byebug/remote.rb +13 -7
  70. data/lib/byebug/runner.rb +102 -54
  71. data/lib/byebug/setting.rb +45 -68
  72. data/lib/byebug/settings/autoeval.rb +2 -0
  73. data/lib/byebug/settings/autoirb.rb +3 -0
  74. data/lib/byebug/settings/autolist.rb +3 -0
  75. data/lib/byebug/settings/autosave.rb +2 -0
  76. data/lib/byebug/settings/basename.rb +2 -0
  77. data/lib/byebug/settings/callstyle.rb +2 -0
  78. data/lib/byebug/settings/fullpath.rb +2 -0
  79. data/lib/byebug/settings/histfile.rb +2 -0
  80. data/lib/byebug/settings/histsize.rb +2 -0
  81. data/lib/byebug/settings/linetrace.rb +2 -0
  82. data/lib/byebug/settings/listsize.rb +2 -0
  83. data/lib/byebug/settings/post_mortem.rb +7 -2
  84. data/lib/byebug/settings/stack_on_error.rb +2 -0
  85. data/lib/byebug/settings/verbose.rb +2 -0
  86. data/lib/byebug/settings/width.rb +2 -0
  87. data/lib/byebug/state.rb +12 -0
  88. data/lib/byebug/states/control_state.rb +26 -0
  89. data/lib/byebug/states/regular_state.rb +178 -0
  90. data/lib/byebug/version.rb +1 -1
  91. metadata +24 -109
  92. data/lib/byebug/commands/catchpoint.rb +0 -53
  93. data/lib/byebug/commands/reload.rb +0 -29
  94. data/lib/byebug/commands/trace.rb +0 -50
  95. data/lib/byebug/commands/variables.rb +0 -206
  96. data/lib/byebug/options.rb +0 -46
  97. data/lib/byebug/settings/autoreload.rb +0 -12
  98. data/lib/byebug/settings/forcestep.rb +0 -14
  99. data/lib/byebug/settings/testing.rb +0 -12
  100. data/lib/byebug/settings/tracing_plus.rb +0 -11
  101. data/test/commands/break_test.rb +0 -364
  102. data/test/commands/condition_test.rb +0 -85
  103. data/test/commands/continue_test.rb +0 -47
  104. data/test/commands/delete_test.rb +0 -26
  105. data/test/commands/display_test.rb +0 -37
  106. data/test/commands/edit_test.rb +0 -52
  107. data/test/commands/eval_test.rb +0 -89
  108. data/test/commands/finish_test.rb +0 -74
  109. data/test/commands/frame_test.rb +0 -223
  110. data/test/commands/help_test.rb +0 -66
  111. data/test/commands/history_test.rb +0 -61
  112. data/test/commands/info_test.rb +0 -238
  113. data/test/commands/interrupt_test.rb +0 -45
  114. data/test/commands/irb_test.rb +0 -28
  115. data/test/commands/kill_test.rb +0 -50
  116. data/test/commands/list_test.rb +0 -174
  117. data/test/commands/method_test.rb +0 -52
  118. data/test/commands/post_mortem_test.rb +0 -71
  119. data/test/commands/pry_test.rb +0 -26
  120. data/test/commands/quit_test.rb +0 -53
  121. data/test/commands/reload_test.rb +0 -39
  122. data/test/commands/restart_test.rb +0 -46
  123. data/test/commands/save_test.rb +0 -67
  124. data/test/commands/set_test.rb +0 -140
  125. data/test/commands/show_test.rb +0 -76
  126. data/test/commands/source_test.rb +0 -46
  127. data/test/commands/stepping_test.rb +0 -192
  128. data/test/commands/thread_test.rb +0 -164
  129. data/test/commands/trace_test.rb +0 -71
  130. data/test/commands/undisplay_test.rb +0 -75
  131. data/test/commands/variables_test.rb +0 -105
  132. data/test/debugger_alias_test.rb +0 -7
  133. data/test/runner_test.rb +0 -150
  134. data/test/support/matchers.rb +0 -65
  135. data/test/support/test_interface.rb +0 -59
  136. data/test/support/utils.rb +0 -122
  137. data/test/test_helper.rb +0 -58
@@ -1,32 +1,23 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Ask for help from byebug's prompt.
4
6
  #
5
7
  class HelpCommand < Command
6
- include Columnize
7
-
8
8
  self.allow_in_control = true
9
9
 
10
10
  def regexp
11
- /^\s* h(?:elp)? (?:\s+(.+))? \s*$/x
11
+ /^\s* h(?:elp)? (?: \s+(\S+) (?:\s+(\S+))? )? \s*$/x
12
12
  end
13
13
 
14
14
  def execute
15
- if @match[1]
16
- args = @match[1].split
17
- cmds = @state.commands.select { |cmd| cmd.names.include?(args[0]) }
18
- if cmds.empty?
19
- return errmsg("Undefined command: \"#{args[0]}\". Try \"help\"")
20
- end
21
-
22
- return puts(cmds.map { |cmd| cmd.help(args[1..-1]) }.join("\n"))
23
- end
15
+ return puts(self.class.help) unless @match[1]
16
+
17
+ cmd = Command.commands.select { |c| c.names.include?(@match[1]) }
18
+ return errmsg(pr('help.errors.undefined', cmd: @match[1])) unless cmd.any?
24
19
 
25
- puts "byebug help v#{VERSION}" unless Setting[:testing]
26
- puts "Type \"help <command-name>\" for help on a specific command\n"
27
- puts 'Available commands:'
28
- cmds = @state.commands.map { |cmd| cmd.names }.flatten.uniq.sort
29
- puts columnize(cmds, Setting[:width])
20
+ cmd.each { |c| puts c.help(@match[2]) }
30
21
  end
31
22
 
32
23
  class << self
@@ -35,11 +26,13 @@ module Byebug
35
26
  end
36
27
 
37
28
  def description
38
- %(h[elp][ <command>[ <subcommand>]]
29
+ prettify <<-EOD
30
+ h[elp][ <cmd>[ <subcmd>]]
39
31
 
40
- "help" alone prints this help.
41
- "help <command>" prints help on <command>.
42
- "help <command> <subcommand> prints help on <subcommand>.)
32
+ help -- prints this help.
33
+ help <cmd> -- prints help on command <cmd>.
34
+ help <cmd> <subcmd> -- prints help on <cmd>'s subcommand <subcmd>.
35
+ EOD
43
36
  end
44
37
  end
45
38
  end
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Show history of byebug commands.
@@ -24,7 +26,9 @@ module Byebug
24
26
  end
25
27
 
26
28
  def description
27
- %(hist[ory] [num_cmds] Show byebug's command history.)
29
+ prettify <<-EOD
30
+ hist[ory] [num_cmds] Show byebug's command history.
31
+ EOD
28
32
  end
29
33
  end
30
34
  end
@@ -1,6 +1,8 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
- # Utility methods to assist the info command
5
+ # Utilities for the info command.
4
6
  #
5
7
  module InfoFunctions
6
8
  def info_catch(*_args)
@@ -43,9 +45,9 @@ module Byebug
43
45
  def info_breakpoints(*args)
44
46
  return puts('No breakpoints.') if Byebug.breakpoints.empty?
45
47
 
46
- brkpts = Byebug.breakpoints.sort_by { |b| b.id }
48
+ brkpts = Byebug.breakpoints.sort_by(&:id)
47
49
  unless args.empty?
48
- indices = args.map { |a| a.to_i }
50
+ indices = args.map(&:to_i)
49
51
  brkpts = brkpts.select { |b| indices.member?(b.id) }
50
52
  return errmsg('No breakpoints found among list given') if brkpts.empty?
51
53
  end
@@ -67,63 +69,37 @@ module Byebug
67
69
  end
68
70
  end
69
71
 
70
- def info_file_path(file)
71
- s = "File #{file}"
72
+ include FileFunctions
73
+
74
+ def info_file_basic(file)
72
75
  path = File.expand_path(file)
73
- s = "#{s} - #{path}" if path && path != file
74
- puts s
75
- end
76
+ return unless File.exist?(path)
76
77
 
77
- def info_file_lines(file)
78
- lines = File.foreach(file)
79
- puts "\t#{lines.count} lines" if lines
78
+ s = n_lines(path) == 1 ? '' : 's'
79
+ "#{path} (#{n_lines(path)} line#{s})"
80
80
  end
81
81
 
82
82
  def info_file_breakpoints(file)
83
- breakpoints = LineCache.trace_line_numbers(file)
83
+ breakpoints = Breakpoint.potential_lines(file)
84
84
  return unless breakpoints
85
85
 
86
- puts "\tbreakpoint line numbers:"
87
- puts columnize(breakpoints.to_a.sort, Setting[:width])
86
+ breakpoints.to_a.sort.columnize(line_prefix: ' ',
87
+ displaywidth: Setting[:width])
88
88
  end
89
89
 
90
90
  def info_file_mtime(file)
91
- stat = File.stat(file)
92
- puts "\t#{stat.mtime}" if stat
91
+ File.stat(file).mtime
93
92
  end
94
93
 
95
94
  def info_file_sha1(file)
96
- puts "\t#{Digest::SHA1.hexdigest(file)}"
97
- end
98
-
99
- def info_files(*_args)
100
- files = SCRIPT_LINES__.keys
101
- files.uniq.sort.each do |file|
102
- info_file_path(file)
103
- info_file_mtime(file)
104
- end
95
+ require 'digest/sha1'
96
+ Digest::SHA1.hexdigest(file)
105
97
  end
106
98
 
107
99
  def info_line(*_args)
108
100
  puts "Line #{@state.line} of \"#{@state.file}\""
109
101
  end
110
102
 
111
- def print_hash(vars)
112
- vars.keys.sort.each do |name|
113
- begin
114
- s = "#{name} = #{vars[name].inspect}"
115
- rescue
116
- begin
117
- s = "#{name} = #{vars[name]}"
118
- rescue
119
- s = "#{name} = *Error in evaluation*"
120
- end
121
- end
122
- s[Setting[:width] - 3..-1] = '...' if s.size > Setting[:width]
123
- puts s
124
- end
125
- end
126
-
127
103
  def info_stop_reason(stop_reason)
128
104
  case stop_reason
129
105
  when :step
@@ -132,8 +108,6 @@ module Byebug
132
108
  puts 'It stopped at a breakpoint.'
133
109
  when :catchpoint
134
110
  puts 'It stopped at a catchpoint.'
135
- else
136
- puts "Unknown reason: #{@state.context.stop_reason}"
137
111
  end
138
112
  end
139
113
 
@@ -147,16 +121,6 @@ module Byebug
147
121
  puts 'Program stopped. '
148
122
  info_stop_reason @state.context.stop_reason
149
123
  end
150
-
151
- def info_variables(*_args)
152
- locals = @state.context.frame_locals
153
- locals[:self] = @state.context.frame_self(@state.frame_pos)
154
- print_hash(locals)
155
-
156
- obj = bb_eval('self')
157
- var_list(obj.instance_variables, obj.instance_eval { binding })
158
- var_class_self
159
- end
160
124
  end
161
125
 
162
126
  #
@@ -164,6 +128,8 @@ module Byebug
164
128
  #
165
129
  class InfoCommand < Command
166
130
  include Columnize
131
+ include InfoFunctions
132
+
167
133
  self.allow_in_control = true
168
134
 
169
135
  Subcommands = [
@@ -174,50 +140,33 @@ module Byebug
174
140
  ['catch', 3, 'Exceptions that can be caught in the current stack frame'],
175
141
  ['display', 2, 'Expressions to display when program stops'],
176
142
  ['file', 4, 'Info about a particular file read in',
177
- 'After the file name is supplied, you can list file attributes that ' \
178
- 'you wish to see. Attributes include: "all", "basic", "breakpoint", ' \
179
- '"lines", "mtime", "path" and "sha1".'],
180
- ['files', 5, 'File names and timestamps of files read in'],
143
+ 'File name, number of lines, possible breakpoints in the file, last ' \
144
+ 'modification time and sha1 digest are listed.'],
181
145
  ['line', 2, 'Line number and file name of current position in source ' \
182
146
  'file.'],
183
147
  ['program', 2, 'Execution status of the program']
184
148
  ].map do |name, min, help|
185
149
  Subcmd.new(name, min, help)
186
- end unless defined?(Subcommands)
187
-
188
- InfoFileSubcommands = [
189
- ['all', 1, 'All file information available - breakpoints, lines, ' \
190
- 'mtime, path and sha1'],
191
- ['basic', 2, 'basic information - path, number of lines'],
192
- ['breakpoints', 2, 'Show trace line numbers',
193
- 'These are the line number where a breakpoint can be set.'],
194
- ['lines', 1, 'Show number of lines in the file'],
195
- ['mtime', 1, 'Show modification time of file'],
196
- ['path', 4, 'Show full file path name for file'],
197
- ['sha1', 1, 'Show SHA1 hash of contents of the file']
198
- ].map do |name, min, help|
199
- Subcmd.new(name, min, help)
200
- end unless defined?(InfoFileSubcommands)
150
+ end
201
151
 
202
152
  def info_file(*args)
203
- return info_files unless args[0]
204
-
205
- mode = args[1] || 'basic'
206
- subcmd = Command.find(InfoFileSubcommands, mode)
207
- return errmsg "Invalid parameter #{args[1]}\n" unless subcmd
208
-
209
- if %w(all basic).member?(subcmd.name)
210
- info_file_path(args[0])
211
- info_file_lines(args[0])
212
- if subcmd.name == 'all'
213
- info_file_breakpoints(args[0])
214
- info_file_mtime(args[0])
215
- info_file_sha1(args[0])
216
- end
217
- else
218
- puts("File #{args[0]}") if subcmd.name != 'path'
219
- send("info_file_#{subcmd.name}", args[0])
153
+ file = args[0] || @state.file
154
+ unless File.exist?(file)
155
+ return errmsg(pr('info.errors.undefined_file', file: file))
220
156
  end
157
+
158
+ puts <<-EOC.gsub(/^ {6}/, '')
159
+
160
+ File #{info_file_basic(file)}
161
+
162
+ Breakpoint line numbers:
163
+ #{info_file_breakpoints(file)}
164
+
165
+ Modification time: #{info_file_mtime(file)}
166
+
167
+ Sha1 Signature: #{info_file_sha1(file)}
168
+
169
+ EOC
221
170
  end
222
171
 
223
172
  def regexp
@@ -225,7 +174,7 @@ module Byebug
225
174
  end
226
175
 
227
176
  def execute
228
- return puts(InfoCommand.help) unless @match[1]
177
+ return puts(self.class.help) unless @match[1]
229
178
 
230
179
  args = @match[1].split(/[ \t]+/)
231
180
  param = args.shift
@@ -235,7 +184,7 @@ module Byebug
235
184
  if @state.context
236
185
  send("info_#{subcmd.name}", *args)
237
186
  else
238
- errmsg "info_#{subcmd.name} not available without a context.\n"
187
+ errmsg "'info #{subcmd.name}' not available without a context.\n"
239
188
  end
240
189
  end
241
190
 
@@ -245,26 +194,12 @@ module Byebug
245
194
  end
246
195
 
247
196
  def description
248
- <<-EOD.gsub(/^ {8}/, '')
249
-
197
+ prettify <<-EOD
250
198
  info[ subcommand]
251
199
 
252
200
  Generic command for showing things about the program being debugged.
253
-
254
201
  EOD
255
202
  end
256
-
257
- def help(subcmds = [])
258
- return description + format_subcmds if subcmds.empty?
259
-
260
- subcmd = subcmds.first
261
- return format_subcmd(subcmd) unless 'file' == subcmd && subcmds[2]
262
-
263
- subsubcmd = Command.find(InfoFileSubcommands, subcmds[2])
264
- return "\nInvalid \"file\" attribute \"#{args[2]}\"." unless subsubcmd
265
-
266
- subsubcmd.short_help
267
- end
268
203
  end
269
204
  end
270
205
  end
@@ -1,9 +1,11 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Interrupting execution of current thread.
4
6
  #
5
7
  class InterruptCommand < Command
6
- self.allow_in_control = true
8
+ self.allow_in_control = true
7
9
  self.allow_in_post_mortem = false
8
10
 
9
11
  def regexp
@@ -21,7 +23,9 @@ module Byebug
21
23
  end
22
24
 
23
25
  def description
24
- %(i|nterrupt Interrupts the program.)
26
+ prettify <<-EOD
27
+ i[nterrupt] Interrupts the program.
28
+ EOD
25
29
  end
26
30
  end
27
31
  end
@@ -1,3 +1,4 @@
1
+ require 'byebug/command'
1
2
  require 'irb'
2
3
 
3
4
  module Byebug
@@ -11,7 +12,7 @@ module Byebug
11
12
 
12
13
  def execute
13
14
  unless @state.interface.is_a?(LocalInterface)
14
- return errmsg('Command is available only in local mode.')
15
+ return errmsg(pr('base.errors.only_local'))
15
16
  end
16
17
 
17
18
  IRB.start(__FILE__)
@@ -23,7 +24,9 @@ module Byebug
23
24
  end
24
25
 
25
26
  def description
26
- %{irb Starts an Interactive Ruby (IRB) session.}
27
+ prettify <<-EOD
28
+ irb Starts an Interactive Ruby (IRB) session.
29
+ EOD
27
30
  end
28
31
  end
29
32
  end
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Send custom signals to the debugged program.
@@ -31,10 +33,12 @@ module Byebug
31
33
  end
32
34
 
33
35
  def description
34
- %{kill[ SIGNAL]
36
+ prettify <<-EOD
37
+ kill[ SIGNAL]
35
38
 
36
39
  Send [signal] to Process.pid
37
- Equivalent of Process.kill(Process.pid)}
40
+ Equivalent of Process.kill(Process.pid)
41
+ EOD
38
42
  end
39
43
  end
40
44
  end
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # List parts of the source code.
@@ -8,15 +10,15 @@ module Byebug
8
10
  end
9
11
 
10
12
  def execute
11
- Byebug.source_reload if Setting[:autoreload]
12
-
13
- lines = get_lines(@state.file)
14
- return errmsg "No sourcefile available for #{@state.file}\n" unless lines
13
+ exist = File.exist?(@state.file)
14
+ return errmsg "No sourcefile available for #{@state.file}\n" unless exist
15
15
 
16
16
  @match ||= match('list')
17
- b, e = range(@match[2], lines.size)
18
- return errmsg('Invalid line range') unless valid_range?(b, e, lines.size)
19
- display_lines(b, e, lines)
17
+ max_lines = n_lines(@state.file)
18
+ b, e = range(@match[2], max_lines)
19
+ return errmsg('Invalid line range') unless valid_range?(b, e, max_lines)
20
+
21
+ display_lines(b, e)
20
22
 
21
23
  @state.prev_line = b
22
24
  end
@@ -27,13 +29,15 @@ module Byebug
27
29
  end
28
30
 
29
31
  def description
30
- %(l[ist][[-=]][ nn-mm]
32
+ prettify <<-EOD
33
+ l[ist][[-=]][ nn-mm]
31
34
 
32
35
  Lists lines of code forward from current line or from the place where
33
36
  code was last listed. If "list-" is specified, lists backwards
34
37
  instead. If "list=" is specified, lists from current line regardless
35
38
  of where code was last listed. A line range can also be specified to
36
- list specific sections of code.)
39
+ list specific sections of code.
40
+ EOD
37
41
  end
38
42
  end
39
43
 
@@ -106,14 +110,17 @@ module Byebug
106
110
  end
107
111
 
108
112
  #
109
- # Show file lines in <lines> from line number <min> to line number <max>.
113
+ # Show lines in @state.file from line number <min> to line number <max>.
110
114
  #
111
- def display_lines(min, max, lines)
115
+ def display_lines(min, max)
112
116
  puts "\n[#{min}, #{max}] in #{@state.file}"
113
117
 
114
- (min..max).to_a.zip(lines[min - 1..max - 1]).map do |l|
115
- mark = l[0] == @state.line ? '=> ' : ' '
116
- puts format("#{mark}%#{max.to_s.size}d: %s", l[0], l[1])
118
+ File.foreach(@state.file).with_index do |line, lineno|
119
+ return if lineno + 1 > max
120
+ next unless (min..max).include?(lineno + 1)
121
+
122
+ mark = lineno + 1 == @state.line ? '=> ' : ' '
123
+ puts format("#{mark}%#{max.to_s.size}d: %s", lineno + 1, line)
117
124
  end
118
125
  end
119
126
  end