debug 1.0.0.beta6 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/debug/color.rb CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  begin
4
4
  require 'irb/color'
5
+
6
+ module IRB
7
+ module Color
8
+ DIM = 2 unless defined? DIM
9
+ end
10
+ end
11
+
5
12
  require "irb/color_printer"
6
13
  rescue LoadError
7
14
  warn "DEBUGGER: can not load newer irb for coloring. Write 'gem \"debug\" in your Gemfile."
@@ -24,18 +31,22 @@ module DEBUGGER__
24
31
  end
25
32
 
26
33
  if defined? IRB::ColorPrinter.pp
27
- def color_pp obj
28
- IRB::ColorPrinter.pp(obj, "".dup)
34
+ def color_pp obj, width
35
+ if !CONFIG[:no_color]
36
+ IRB::ColorPrinter.pp(obj, "".dup, width)
37
+ else
38
+ obj.pretty_inspect
39
+ end
29
40
  end
30
41
  else
31
- def color_pp obj
42
+ def color_pp obj, width
32
43
  obj.pretty_inspect
33
44
  end
34
45
  end
35
46
 
36
- def colored_inspect obj
37
- if !CONFIG[:no_color]
38
- color_pp obj
47
+ def colored_inspect obj, width: SESSION.width, no_color: false
48
+ if !no_color
49
+ color_pp obj, width
39
50
  else
40
51
  obj.pretty_inspect
41
52
  end
@@ -68,5 +79,13 @@ module DEBUGGER__
68
79
  def colorize_blue(str)
69
80
  colorize(str, [:BLUE, :BOLD])
70
81
  end
82
+
83
+ def colorize_magenta(str)
84
+ colorize(str, [:MAGENTA, :BOLD])
85
+ end
86
+
87
+ def colorize_dim(str)
88
+ colorize(str, [:DIM])
89
+ end
71
90
  end
72
91
  end
data/lib/debug/config.rb CHANGED
@@ -1,200 +1,422 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DEBUGGER__
4
- def self.unix_domain_socket_dir
5
- case
6
- when path = ::DEBUGGER__::CONFIG[:sock_dir]
7
- when path = ENV['XDG_RUNTIME_DIR']
8
- when home = ENV['HOME']
9
- path = File.join(home, '.ruby-debug-sock')
4
+ CONFIG_SET = {
5
+ # UI setting
6
+ log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger (default: WARN)", :loglevel],
7
+ show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint (default: 10 lines)", :int],
8
+ show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint (default: 2 frames)", :int],
9
+ use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shoten PATH (like $(Gem)/foo.rb)", :bool],
10
+ no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize (default: false)", :bool],
11
+ no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT (default: false)", :bool],
12
+ no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library (default: false)", :bool],
10
13
 
11
- case
12
- when !File.exist?(path)
13
- Dir.mkdir(path, 0700)
14
- when !File.directory?(path)
15
- raise "#{path} is not a directory."
16
- end
17
- else
18
- raise 'specify RUBY_DEBUG_SOCK_DIR environment variable for UNIX domain socket directory.'
14
+ # control setting
15
+ skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths (default: [])", :path],
16
+ skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines (default: false)", :bool],
17
+ keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it (default: false)", :bool],
18
+ postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug (default: false)", :bool],
19
+ parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "CONTROL: Keep debugging parent process on fork (default: false)", :bool],
20
+ sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal (default: disabled)"],
21
+
22
+ # boot setting
23
+ nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool],
24
+ init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
25
+ commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. commands should be separated by ';;'"],
26
+ no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool],
27
+
28
+ # remote setting
29
+ port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
30
+ host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host (localhost if not given)"],
31
+ sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
32
+ sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
33
+ cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
34
+ }.freeze
35
+
36
+ CONFIG_MAP = CONFIG_SET.map{|k, (ev, desc)| [k, ev]}.to_h.freeze
37
+
38
+ class Config
39
+ def self.config
40
+ @config
19
41
  end
20
42
 
21
- path
22
- end
43
+ def initialize argv
44
+ if self.class.instance_variable_defined? :@config
45
+ raise 'Can not make multiple configurations in one process'
46
+ end
23
47
 
24
- def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
25
- user = ENV['USER'] || 'ruby-debug'
26
- File.join(base_dir, "ruby-debug-#{user}")
27
- end
48
+ update self.class.parse_argv(argv)
49
+ end
28
50
 
29
- def self.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir)
30
- create_unix_domain_socket_name_prefix(base_dir) + "-#{Process.pid}"
31
- end
51
+ def [](key)
52
+ config[key]
53
+ end
32
54
 
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)
55
+ def []=(key, val)
56
+ set_config(key => val)
57
+ end
39
58
 
