debug 1.0.0.beta6 → 1.0.0.beta7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fffc4898e989a76e77a9076407cc1ba6d31b13a531e739c8972afe71bf049285
4
- data.tar.gz: 190c18099e1078e00786dde75819b0b793647cd9508b0577e88d93d6a06c045c
3
+ metadata.gz: d545d212530685e0eaf7163bc0b2517befd0edfdc1b083c64ecab6bfcb6958b8
4
+ data.tar.gz: 6662febf1dccfbc0e7e4ec785578fb5eac2a076fa488a4a3a814582f80fa940f
5
5
  SHA512:
6
- metadata.gz: 647e6c227bded49c962b8d6934557a26930664f5f1ddd57fd596c6651b1c655c1c77e64d5cbba28d2125cdd8a27817e33dc94d465d01f6b43b7f0be61ee30a35
7
- data.tar.gz: ceb4dbf7b9479dc54ff5af725e973985493650ca9aaebd16878c4669fa037ae2ee1ec9ddddf83eb25dd65dc2057d0419a74005ec5d74c98585d855eb918e53bb
6
+ metadata.gz: 3173551c5ada6fb2f7f71656a5762b6a6a6cc541d80d371532abfe1e03188f81ffb397df1a2c8d743c34983e27c5abe6e33ae8d8188502960501801af3aa9ea3
7
+ data.tar.gz: 59c84ef76b01d8630b764784d68edb7b1e25e2c336cab56a74e23add5f606f14c3dfe2d6cdd9fe3779e328ca8873317d5d7b56a8e5a7951ecc3a081c20c309d8
data/README.md CHANGED
@@ -83,6 +83,7 @@ require 'debug/run' # start the debug console
83
83
  # ... rest of program ...
84
84
  ```
85
85
 
86
+
86
87
  ```
87
88
  $ ruby target.rb
88
89
  ```
@@ -90,6 +91,24 @@ $ ruby target.rb
90
91
  When you run the program with the debug console, you will see the debug console prompt `(rdbg)`.
91
92
  The debuggee program (`target.rb`) is suspended at the beginning of `target.rb`.
92
93
 
94
+
95
+ Alternatively, start the debugger at a specific location in your program using `binding.break` (`binding.b` for short).
96
+
97
+ ```ruby
98
+ # target.rb
99
+ require 'debug' # start the debugger
100
+
101
+ # ... program ...
102
+
103
+ binding.break # setup a breakpoint at this line
104
+
105
+ # ... rest of program ...
106
+ ```
107
+
108
+ ```
109
+ $ ruby target.rb
110
+ ```
111
+
93
112
  You can type any debugger's command described bellow. "c" or "continue" resume the debuggee program.
94
113
  You can suspend the debuggee program and show the debug console with `Ctrl-C`.
95
114
 
@@ -310,20 +329,41 @@ If there are `~/.rdbgrc`, the file is loaded as initial scripts which contains d
310
329
 
311
330
  If there are `~/.rdbgrc.rb` is available, it is loaded as a ruby script at same timing.
312
331
 
313
- ### Environment variables
332
+ ### Configurations
314
333
 
315
- You can control debuggee's behavior with environment variables:
334
+ You can configure debugger's setting with environment variables and `config` command.
335
+ You can write any configuration into `~/.rdbgrc` like:
336
+
337
+ ```
338
+ config set log_level INFO
339
+ config set no_color true
340
+ ```
316
341
 
317
- * `RUBY_DEBUG_NONSTOP`: 1 for nonstop at the beginning of program.
318
- * `RUBY_DEBUG_INIT_SCRIPT`: Initial script path loaded at the first stop.
319
- * `RUBY_DEBUG_COMMANDS`: Debug commands invoked at the first stop. Commands should be separated by ';;'.
320
- * `RUBY_DEBUG_SHOW_SRC_LINES`: Show n lines source code on breakpoint (default: 10 lines).
321
- * `RUBY_DEBUG_SHOW_FRAMES`: Show n frames on breakpoint (default: 2 frames).
322
- * Remote debugging
323
- * `RUBY_DEBUG_PORT`: TCP/IP remote debugging: port to open.
324
- * `RUBY_DEBUG_HOST`: TCP/IP remote debugging: host (localhost if not given) to open.
325
- * `RUBY_DEBUG_SOCK_PATH`: UNIX Domain Socket remote debugging: socket path to open.
326
- * `RUBY_DEBUG_SOCK_DIR`: UNIX Domain Socket remote debugging: socket directory to open.
342
+
343
+ * UI
344
+ * `RUBY_DEBUG_LOG_LEVEL` (`log_level`): Log level same as Logger (default: WARN)
345
+ * `RUBY_DEBUG_SHOW_SRC_LINES` (`show_src_lines`): Show n lines source code on breakpoint (default: 10 lines)
346
+ * `RUBY_DEBUG_SHOW_FRAMES` (`show_frames`): Show n frames on breakpoint (default: 2 frames)
347
+ * `RUBY_DEBUG_SHOW_INFO_LINES` (`show_info_lines`): Show n lines on info command (default: 10 lines, 0 for unlimited)
348
+ * `RUBY_DEBUG_USE_SHORT_PATH` (`use_short_path`): Show shoten PATH (like $(Gem)/foo.rb)
349
+ * `RUBY_DEBUG_SKIP_NOSRC` (`skip_nosrc`): Skip on no source code lines (default: false)
350
+ * `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing frames for given paths (default: [])
351
+ * `RUBY_DEBUG_NO_COLOR` (`no_color`): Do not use colorize (default: false)
352
+ * `RUBY_DEBUG_NO_SIGINT_HOOK` (`no_sigint_hook`): Do not suspend on SIGINT (default: false)
353
+
354
+ * BOOT
355
+ * `RUBY_DEBUG_NONSTOP` (`nonstop`): Nonstop mode
356
+ * `RUBY_DEBUG_INIT_SCRIPT` (`init_script`): debug command script path loaded at first stop
357
+ * `RUBY_DEBUG_COMMANDS` (`commands`): debug commands invoked at first stop. commands should be separated by ';;'
358
+ * `RUBY_DEBUG_NO_RC` (`no_rc`): ignore loading ~/.rdbgrc(.rb)
359
+ * `RUBY_DEBUG_HISTORY` (`history`): save and load history file (default: ~/.rdbg_history)
360
+
361
+ * REMOTE
362
+ * `RUBY_DEBUG_PORT` (`port`): TCP/IP remote debugging: port
363
+ * `RUBY_DEBUG_HOST` (`host`): TCP/IP remote debugging: host (localhost if not given)
364
+ * `RUBY_DEBUG_SOCK_PATH` (`sock_path`): UNIX Domain Socket remote debugging: socket path
365
+ * `RUBY_DEBUG_SOCK_DIR` (`sock_dir`): UNIX Domain Socket remote debugging: socket directory
366
+ * `RUBY_DEBUG_COOKIE` (`cookie`): Cookie for negotiation
327
367
 
