debug 1.0.0.beta6 → 1.0.0.beta7

Sign up to get free protection for your applications and to get access to all the features.
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