40
- # 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
59
+ def set_config(**kw)
60
+ conf = config.dup
61
+ kw.each{|k, v|
62
+ if CONFIG_MAP[k]
63
+ conf[k] = parse_config_value(k, v) # TODO: ractor support
64
+ else
65
+ raise "Unknown configuration: #{k}"
66
+ end
67
+ }
48
68
 
49
- # 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
55
- }.freeze
69
+ update conf
70
+ end
56
71
 
57
- def self.config_to_env_hash config
58
- CONFIG_MAP.each_with_object({}){|(key, evname), env|
59
- env[evname] = config[key].to_s if config[key]
60
- }
61
- end
72
+ def append_config key, val
73
+ conf = self.config.dup
62
74
 
63
- def self.parse_argv argv
64
- config = {
65
- mode: :start,
66
- }
67
- CONFIG_MAP.each{|key, evname|
68
- 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
75
+ if CONFIG_SET[key]
76
+ if CONFIG_SET[key][2] == :path
77
+ conf[key] = [*conf[key], *parse_config_value(key, val)];
76
78
  else
77
- config[key] = val
79
+ raise "not an Array type: #{key}"
78
80
  end
81
+ else
82
+ raise "Unknown configuration: #{key}"
79
83
  end
80
- }
81
- return config if !argv || argv.empty?
82
84
 
83
- require 'optparse'
84
- require_relative 'version'
85
+ update conf
86
+ end
85
87
 
86
- opt = OptionParser.new do |o|
87
- o.banner = "#{$0} [options] -- [debuggee options]"
88
- o.separator ''
89
- o.version = ::DEBUGGER__::VERSION
88
+ def update conf
89
+ old_conf = self.class.instance_variable_get(:@config) || {}
90
90
 
91
- o.separator 'Debug console mode:'
92
- o.on('-n', '--nonstop', 'Do not stop at the beginning of the script.') do
93
- config[:nonstop] = '1'
94
- end
91
+ # TODO: Use Ractor.make_shareable(conf)
92
+ self.class.instance_variable_set(:@config, conf.freeze)
95
93
 
96
- o.on('-e COMMAND', 'Execute debug command at the beginning of the script.') do |cmd|
97
- config[:commands] ||= ''
98
- config[:commands] += cmd + ';;'
94
+ # Post process
95
+ if_updated old_conf, conf, :keep_alloc_site do |_, new|
96
+ if new
97
+ require 'objspace'
98
+ ObjectSpace.trace_object_allocations_start
99
+ else
100
+ ObjectSpace.trace_object_allocations_stop
101
+ end
99
102
  end
100
103
 
101
- o.on('-x FILE', '--init-script=FILE', 'Execute debug command in the FILE.') do |file|
102
- config[:init_script] = file
103
- end
104
- o.on('--no-rc', 'Ignore ~/.rdbgrc') do
105
- config[:no_rc] = true
106
- end
107
- o.on('--no-color', 'Disable colorize') do
108
- config[:no_color] = true
104
+ if_updated old_conf, conf, :postmortem do |_, new_p|
105
+ SESSION.postmortem = new_p
109
106
  end
110
107
 
111
- o.on('-c', '--command', 'Enable command mode.',
112
- 'The first argument should be a command name in $PATH.',
113
- 'Example: \'rdbg -c bundle exec rake test\'') do
114
- config[:command] = true
108
+ if_updated old_conf, conf, :sigdump_sig do |old_sig, new_sig|
109
+ setup_sigdump old_sig, new_sig
115
110
  end
111
+ end
116
112
 
117
- o.separator ''
113
+ private def if_updated old_conf, new_conf, key
114
+ old, new = old_conf[key], new_conf[key]
115
+ yield old, new if old != new
116
+ end
118
117
 
119
- o.on('-O', '--open', 'Start remote debugging with opening the network port.',
120
- 'If TCP/IP options are not given,',
121
- 'a UNIX domain socket will be used.') do
122
- config[:remote] = true
123
- end
124
- o.on('--sock-path=SOCK_PATH', 'UNIX Doman socket path') do |path|
125
- config[:sock_path] = path
126
- end
127
- o.on('--port=PORT', 'Listening TCP/IP port') do |port|
128
- config[:port] = port
129
- end
130
- o.on('--host=HOST', 'Listening TCP/IP host') do |host|
131
- config[:host] = host
118
+ private def enable_sigdump sig
119
+ @sigdump_sig_prev = trap(sig) do
120
+ str = []
121
+ str << "Simple sigdump on #{Process.pid}"
122
+ Thread.list.each{|th|
123
+ str << "Thread: #{th}"
124
+ th.backtrace.each{|loc|
125
+ str << " #{loc}"
126
+ }
127
+ str << ''
128
+ }
129
+
130
+ STDERR.puts str
132
131
  end