328
368
  ## Debug command on the debug console
329
369
 
@@ -366,10 +406,14 @@ The `<...>` notation means the argument.
366
406
  * Set breakpoint on the method `<class>#<name>`.
367
407
  * `b[reak] <expr>.<name>`
368
408
  * Set breakpoint on the method `<expr>.<name>`.
369
- * `b[reak] ... if <expr>`
409
+ * `b[reak] ... if: <expr>`
370
410
  * break if `<expr>` is true at specified location.
371
- * `b[reak] if <expr>`
372
- * break if `<expr>` is true at any lines.
411
+ * `b[reak] ... pre: <command>`
412
+ * break and run `<command>` before stopping.
413
+ * `b[reak] ... do: <command>`
414
+ * break and run `<command>`, and continue.
415
+ * `b[reak] if: <expr>`
416
+ * break if: `<expr>` is true at any lines.
373
417
  * Note that this feature is super slow.
374
418
  * `catch <Error>`
375
419
  * Set breakpoint on raising `<Error>`.
@@ -385,6 +429,12 @@ The `<...>` notation means the argument.
385
429
 
386
430
  * `bt` or `backtrace`
387
431
  * Show backtrace (frame) information.
432
+ * `bt <num>` or `backtrace <num>`
433
+ * Only shows first `<num>` frames.
434
+ * `bt /regexp/` or `backtrace /regexp/`
435
+ * Only shows frames with method name or location info that matches `/regexp/`.
436
+ * `bt <num> /regexp/` or `backtrace <num> /regexp/`
437
+ * Only shows first `<num>` frames with method name or location info that matches `/regexp/`.
388
438
  * `l[ist]`
389
439
  * Show current frame's source code.
390
440
  * Next `list` command shows the successor lines.
@@ -442,6 +492,19 @@ The `<...>` notation means the argument.
442
492
  * `th[read] <thnum>`
443
493
  * Switch thread specified by `<thnum>`.
444
494
 
495
+ ### Configuration
496
+
497
+ * `config`
498
+ * Show all configuration with description.
499
+ * `config <name>`
500
+ * Show current configuration of <name>.
501
+ * `config set <name> <val>` or `config <name> = <val>`
502
+ * Set <name> to <val>.
503
+ * `config append <name> <val>` or `config <name> << <val>`
504
+ * Append `<val>` to `<name>` if it is an array.
505
+ * `config unset <name>`
506
+ * Set <name> to default.
507
+
445
508
  ### Help
446
509
 
447
510
  * `h[elp]`
@@ -457,7 +520,7 @@ exe/rdbg [options] -- [debuggee options]
457
520
 
458
521
  Debug console mode:
459
522
  -n, --nonstop Do not stop at the beginning of the script.
460
- -e COMMAND Execute debug command at the beginning of the script.
523
+ -e DEBUG_COMMAND Execute debug command at the beginning of the script.
461
524
  -x, --init-script=FILE Execute debug command in the FILE.
462
525
  --no-rc Ignore ~/.rdbgrc
463
526
  --no-color Disable colorize
@@ -477,6 +540,9 @@ Debug console mode:
477
540
 
478
541
  'rdbg target.rb foo bar' starts like 'ruby target.rb foo bar'.
479
542
  'rdbg -- -r foo -e bar' starts like 'ruby -r foo -e bar'.
543
+ 'rdbg -c rake test' starts like 'rake test'.
544
+ 'rdbg -c -- rake test -t' starts like 'rake test -t'.
545
+ 'rdbg -c bundle exec rake test' starts like 'bundle exec rake test'.
480
546
  'rdbg -O target.rb foo bar' starts and accepts attaching with UNIX domain socket.
481
547
  'rdbg -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234.
482
548
  'rdbg -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234.
data/TODO.md CHANGED
@@ -2,14 +2,11 @@
2
2
 
3
3
  ## Basic functionality
4
4
 
5
- * VScode DAP support
6
5
  * Support Ractors
7
6
  * Signal (SIGINT) support
8
- * Remote connection with openssl
9
7
 
10
8
  ## UI
11
9
 
12
- * Coloring
13
10
  * Interactive breakpoint setting
14
11
  * irb integration
15
12
  * Web browser integrated UI
@@ -28,6 +25,3 @@
28
25
 
29
26
  ## Tests
30
27
 
31
- * Test framework
32
- * Tests for commands
33
- * Tests for remote debugging
@@ -49,15 +49,22 @@ module DEBUGGER__
49
49
  end
50
50
 
51
51
  def suspend
52
+ if @command
53
+ provider, pre_cmds, do_cmds = @command
54
+ nonstop = true if do_cmds
55
+ cmds = [*pre_cmds&.split(';;'), *do_cmds&.split(';;')]
56
+ SESSION.add_preset_commands provider, cmds, kick: false, continue: nonstop
57
+ end
58
+
52
59
  ThreadClient.current.on_breakpoint @tp, self
53
60
  end
54
61
 
55
62
  def to_s
56
- if @cond
57
- " if #{@cond}"
58
- else
59
- ""
60
- end
63
+ s = ''.dup
64
+ s << " if: #{@cond}" if defined?(@cond) && @cond
65
+ s << " pre: #{@command[1]}" if defined?(@command) && @command && @command[1]
66
+ s << " do: #{@command[2]}" if defined?(@command) && @command && @command[2]
67
+ s
61
68
  end
62
69
 
63
70
  def description
@@ -68,27 +75,24 @@ module DEBUGGER__
68
75
  false
69
76
  end
70
77
 
71
- class << self
72
- include Color
78
+ include Color
73
79
 
74
- def generate_label(name)
75
- colorize(" BP - #{name} ", [:YELLOW, :BOLD, :REVERSE])
76
- end
80
+ def generate_label(name)
81
+ colorize(" BP - #{name} ", [:YELLOW, :BOLD, :REVERSE])
77
82
  end
78
83
  end
79
84
 
80
85
  class LineBreakpoint < Breakpoint
81
- LABEL = generate_label("Line")
82
- PENDING_LABEL = generate_label("Line (pending)")
83
-
84
86
  attr_reader :path, :line, :iseq
85
87
 
86
- def initialize path, line, cond: nil, oneshot: false, hook_call: true
88
+ def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil
87
89
  @path = path
88
90
  @line = line
89
91
  @cond = cond
90
92
  @oneshot = oneshot
91
93
  @hook_call = hook_call
