byebug 3.5.1 → 4.0.0

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.
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