133
- o.on('--cookie=COOKIE', 'Set a cookie for connection') do |c|
134
- config[:cookie] = c
132
+ end
133
+
134
+ private def disable_sigdump old_sig
135
+ trap(old_sig, @sigdump_sig_prev)
136
+ @sigdump_sig_prev = nil
137
+ end
138
+
139
+ # emergency simple sigdump.
140
+ # Use `sigdump` gem for more rich features.
141
+ private def setup_sigdump old_sig = nil, sig = CONFIG[:sigdump_sig]
142
+ if !old_sig && sig
143
+ enable_sigdump sig
144
+ elsif old_sig && !sig
145
+ disable_sigdump old_sig
146
+ elsif old_sig && sig
147
+ disable_sigdump old_sig
148
+ enable_sigdump sig
135
149
  end
150
+ end
151
+
152
+ private def config
153
+ self.class.config
154
+ end
155
+
156
+ private def parse_config_value name, valstr
157
+ self.class.parse_config_value name, valstr
158
+ end
136
159
 
137
- rdbg = 'rdbg'
138
-
139
- o.separator ''
140
- o.separator ' Debug console mode runs Ruby program with the debug console.'
141
- o.separator ''
142
- o.separator " '#{rdbg} target.rb foo bar' starts like 'ruby target.rb foo bar'."
143
- o.separator " '#{rdbg} -- -r foo -e bar' starts like 'ruby -r foo -e bar'."
144
- o.separator " '#{rdbg} -O target.rb foo bar' starts and accepts attaching with UNIX domain socket."
145
- o.separator " '#{rdbg} -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234."
146
- o.separator " '#{rdbg} -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234."
147
-
148
- o.separator ''
149
- o.separator 'Attach mode:'
150
- o.on('-A', '--attach', 'Attach to debuggee process.') do
151
- config[:mode] = :attach
160
+ def self.parse_config_value name, valstr
161
+ return valstr unless valstr.kind_of? String
162
+
163
+ case CONFIG_SET[name][2]
164
+ when :bool
165
+ case valstr
166
+ when '1', 'true', 'TRUE', 'T'
167
+ true
168
+ else
169
+ false
170
+ end
171
+ when :int
172
+ valstr.to_i
173
+ when :loglevel
174
+ if DEBUGGER__::LOG_LEVELS[s = valstr.to_sym]
175
+ s
176
+ else
177
+ raise "Unknown loglevel: #{valstr}"
178
+ end
179
+ when :path # array of String
180
+ valstr.split(/:/).map{|e|
181
+ if /\A\/(.+)\/\z/ =~ e
182
+ Regexp.compile $1
183
+ else
184
+ e
185
+ end
186
+ }
187
+ else
188
+ valstr
152
189
  end
190
+ end
153
191
 
154
- o.separator ''
155
- o.separator ' Attach mode attaches the remote debug console to the debuggee process.'
156
- o.separator ''
157
- o.separator " '#{rdbg} -A' tries to connect via UNIX domain socket."
158
- o.separator " #{' ' * rdbg.size} If there are multiple processes are waiting for the"
159
- o.separator " #{' ' * rdbg.size} debugger connection, list possible debuggee names."
160
- o.separator " '#{rdbg} -A path' tries to connect via UNIX domain socket with given path name."
161
- o.separator " '#{rdbg} -A port' tries to connect to localhost:port via TCP/IP."
162
- o.separator " '#{rdbg} -A host port' tries to connect to host:port via TCP/IP."
163
-
164
- o.separator ''
165
- o.separator 'Other options:'
166
-
167
- o.on("-h", "--help", "Print help") do
168
- puts o
169
- exit
192
+ def self.parse_argv argv
193
+ config = {
194
+ mode: :start,
195
+ }
196
+ CONFIG_MAP.each{|key, evname|
197
+ if val = ENV[evname]
198
+ config[key] = parse_config_value(key, val)
199
+ end
200
+ }
201
+ return config if !argv || argv.empty?
202
+
203
+ if argv.kind_of? String
204
+ require 'shellwords'
205
+ argv = Shellwords.split(argv)
170
206
  end
171
207
 