94
+ @command = command
95
+ @pending = false
92
96
 
93
97
  @iseq = nil
94
98
  @type = nil
@@ -96,23 +100,21 @@ module DEBUGGER__
96
100
  @key = [@path, @line].freeze
97
101
 
98
102
  super()
103
+
99
104
  try_activate
105
+ @pending = !@iseq
100
106
  end
101
107
 
102
108
  def setup
103
109
  return unless @type
104
110
 
105
- if !@cond
106
- @tp = TracePoint.new(@type) do |tp|
107
- delete if @oneshot
108
- suspend
109
- end
110
- else
111
- @tp = TracePoint.new(@type) do |tp|
111
+ @tp = TracePoint.new(@type) do |tp|
112
+ if @cond
112
113
  next unless safe_eval tp.binding, @cond
113
- delete if @oneshot
114
- suspend
115
114
  end
115
+ delete if @oneshot
116
+
117
+ suspend
116
118
  end
117
119
  end
118
120
 
@@ -138,9 +140,12 @@ module DEBUGGER__
138
140
 
139
141
  @key = [@path, @line].freeze
140
142
  SESSION.rehash_bps
141
-
142
143
  setup
143
144
  enable
145
+
146
+ if @pending && !@oneshot
147
+ DEBUGGER__.warn "#{self} is activated."
148
+ end
144
149
  end
145
150
 
146
151
  def activate_exact iseq, events, line
@@ -162,7 +167,6 @@ module DEBUGGER__
162
167
  end
163
168
 
164
169
  def duplicable?
165
- # only binding.bp or DEBUGGER__.console are duplicable
166
170
  @oneshot
167
171
  end
168
172
 
@@ -214,9 +218,9 @@ module DEBUGGER__
214
218
  oneshot = @oneshot ? " (oneshot)" : ""
215
219
 
216
220
  if @iseq
217
- "#{LABEL} #{@path}:#{@line} (#{@type})#{oneshot}" + super
221
+ "#{generate_label("Line")} #{@path}:#{@line} (#{@type})#{oneshot}" + super
218
222
  else
219
- "#{PENDING_LABEL} #{@path}:#{@line}#{oneshot}" + super
223
+ "#{generate_label("Line (pending)")} #{@path}:#{@line}#{oneshot}" + super
220
224
  end
221
225
  end
222
226
 
@@ -226,7 +230,6 @@ module DEBUGGER__
226
230
  end
227
231
 
228
232
  class CatchBreakpoint < Breakpoint
229
- LABEL = generate_label("Catch")
230
233
  attr_reader :last_exc
231
234
 
232
235
  def initialize pat
@@ -240,7 +243,9 @@ module DEBUGGER__
240
243
  def setup
241
244
  @tp = TracePoint.new(:raise){|tp|
242
245
  exc = tp.raised_exception
246
+ next if SystemExit === exc
243
247
  should_suspend = false
248
+
244
249
  exc.class.ancestors.each{|cls|
245
250
  if @pat === cls.name
246
251
  should_suspend = true
@@ -253,7 +258,7 @@ module DEBUGGER__
253
258
  end
254
259
 
255
260
  def to_s
256
- "#{LABEL} #{@pat.inspect}"
261
+ "#{generate_label("Catch")} #{@pat.inspect}"
257
262
  end
258
263
 
259
264
  def description
@@ -262,8 +267,6 @@ module DEBUGGER__
262
267
  end
263
268
 
264
269
  class CheckBreakpoint < Breakpoint
265
- LABEL = generate_label("Check")
266
-
267
270
  def initialize expr
268
271
  @expr = expr.freeze
269
272
  @key = [:check, @expr].freeze
@@ -285,13 +288,11 @@ module DEBUGGER__
285
288
  end
286
289
 
287
290
  def to_s
288
- "#{LABEL} #{@expr}"
291
+ "#{generate_label("Check")} #{@expr}"
289
292
  end
290
293
  end
291
294
 
292
295
  class WatchIVarBreakpoint < Breakpoint
293
- LABEL = generate_label("Watch")
294
-
295
296
  def initialize ivar, object, current
296
297
  @ivar = ivar.to_sym
297
298
  @object = object
@@ -332,17 +333,14 @@ module DEBUGGER__
332
333
  else
333
334
  "#{@current}"
334
335
  end
335
- "#{LABEL} #{@object} #{@ivar} = #{value_str}"
336
+ "#{generate_label("Watch")} #{@object} #{@ivar} = #{value_str}"
336
337
  end
337
338
  end
338
339
 
339
340
  class MethodBreakpoint < Breakpoint
340
- LABEL = generate_label("Method")
341
- PENDING_LABEL = generate_label("Method (pending)")
342
-
343
341
  attr_reader :sig_method_name, :method
344
342
 
345
- def initialize b, klass_name, op, method_name, cond
343
+ def initialize b, klass_name, op, method_name, cond, command: nil
346
344
  @sig_klass_name = klass_name
347
345
  @sig_op = op
348
346
  @sig_method_name = method_name
@@ -351,6 +349,7 @@ module DEBUGGER__
351
349
  @klass = nil
352
350
  @method = nil
353
351
  @cond = cond
352
+ @command = command
354
353
  @key = "#{klass_name}#{op}#{method_name}".freeze
355
354
 
356
355
  super(false)
@@ -391,13 +390,14 @@ module DEBUGGER__
391
390
  try_enable
392
391
  end
393
392
 
394
- def try_enable quiet: false
393
+ def try_enable added: false
395
394
  eval_class_name
396
395
  search_method
397
396
 
398
397
  begin
399
398
  retried = false
400
399
  @tp.enable(target: @method)
400
+ DEBUGGER__.warn "#{self} is activated." if added
401
401
 
402
402
  rescue ArgumentError
403
403
  raise if retried
@@ -418,7 +418,7 @@ module DEBUGGER__
418
418
  retry
419
419
  end
420
420
  rescue Exception
421
- raise unless quiet
421
+ raise unless added
422
422
  end
423
423
 
424
424
  def sig
@@ -427,9 +427,9 @@ module DEBUGGER__
427
427
 
428
428
  def to_s
429
429
  if @method
430
- "#{LABEL} #{sig}"
430
+ "#{generate_label("Method")} #{sig} at #{@method.source_location.join(':')}"
431
431
  else
432
- "#{PENDING_LABEL} #{sig}"
432
+ "#{generate_label("Method (pending)")} #{sig}"
433
433
  end + super
434
434
  end
435
435
  end
data/lib/debug/client.rb CHANGED
@@ -47,6 +47,7 @@ module DEBUGGER__
47
47
  end
48
48
 
49
49
  @width = IO.console_size[1]
50
+ @width = 80 if @width == 0
50
51
  @width_changed = false
51
52
 
52
53
  send "version: #{VERSION} width: #{@width} cookie: #{CONFIG[:cookie]}"
data/lib/debug/color.rb CHANGED
@@ -24,8 +24,12 @@ module DEBUGGER__
24
24
  end
25
25
 
26
26
  if defined? IRB::ColorPrinter.pp
27
- def color_pp obj
28
- IRB::ColorPrinter.pp(obj, "".dup)
27
+ def color_pp obj, width = SESSION.width
28
+ if !CONFIG[:no_color]
29
+ IRB::ColorPrinter.pp(obj, "".dup, width)
30
+ else
31
+ obj.pretty_inspect
32
+ end
29
33
  end
30
34
  else
31
35
  def color_pp obj
@@ -33,8 +37,8 @@ module DEBUGGER__
33
37
  end
34
38
  end
35
39
 
36
- def colored_inspect obj
37
- if !CONFIG[:no_color]
40
+ def colored_inspect obj, no_color: false
41
+ if !no_color
38
42
  color_pp obj
39
43
  else
40
44
  obj.pretty_inspect
data/lib/debug/config.rb CHANGED
@@ -30,52 +30,80 @@ module DEBUGGER__
30
30
  create_unix_domain_socket_name_prefix(base_dir) + "-#{Process.pid}"
31
31
  end
32
32
 
33
- CONFIG_MAP = {
34
- # boot setting
35
- nonstop: 'RUBY_DEBUG_NONSTOP', # Nonstop mode ('1' is nonstop)
36
- init_script: 'RUBY_DEBUG_INIT_SCRIPT', # debug command script path loaded at first stop
37
- commands: 'RUBY_DEBUG_COMMANDS', # debug commands invoked at first stop. commands should be separated by ';;'
38
- no_rc: 'RUBY_DEBUG_NO_RC', # ignore loading ~/.rdbgrc(.rb)
39
-
33
+ CONFIG_SET = {
40
34
  # UI setting
41
- show_src_lines: 'RUBY_DEBUG_SHOW_SRC_LINES', # Show n lines source code on breakpoint (default: 10 lines).
42
- show_frames: 'RUBY_DEBUG_SHOW_FRAMES', # Show n frames on breakpoint (default: 2 frames).
43
- use_short_path: 'RUBY_DEBUG_USE_SHORT_PATH', # Show shoten PATH (like $(Gem)/foo.rb).
44
- skip_nosrc: 'RUBY_DEBUG_SKIP_NOSRC', # Skip on no source code lines (default: false).
45
- no_color: 'RUBY_DEBUG_NO_COLOR', # Do not use colorize
46
- no_sigint_hook: 'RUBY_DEBUG_NO_SIGINT_HOOK', # Do not suspend on SIGINT
47
- quiet: 'RUBY_DEBUG_QUIET', # Do not show messages
35
+ log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger (default: WARN)", :loglevel],
36
+ show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint (default: 10 lines)", :int],
37
+ show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint (default: 2 frames)", :int],
38
+ show_info_lines:['RUBY_DEBUG_SHOW_INFO_LINES',"UI: Show n lines on info command (default: 10 lines, 0 for unlimited)", :int],
39
+ use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shoten PATH (like $(Gem)/foo.rb)", :bool],
40
+ skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "UI: Skip on no source code lines (default: false)", :bool],
41
+ skip_path: ['RUBY_DEBUG_SKIP_PATH', "UI: Skip showing frames for given paths (default: [])", :path],
42
+ no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize (default: false)", :bool],
43
+ no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT (default: false)", :bool],
44
+
45
+ # boot setting
46
+ nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool],
47
+ init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
48
+ commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. commands should be separated by ';;'"],
49
+ no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool],
50
+ history: ['RUBY_DEBUG_HISTORY', "BOOT: save and load history file (default: ~/.rdbg_history)"],
48
51
 
49
52
  # remote setting
50
- port: 'RUBY_DEBUG_PORT', # TCP/IP remote debugging: port
51
- host: 'RUBY_DEBUG_HOST', # TCP/IP remote debugging: host (localhost if not given)
52
- sock_path: 'RUBY_DEBUG_SOCK_PATH', # UNIX Domain Socket remote debugging: socket path
53
- sock_dir: 'RUBY_DEBUG_SOCK_DIR', # UNIX Domain Socket remote debugging: socket directory
54
- cookie: 'RUBY_DEBUG_COOKIE', # Cookie for negotiation
53
+ port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
54
+ host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host (localhost if not given)"],
55
+ sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
56
+ sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
57
+ cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
55
58
  }.freeze
56
59
 
60
+ CONFIG_MAP = CONFIG_SET.map{|k, (ev, desc)| [k, ev]}.to_h.freeze
61
+
57
62
  def self.config_to_env_hash config
58
63
  CONFIG_MAP.each_with_object({}){|(key, evname), env|
59
64
  env[evname] = config[key].to_s if config[key]
60
65
  }
61
66
  end
62
67
 
68
+ def self.parse_config_value name, valstr
69
+ return valstr unless valstr.kind_of? String
70
+
71
+ case CONFIG_SET[name][2]
72
+ when :bool
73
+ case valstr
74
+ when '1', 'true', 'TRUE', 'T'
75
+ true
76
+ else
77
+ false
78
+ end
79
+ when :int
80
+ valstr.to_i
81
+ when :loglevel
82
+ if DEBUGGER__::LOG_LEVELS[s = valstr.to_sym]
83
+ s
84
+ else
85
+ raise "Unknown loglevel: #{valstr}"
86
+ end
87
+ when :path # array of String
88
+ valstr.split(/:/).map{|e|
89
+ if /\A\/(.+)\/\z/ =~ e
90
+ Regexp.compile $1
91
+ else
92
+ e
93
+ end
94
+ }
95
+ else
96
+ valstr
97
+ end
98
+ end
99
+
63
100
  def self.parse_argv argv
64
101
  config = {
65
102
  mode: :start,
66
103
  }
67
104
  CONFIG_MAP.each{|key, evname|
68
105
  if val = ENV[evname]
69
- if /_USE_/ =~ evname || /NONSTOP/ =~ evname
70
- case val
71
- when '1', 'true', 'TRUE', 'T'
72
- config[key] = true
73
- else
74
- config[key] = false
75
- end
76
- else
77
- config[key] = val
78
- end
106
+ config[key] = parse_config_value(key, val)
79
107
  end
80
108
  }
81
109
  return config if !argv || argv.empty?
@@ -93,7 +121,7 @@ module DEBUGGER__
93
121
  config[:nonstop] = '1'
94
122
  end
95
123
 