172
- o.on('--util=NAME', 'Utility mode (used by tools)') do |name|
173
- require_relative 'client'
174
- Client.new(name)
175
- exit
208
+ require 'optparse'
209
+ require_relative 'version'
210
+
211
+ opt = OptionParser.new do |o|
212
+ o.banner = "#{$0} [options] -- [debuggee options]"
213
+ o.separator ''
214
+ o.version = ::DEBUGGER__::VERSION
215
+
216
+ o.separator 'Debug console mode:'
217
+ o.on('-n', '--nonstop', 'Do not stop at the beginning of the script.') do
218
+ config[:nonstop] = '1'
219
+ end
220
+
221
+ o.on('-e DEBUG_COMMAND', 'Execute debug command at the beginning of the script.') do |cmd|
222
+ config[:commands] ||= ''
223
+ config[:commands] += cmd + ';;'
224
+ end
225
+
226
+ o.on('-x FILE', '--init-script=FILE', 'Execute debug command in the FILE.') do |file|
227
+ config[:init_script] = file
228
+ end
229
+ o.on('--no-rc', 'Ignore ~/.rdbgrc') do
230
+ config[:no_rc] = true
231
+ end
232
+ o.on('--no-color', 'Disable colorize') do
233
+ config[:no_color] = true
234
+ end
235
+ o.on('--no-sigint-hook', 'Disable to trap SIGINT') do
236
+ config[:no_sigint_hook] = true
237
+ end
238
+
239
+ o.on('-c', '--command', 'Enable command mode.',
240
+ 'The first argument should be a command name in $PATH.',
241
+ 'Example: \'rdbg -c bundle exec rake test\'') do
242
+ config[:command] = true
243
+ end
244
+
245
+ o.separator ''
246
+
247
+ o.on('-O', '--open', 'Start remote debugging with opening the network port.',
248
+ 'If TCP/IP options are not given,',
249
+ 'a UNIX domain socket will be used.') do
250
+ config[:remote] = true
251
+ end
252
+ o.on('--sock-path=SOCK_PATH', 'UNIX Domain socket path') do |path|
253
+ config[:sock_path] = path
254
+ end
255
+ o.on('--port=PORT', 'Listening TCP/IP port') do |port|
256
+ config[:port] = port
257
+ end
258
+ o.on('--host=HOST', 'Listening TCP/IP host') do |host|
259
+ config[:host] = host
260
+ end
261
+ o.on('--cookie=COOKIE', 'Set a cookie for connection') do |c|
262
+ config[:cookie] = c
263
+ end
264
+
265
+ rdbg = 'rdbg'
266
+
267
+ o.separator ''
268
+ o.separator ' Debug console mode runs Ruby program with the debug console.'
269
+ o.separator ''
270
+ o.separator " '#{rdbg} target.rb foo bar' starts like 'ruby target.rb foo bar'."
271
+ o.separator " '#{rdbg} -- -r foo -e bar' starts like 'ruby -r foo -e bar'."
272
+ o.separator " '#{rdbg} -c rake test' starts like 'rake test'."
273
+ o.separator " '#{rdbg} -c -- rake test -t' starts like 'rake test -t'."
274
+ o.separator " '#{rdbg} -c bundle exec rake test' starts like 'bundle exec rake test'."
275
+ o.separator " '#{rdbg} -O target.rb foo bar' starts and accepts attaching with UNIX domain socket."
276
+ o.separator " '#{rdbg} -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234."
277
+ o.separator " '#{rdbg} -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234."
278
+
279
+ o.separator ''
280
+ o.separator 'Attach mode:'
281
+ o.on('-A', '--attach', 'Attach to debuggee process.') do
282
+ config[:mode] = :attach
283
+ end
284
+
285
+ o.separator ''
286
+ o.separator ' Attach mode attaches the remote debug console to the debuggee process.'
287
+ o.separator ''
288
+ o.separator " '#{rdbg} -A' tries to connect via UNIX domain socket."
289
+ o.separator " #{' ' * rdbg.size} If there are multiple processes are waiting for the"
290
+ o.separator " #{' ' * rdbg.size} debugger connection, list possible debuggee names."
291
+ o.separator " '#{rdbg} -A path' tries to connect via UNIX domain socket with given path name."
292
+ o.separator " '#{rdbg} -A port' tries to connect to localhost:port via TCP/IP."
293
+ o.separator " '#{rdbg} -A host port' tries to connect to host:port via TCP/IP."
294
+
295
+ o.separator ''
296
+ o.separator 'Other options:'
297
+
298
+ o.on("-h", "--help", "Print help") do
299
+ puts o
300
+ exit
301
+ end
302
+
303
+ o.on('--util=NAME', 'Utility mode (used by tools)') do |name|
304
+ require_relative 'client'
305
+ Client.new(name)
306
+ exit
307
+ end
308
+
309
+ o.separator ''
310
+ o.separator 'NOTE'
311
+ o.separator ' All messages communicated between a debugger and a debuggee are *NOT* encrypted.'
312
+ o.separator ' Please use the remote debugging feature carefully.'
176
313
  end
177
314
 
178
- o.separator ''
179
- o.separator 'NOTE'
180
- o.separator ' All messages communicated between a debugger and a debuggee are *NOT* encrypted.'
181
- o.separator ' Please use the remote debugging feature carefully.'
315
+ opt.parse!(argv)
316
+
317
+ config
182
318
  end
183
319
 
184
- opt.parse!(argv)
320
+ def self.config_to_env_hash config
321
+ CONFIG_MAP.each_with_object({}){|(key, evname), env|
322
+ unless config[key].nil?
323
+ case CONFIG_SET[key][2]
324
+ when :path
325
+ valstr = config[key].map{|e| e.kind_of?(Regexp) ? e.inspect : e}.join(':')
326
+ else
327
+ valstr = config[key].to_s
328
+ end
329
+ env[evname] = valstr
330
+ end
331
+ }
332
+ end
333
+ end
334
+
335
+ CONFIG = Config.new ENV['RUBY_DEBUG_OPT']
185
336
 
186
- config
337
+ ## Unix domain socket configuration
338
+
339
+ def self.unix_domain_socket_dir
340
+ case
341
+ when path = CONFIG[:sock_dir]
342
+ when path = ENV['XDG_RUNTIME_DIR']
343
+ when home = ENV['HOME']
344
+ path = File.join(home, '.ruby-debug-sock')
345
+
346
+ case
347
+ when !File.exist?(path)
348
+ Dir.mkdir(path, 0700)
349
+ when !File.directory?(path)
350
+ raise "#{path} is not a directory."
351
+ end
352
+ else
353
+ raise 'specify RUBY_DEBUG_SOCK_DIR environment variable for UNIX domain socket directory.'
354
+ end
355
+
356
+ path
357
+ end
358
+
359
+ def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
360
+ user = ENV['USER'] || 'ruby-debug'
361
+ File.join(base_dir, "ruby-debug-#{user}")
362
+ end
363
+
364
+ def self.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir)
365
+ create_unix_domain_socket_name_prefix(base_dir) + "-#{Process.pid}"
187
366
  end
188
367
 
189
- CONFIG = ::DEBUGGER__.parse_argv(ENV['RUBY_DEBUG_OPT'])
368
+ ## Help
190
369
 
191
- def self.set_config kw
192
- kw.each{|k, v|
193
- if CONFIG_MAP[k]
194
- CONFIG[k] = v # TODO: ractor support
195
- else
196
- raise "unknown option: #{k}"
370
+ def self.parse_help
371
+ helps = Hash.new{|h, k| h[k] = []}
372
+ desc = cat = nil
373
+ cmds = Hash.new
374
+
375
+ File.read(File.join(__dir__, 'session.rb')).each_line do |line|
376
+ case line
377
+ when /\A\s*### (.+)/
378
+ cat = $1
379
+ break if $1 == 'END'
380
+ when /\A when (.+)/
381
+ next unless cat
382
+ next unless desc
383
+ ws = $1.split(/,\s*/).map{|e| e.gsub('\'', '')}
384
+ helps[cat] << [ws, desc]
385
+ desc = nil
386
+ max_w = ws.max_by{|w| w.length}
387
+ ws.each{|w|
388
+ cmds[w] = max_w
389
+ }
390
+ when /\A\s+# (\s*\*.+)/
391
+ if desc
392
+ desc << "\n" + $1
393
+ else
394
+ desc = $1
395
+ end
197
396
  end
397
+ end
398
+ @commands = cmds
399
+ @helps = helps
400
+ end
401
+
402
+ def self.helps
403
+ (defined?(@helps) && @helps) || parse_help
404
+ end
405
+
406
+ def self.commands
407
+ (defined?(@commands) && @commands) || (parse_help; @commands)
408
+ end
409
+
410
+ def self.help
411
+ r = []
412
+ self.helps.each{|cat, cmds|
413
+ r << "### #{cat}"
414
+ r << ''
415
+ cmds.each{|ws, desc|
416
+ r << desc
417
+ }
418
+ r << ''
198
419
  }
420
+ r.join("\n")
199
421
  end
200
422
  end