96
- o.on('-e COMMAND', 'Execute debug command at the beginning of the script.') do |cmd|
124
+ o.on('-e DEBUG_COMMAND', 'Execute debug command at the beginning of the script.') do |cmd|
97
125
  config[:commands] ||= ''
98
126
  config[:commands] += cmd + ';;'
99
127
  end
@@ -141,6 +169,9 @@ module DEBUGGER__
141
169
  o.separator ''
142
170
  o.separator " '#{rdbg} target.rb foo bar' starts like 'ruby target.rb foo bar'."
143
171
  o.separator " '#{rdbg} -- -r foo -e bar' starts like 'ruby -r foo -e bar'."
172
+ o.separator " '#{rdbg} -c rake test' starts like 'rake test'."
173
+ o.separator " '#{rdbg} -c -- rake test -t' starts like 'rake test -t'."
174
+ o.separator " '#{rdbg} -c bundle exec rake test' starts like 'bundle exec rake test'."
144
175
  o.separator " '#{rdbg} -O target.rb foo bar' starts and accepts attaching with UNIX domain socket."
145
176
  o.separator " '#{rdbg} -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234."
146
177
  o.separator " '#{rdbg} -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234."
@@ -191,10 +222,22 @@ module DEBUGGER__
191
222
  def self.set_config kw
192
223
  kw.each{|k, v|
193
224
  if CONFIG_MAP[k]
194
- CONFIG[k] = v # TODO: ractor support
225
+ CONFIG[k] = parse_config_value(k, v) # TODO: ractor support
195
226
  else
196
- raise "unknown option: #{k}"
227
+ raise "Unknown configuration: #{k}"
197
228
  end
198
229
  }
199
230
  end
231
+
232
+ def self.append_config key, val
233
+ if CONFIG_SET[key]
234
+ if CONFIG_SET[key][2] == :path
235
+ CONFIG[key] = [*CONFIG[key], *parse_config_value(key, val)];
236
+ else
237
+ raise "not an Array type: #{key}"
238
+ end
239
+ else
240
+ raise "Unknown configuration: #{key}"
241
+ end
242
+ end
200
243
  end
data/lib/debug/console.rb CHANGED
@@ -26,7 +26,11 @@ module DEBUGGER__
26
26
  end
27
27
 
28
28
  def width
29
- IO.console_size[1]
29
+ if (w = IO.console_size[1]) == 0 # for tests PTY
30
+ 80
31
+ else
32
+ w
33
+ end
30
34
  end
31
35
 
32
36
  def quit n
@@ -36,7 +40,7 @@ module DEBUGGER__
36
40
  def ask prompt
37
41
  setup_interrupt do
38
42
  print prompt
39
- (gets || '').strip
43
+ ($stdin.gets || '').strip
40
44
  end
41
45
  end
42
46
 
data/lib/debug/session.rb CHANGED
@@ -101,6 +101,10 @@ module DEBUGGER__
101
101
  @tp_thread_begin.enable
102
102
  end
103
103
 
104
+ def active?
105
+ @ui ? true : false
106
+ end
107
+
104
108
  def reset_ui ui
105
109
  @ui.close
106
110
  @ui = ui
@@ -172,8 +176,11 @@ module DEBUGGER__
172
176
  end
173
177
  end
174
178
  ensure
179
+ @tp_load_script.disable
180
+ @tp_thread_begin.disable
175
181
  @bps.each{|k, bp| bp.disable}
176
182
  @th_clients.each{|th, thc| thc.close}
183
+ @ui = nil
177
184
  end
178
185
 
179
186
  def add_preset_commands name, cmds, kick: true, continue: true
@@ -337,10 +344,14 @@ module DEBUGGER__
337
344
  # * Set breakpoint on the method `<class>#<name>`.
338
345
  # * `b[reak] <expr>.<name>`
339
346
  # * Set breakpoint on the method `<expr>.<name>`.
340
- # * `b[reak] ... if <expr>`
347
+ # * `b[reak] ... if: <expr>`
341
348
  # * break if `<expr>` is true at specified location.
342
- # * `b[reak] if <expr>`
343
- # * break if `<expr>` is true at any lines.
349
+ # * `b[reak] ... pre: <command>`
350
+ # * break and run `<command>` before stopping.
351
+ # * `b[reak] ... do: <command>`
352
+ # * break and run `<command>`, and continue.
353
+ # * `b[reak] if: <expr>`
354
+ # * break if: `<expr>` is true at any lines.
344
355
  # * Note that this feature is super slow.
345
356
  when 'b', 'break'
346
357
  if arg == nil
@@ -428,8 +439,25 @@ module DEBUGGER__
428
439
 
429
440
  # * `bt` or `backtrace`
430
441
  # * Show backtrace (frame) information.
442
+ # * `bt <num>` or `backtrace <num>`
443
+ # * Only shows first `<num>` frames.
444
+ # * `bt /regexp/` or `backtrace /regexp/`
445
+ # * Only shows frames with method name or location info that matches `/regexp/`.
446
+ # * `bt <num> /regexp/` or `backtrace <num> /regexp/`
447
+ # * Only shows first `<num>` frames with method name or location info that matches `/regexp/`.
431
448
  when 'bt', 'backtrace'
432
- @tc << [:show, :backtrace]
449
+ case arg
450
+ when /\A(\d+)\z/
451
+ @tc << [:show, :backtrace, arg.to_i, nil]
452
+ when /\A\/(.*)\/\z/
453
+ pattern = $1
454
+ @tc << [:show, :backtrace, nil, Regexp.compile(pattern)]
455
+ when /\A(\d+)\s+\/(.*)\/\z/
456
+ max, pattern = $1, $2
457
+ @tc << [:show, :backtrace, max.to_i, Regexp.compile(pattern)]
458
+ else
459
+ @tc << [:show, :backtrace, nil, nil]
460
+ end
433
461
 
434
462
  # * `l[ist]`
435
463
  # * Show current frame's source code.
@@ -609,6 +637,21 @@ module DEBUGGER__
609
637
  end
610
638
  return :retry
611
639
 
640
+ ### Configuration
641
+ # * `config`
642
+ # * Show all configuration with description.
643
+ # * `config <name>`
644
+ # * Show current configuration of <name>.
645
+ # * `config set <name> <val>` or `config <name> = <val>`
646
+ # * Set <name> to <val>.
647
+ # * `config append <name> <val>` or `config <name> << <val>`
648
+ # * Append `<val>` to `<name>` if it is an array.
649
+ # * `config unset <name>`
650
+ # * Set <name> to default.
651
+ when 'config'
652
+ config_command arg
653
+ return :retry
654
+
612
655
  ### Help
613
656
 
614
657
  # * `h[elp]`
@@ -640,6 +683,73 @@ module DEBUGGER__
640
683
  return :retry
641
684
  end
642
685
 
686
+ def config_show key
687
+ key = key.to_sym
688
+ if CONFIG_SET[key]
689
+ v = CONFIG[key]
690
+ kv = "#{key} = #{v.nil? ? '(default)' : v.inspect}"
691
+ desc = CONFIG_SET[key][1]
692
+ line = "%-30s \# %s" % [kv, desc]
693
+ if line.size > SESSION.width
694
+ @ui.puts "\# #{desc}\n#{kv}"
695
+ else
696
+ @ui.puts line
697
+ end
698
+ else
699
+ @ui.puts "Unknown configuration: #{key}. 'config' shows all configurations."
700
+ end
701
+ end
702
+
703
+ def config_set key, val, append: false
704
+ if CONFIG_SET[key = key.to_sym]
705
+ begin
706
+ if append
707
+ DEBUGGER__.append_config(key, val)
708
+ else
709
+ DEBUGGER__.set_config({key => val})
710
+ end
711
+ rescue => e
712
+ @ui.puts e.message
713
+ end
714
+ end
715
+
716
+ config_show key
717
+ end
718
+
719
+ def config_command arg
720
+ case arg
721
+ when nil
722
+ CONFIG_SET.each do |k, _|
723
+ config_show k
724
+ end
725
+
726
+ when /\Aunset\s+(.+)\z/
727
+ if CONFIG_SET[key = $1.to_sym]
728
+ DEBUGGER__.set_config({key => nil})
729
+ end
730
+ config_show key
731
+
732
+ when /\A(\w+)\s*=\s*(.+)\z/
733
+ config_set $1, $2
734
+
735
+ when /\A\s*set\s+(\w+)\s+(.+)\z/
736
+ config_set $1, $2
737
+
738
+ when /\A(\w+)\s*<<\s*(.+)\z/
739
+ config_set $1, $2, append: true
740
+
741
+ when /\A\s*append\s+(\w+)\s+(.+)\z/
742
+ config_set $1, $2
743
+
744
+ when /\A(\w+)\z/
745
+ config_show $1
746
+
747
+ else
748
+ @ui.puts "Can not parse parameters: #{arg}"
749
+ end
750
+ end
751
+
752
+
643
753
  def cancel_auto_continue
644
754
  if @preset_command&.auto_continue
645
755
  @preset_command.auto_continue = false
@@ -762,29 +872,37 @@ module DEBUGGER__
762
872
  end
763
873
  end
764
874
 
765
- def repl_add_breakpoint arg
766
- arg.strip!
875
+ BREAK_KEYWORDS = %w(if: do: pre:).freeze
767
876
 
768
- case arg
769
- when /\Aif\s+(.+)\z/
770
- cond = $1
771
- when /(.+?)\s+if\s+(.+)\z/
772
- sig = $1
773
- cond = $2
774
- else
775
- sig = arg
776
- end
877
+ def parse_break arg
878
+ mode = :sig
879
+ expr = Hash.new{|h, k| h[k] = []}
880
+ arg.split(' ').each{|w|
881
+ if BREAK_KEYWORDS.any?{|pat| w == pat}
882
+ mode = w[0..-2].to_sym
883
+ else
884
+ expr[mode] << w
885
+ end
886
+ }
887
+ expr.default_proc = nil
888
+ expr.transform_values{|v| v.join(' ')}
889
+ end
890
+
891
+ def repl_add_breakpoint arg
892
+ expr = parse_break arg.strip
893
+ cond = expr[:if]
894
+ cmd = ['break', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
777
895
 
778
- case sig
896
+ case expr[:sig]
779
897
  when /\A(\d+)\z/
780
- add_line_breakpoint @tc.location.path, $1.to_i, cond: cond
898
+ add_line_breakpoint @tc.location.path, $1.to_i, cond: expr[:if], command: cmd
781
899
  when /\A(.+)[:\s+](\d+)\z/
782
- add_line_breakpoint $1, $2.to_i, cond: cond
900
+ add_line_breakpoint $1, $2.to_i, cond: expr[:if], command: cmd
783
901
  when /\A(.+)([\.\#])(.+)\z/
784
- @tc << [:breakpoint, :method, $1, $2, $3, cond]
902
+ @tc << [:breakpoint, :method, $1, $2, $3, expr[:if], cmd]
785
903
  return :noretry
786
904
  when nil
787
- add_check_breakpoint cond
905
+ add_check_breakpoint expr[:if]
788
906
  else
789
907
  @ui.puts "Unknown breakpoint format: #{arg}"
790
908
  @ui.puts
@@ -908,6 +1026,7 @@ module DEBUGGER__
908
1026
  ## event
909
1027
 
910
1028
  def on_load iseq, src
1029
+ DEBUGGER__.info "Load #{iseq.absolute_path || iseq.path}"
911
1030
  @sr.add iseq, src
912
1031
 
913
1032
  pending_line_breakpoints do |bp|
@@ -920,6 +1039,9 @@ module DEBUGGER__
920
1039
  # breakpoint management
921
1040
 
922
1041
  def add_breakpoint bp
1042
+ # don't repeat commands that add breakpoints
1043
+ @repl_prev_line = nil
1044
+
923
1045
  if @bps.has_key? bp.key
924
1046
  unless bp.duplicable?
925
1047
  @ui.puts "duplicated breakpoint: #{bp}"
@@ -928,9 +1050,6 @@ module DEBUGGER__
928
1050
  else
929
1051
  @bps[bp.key] = bp
930
1052
  end
931
-
932
- # don't repeat commands that add breakpoints
933
- @repl_prev_line = nil
934
1053
  end
935
1054
 
936
1055
  def rehash_bps
@@ -1001,7 +1120,7 @@ module DEBUGGER__
1001
1120
  when MethodBreakpoint
1002
1121
  if bp.method.nil?
1003
1122
  if bp.sig_method_name == mid.to_s
1004
- bp.try_enable(quiet: true)
1123
+ bp.try_enable(added: true)
1005
1124
  end
1006
1125
  end
1007
1126
 
@@ -1139,20 +1258,18 @@ module DEBUGGER__
1139
1258
  # ::DEBUGGER__.add_catch_breakpoint 'RuntimeError'
1140
1259
 
1141
1260
  Binding.module_eval do
1142
- def bp command: nil, nonstop: nil
1143
- if command
1144
- cmds = command.split(";;")
1145
- # nonstop
1146
- # nil, true -> auto_continue
1147
- # false -> stop
1148
- SESSION.add_preset_commands 'binding.bp(command:)', cmds,
1149
- kick: false,
1150
- continue: nonstop == false ? false : true
1261
+ def break pre: nil, do: nil
1262
+ return unless SESSION.active?
1263
+
1264
+ if pre || (do_expr = binding.local_variable_get(:do))
1265
+ cmds = ['binding.break', pre, do_expr]
1151
1266
  end
1152
1267
 
1153
- ::DEBUGGER__.add_line_breakpoint __FILE__, __LINE__ + 1, oneshot: true
1268
+ ::DEBUGGER__.add_line_breakpoint __FILE__, __LINE__ + 1, oneshot: true, command: cmds
1154
1269
  true
1155
1270
  end
1271
+ alias b break
1272
+ # alias bp break
1156
1273
  end
1157
1274
 
1158
1275
  load_rc
@@ -1262,12 +1379,33 @@ module DEBUGGER__
1262
1379
  end
1263
1380
  end
1264
1381
 
1265
- def self.warn msg, level = :warn
1266
- case level
1267
- when :warn
1268
- STDERR.puts "DEBUGGER: #{msg}" unless CONFIG[:quiet]
1269
- when :error
1270
- STDERR.puts "DEBUGGER: #{msg}"
1382
+ LOG_LEVELS = {
1383
+ UNKNOWN: 0,
1384
+ FATAL: 1,
1385
+ ERROR: 2,
1386
+ WARN: 3,
1387
+ INFO: 4,
1388
+ }.freeze
1389
+
1390
+ def self.warn msg
1391
+ log :WARN, msg
1392
+ end
1393
+
1394
+ def self.info msg
1395
+ log :INFO, msg
1396
+ end
1397
+
1398
+ def self.log level, msg
1399
+ lv = LOG_LEVELS[level]
1400
+ config_lv = LOG_LEVELS[CONFIG[:log_level] || :WARN]
1401
+
1402
+ if lv <= config_lv
1403
+ if level == :WARN
1404
+ # :WARN on debugger is general information
1405
+ STDERR.puts "DEBUGGER: #{msg}"
1406
+ else
1407
+ STDERR.puts "DEBUGGER (#{level}): #{msg}"
1408
+ end
1271
1409
  end
1272
1410
  end
1273
1411
  end
@@ -69,11 +69,11 @@ module DEBUGGER__
69
69
  @q_cmd = q_cmd
70
70
  @step_tp = nil
71
71
  @output = []
72
- @src_lines_on_stop = (::DEBUGGER__::CONFIG[:show_src_lines] || 10).to_i
73
- @show_frames_on_stop = (::DEBUGGER__::CONFIG[:show_frames] || 2).to_i
74
72
  @frame_formatter = method(:default_frame_formatter)
75
73
  @var_map = {} # { thread_local_var_id => obj } for DAP
76
74
  set_mode nil
75
+
76
+ ::DEBUGGER__.info("Thread \##{@id} is created.")
77
77
  end
78
78
 
79
79
  def name
@@ -167,8 +167,8 @@ module DEBUGGER__
167
167
  end
168
168
 
169
169
  if event != :pause
170
- show_src max_lines: @src_lines_on_stop
171
- show_frames @show_frames_on_stop
170
+ show_src max_lines: (::DEBUGGER__::CONFIG[:show_src_lines] || 10)
171
+ show_frames ::DEBUGGER__::CONFIG[:show_frames] || 2
172
172
 
173
173
  if bp
174
174
  event! :suspend, :breakpoint, bp.key
@@ -304,20 +304,39 @@ module DEBUGGER__
304
304
  end
305
305
  end
306
306
 
307
+ def puts_variable_info label, obj
308
+ info = "#{colorize_cyan(label)} => #{colored_inspect(obj)}".lines
309
+ w = SESSION.width
310
+ max_inspect_lines = CONFIG[:show_inspect_lines] || 10
311
+
312
+ if (max_inspect_lines > 0 && (info.size > max_inspect_lines)) || info.any?{|l| l.size > w}
313
+ info = "#{colorize_cyan(label)} => #{colored_inspect(obj, no_color: true)}".lines
314
+ if max_inspect_lines > 0 && info.size > max_inspect_lines
315
+ info = info.first(max_inspect_lines - 2) +
316
+ ["...(#{info.size - (max_inspect_lines - 1)} lines)\n" + info.last]
317
+ end
318
+ info.map!{|l|
319
+ l.length > w ? l[0..(w-4)] + '...' : l
320
+ }
321
+ end
322
+
323
+ puts info
324
+ end
325
+
307
326
  def show_locals
308
327
  if s = current_frame&.self
309
- puts " #{colorize_cyan("%self")} => #{colored_inspect(s)}"
328
+ puts_variable_info '%self', s
310
329
  end
311
330
  if current_frame&.has_return_value
312
- puts " #{colorize_cyan("%return")} => #{colored_inspect(current_frame.return_value)}"
331
+ puts_variable_info '%return', current_frame.return_value
313
332
  end
314
333
  if current_frame&.has_raised_exception
315
- puts " #{colorize_cyan("%raised")} => #{colored_inspect(current_frame.raised_exception)}"
334
+ puts_variable_info "%raised", current_frame.raised_exception
316
335
  end
317
336
  if b = current_frame&.binding
318
337
  b.local_variables.each{|loc|
319
338
  value = b.local_variable_get(loc)
320
- puts " #{colorize_cyan(loc)} => #{colored_inspect(value)}"
339
+ puts_variable_info loc, value
321
340
  }
322
341
  end
323
342
  end
@@ -326,11 +345,15 @@ module DEBUGGER__
326
345
  if s = current_frame&.self
327
346
  s.instance_variables.each{|iv|
328
347
  value = s.instance_variable_get(iv)
329
- puts " #{colorize_cyan(iv)} => #{colored_inspect(value)}"
348
+ puts_variable_info iv, value
330
349
  }
331
350
  end
332
351
  end
333
352
 
353
+ def instance_eval_for_cmethod frame_self, src
354
+ frame_self.instance_eval(src)
355
+ end
356
+
334
357
  def frame_eval src, re_raise: false
335
358
  begin
336
359
  @success_last_eval = false
@@ -341,7 +364,7 @@ module DEBUGGER__
341
364
  b.eval(src, "(rdbg)/#{f}")
342
365
  else
343
366
  frame_self = current_frame.self
344
- frame_self.instance_eval(src)
367
+ instance_eval_for_cmethod(frame_self, src)
345
368
  end
346
369
  @success_last_eval = true
347
370
  result
@@ -359,21 +382,35 @@ module DEBUGGER__
359
382
  end
360
383
  end
361
384
 
362
- def frame_str(i)
385
+ def frame_str(i, frame: @target_frames[i])
363
386
  cur_str = (@current_frame_index == i ? '=>' : ' ')
364
387
  prefix = "#{cur_str}##{i}"
365
- frame = @target_frames[i]
366
388
  frame_string = @frame_formatter.call(frame)
367
389
  "#{prefix}\t#{frame_string}"
368
390
  end
369
391
 
370
- def show_frames max = (@target_frames || []).size
371
- if max > 0 && @target_frames
372
- size = @target_frames.size
373
- max += 1 if size == max + 1
392
+ def show_frames max = nil, pattern = nil
393
+ if @target_frames && (max ||= @target_frames.size) > 0
394
+ frames = []
395
+ @target_frames.each_with_index{|f, i|
396
+ next if pattern && !(f.name.match?(pattern) || f.location_str.match?(pattern))
397
+ next if CONFIG[:skip_path] && CONFIG[:skip_path].any?{|pat|
398
+ case pat
399
+ when String
400
+ f.location_str.start_with?(pat)
401
+ when Regexp
402
+ f.location_str.match?(pat)
403
+ end
404
+ }
405
+
406
+ frames << [i, f]
407
+ }
408
+
409
+ size = frames.size
374
410
  max.times{|i|
375
- break if i >= size
376
- puts frame_str(i)
411
+ break unless frames[i]
412
+ index, frame = frames[i]
413
+ puts frame_str(index, frame: frame)
377
414
  }
378
415
  puts " # and #{size - max} frames (use `bt' command for all frames)" if max < size
379
416
  end
@@ -404,8 +441,8 @@ module DEBUGGER__
404
441
  def make_breakpoint args
405
442
  case args.first
406
443
  when :method
407
- klass_name, op, method_name, cond = args[1..]
408
- bp = MethodBreakpoint.new(current_frame.binding, klass_name, op, method_name, cond)
444
+ klass_name, op, method_name, cond, cmd = args[1..]
445
+ bp = MethodBreakpoint.new(current_frame.binding, klass_name, op, method_name, cond, command: cmd)
409
446
  begin
410
447
  bp.enable
411
448
  rescue Exception => e
@@ -493,8 +530,7 @@ module DEBUGGER__
493
530
  when :pp
494
531
  result = frame_eval(eval_src)
495
532
  puts "=> "
496
- PP.pp(result, out = ''.dup, SESSION.width)
497
- puts out
533
+ puts color_pp(result, SESSION.width)
498
534
  when :call
499
535
  result = frame_eval(eval_src)
500
536
  when :display, :try_display
@@ -549,7 +585,8 @@ module DEBUGGER__
549
585
 
550
586
  case type
551
587
  when :backtrace
552
- show_frames
588
+ max_lines, pattern = *args
589
+ show_frames max_lines, pattern
553
590
 
554
591
  when :list
555
592
  show_src(update_line: true, **(args.first || {}))
@@ -603,7 +640,7 @@ module DEBUGGER__
603
640
  rescue SystemExit
604
641
  raise
605
642
  rescue Exception => e
606
- pp [__FILE__, __LINE__, e, e.backtrace]
643
+ pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
607
644
  raise
608
645
  ensure
609
646
  set_mode nil
data/lib/debug/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DEBUGGER__
4
- VERSION = "1.0.0.beta6"
4
+ VERSION = "1.0.0.beta7"
5
5
  end
data/misc/README.md.erb CHANGED
@@ -83,6 +83,7 @@ require 'debug/run' # start the debug console
83
83
  # ... rest of program ...
84
84
  ```
85
85
 
86
+
86
87
  ```
87
88
  $ ruby target.rb
88
89
  ```
@@ -90,6 +91,24 @@ $ ruby target.rb
90
91
  When you run the program with the debug console, you will see the debug console prompt `(rdbg)`.
91
92
  The debuggee program (`target.rb`) is suspended at the beginning of `target.rb`.
92
93
 
94
+
95
+ Alternatively, start the debugger at a specific location in your program using `binding.break` (`binding.b` for short).
96
+
97
+ ```ruby
98
+ # target.rb
99
+ require 'debug' # start the debugger
100
+
101
+ # ... program ...
102
+
103
+ binding.break # setup a breakpoint at this line
104
+
105
+ # ... rest of program ...
106
+ ```
107
+
108
+ ```
109
+ $ ruby target.rb
110
+ ```
111
+
93
112
  You can type any debugger's command described bellow. "c" or "continue" resume the debuggee program.
94
113
  You can suspend the debuggee program and show the debug console with `Ctrl-C`.
95
114
 
@@ -310,20 +329,19 @@ If there are `~/.rdbgrc`, the file is loaded as initial scripts which contains d
310
329
 
311
330
  If there are `~/.rdbgrc.rb` is available, it is loaded as a ruby script at same timing.
312
331
 
313
- ### Environment variables
332
+ ### Configurations
314
333
 
315
- You can control debuggee's behavior with environment variables:
334
+ You can configure debugger's setting with environment variables and `config` command.
335
+ You can write any configuration into `~/.rdbgrc` like:
316
336
 
317
- * `RUBY_DEBUG_NONSTOP`: 1 for nonstop at the beginning of program.
318
- * `RUBY_DEBUG_INIT_SCRIPT`: Initial script path loaded at the first stop.
319
- * `RUBY_DEBUG_COMMANDS`: Debug commands invoked at the first stop. Commands should be separated by ';;'.
320
- * `RUBY_DEBUG_SHOW_SRC_LINES`: Show n lines source code on breakpoint (default: 10 lines).
321
- * `RUBY_DEBUG_SHOW_FRAMES`: Show n frames on breakpoint (default: 2 frames).
322
- * Remote debugging
323
- * `RUBY_DEBUG_PORT`: TCP/IP remote debugging: port to open.
324
- * `RUBY_DEBUG_HOST`: TCP/IP remote debugging: host (localhost if not given) to open.
325
- * `RUBY_DEBUG_SOCK_PATH`: UNIX Domain Socket remote debugging: socket path to open.
326
- * `RUBY_DEBUG_SOCK_DIR`: UNIX Domain Socket remote debugging: socket directory to open.
337
+ ```
338
+ config set log_level INFO
339
+ config set no_color true
340
+ ```
341
+ <% cat = nil; DEBUGGER__::CONFIG_SET.each do |key, (env, desc)| %>
342
+ <% /\A(\w+): (.+)/ =~ desc; if cat != $1; cat = 1 %>
343
+ * <%= $1 %>
344
+ <% cat = $1; end %> * `<%= env %>` (`<%= key %>`): <%= $2 %><% end %>
327
345
 
328
346
  ## Debug command on the debug console
329
347
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: debug
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta6
4
+ version: 1.0.0.beta7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Sasada
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-07 00:00:00.000000000 Z
11
+ date: 2021-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: irb