debug 1.10.0 → 1.11.1

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.
data/lib/debug/config.rb CHANGED
@@ -12,50 +12,52 @@ module DEBUGGER__
12
12
 
13
13
  CONFIG_SET = {
14
14
  # UI setting
15
- log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger", :loglevel, "WARN"],
16
- show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint", :int, "10"],
17
- show_evaledsrc: ['RUBY_DEBUG_SHOW_EVALEDSRC', "UI: Show actually evaluated source", :bool, "false"],
18
- show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"],
19
- use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"],
20
- no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"],
21
- no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"],
22
- no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"],
23
- no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"],
24
- no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"],
25
- irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"],
15
+ log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger", :loglevel, "WARN"],
16
+ show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint", :int, "10"],
17
+ show_src_lines_frame:['RUBY_DEBUG_SHOW_SRC_LINES_FRAME', "UI: Show n lines source code on frame operations", :int, "1"],
18
+ show_evaledsrc: ['RUBY_DEBUG_SHOW_EVALEDSRC', "UI: Show actually evaluated source", :bool, "false"],
19
+ show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"],
20
+ use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"],
21
+ no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"],
22
+ no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"],
23
+ no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"],
24
+ no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"],
25
+ no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"],
26
+ no_repeat: ['RUBY_DEBUG_NO_REPEAT', "UI: Do not repeat last line when empty line",:bool, "false"],
27
+ irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"],
26
28
 
27
29
  # control setting
28
- skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path],
29
- skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines", :bool, "false"],
30
- keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"],
31
- postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug", :bool, "false"],
32
- fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)", :forkmode, "both"],
33
- sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal", :bool, "false"],
30
+ skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path],
31
+ skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines", :bool, "false"],
32
+ keep_alloc_site: ['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"],
33
+ postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug", :bool, "false"],
34
+ fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)", :forkmode, "both"],
35
+ sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal", :bool, "false"],
34
36
 
35
37
  # boot setting
36
- nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"],
37
- stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"],
38
- init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
39
- commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"],
40
- no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"],
41
- history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file", :string, "~/.rdbg_history"],
42
- save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"],
38
+ nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"],
39
+ stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"],
40
+ init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
41
+ commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"],
42
+ no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"],
43
+ history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file (default: ${XDG_STATE_HOME-~/.local/state}/rdbg/history)", :string, nil],
44
+ save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"],
43
45
 
44
46
  # remote setting
45
- open: ['RUBY_DEBUG_OPEN', "REMOTE: Open remote port (same as `rdbg --open` option)"],
46
- port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
47
- port_range: ['RUBY_DEBUG_PORT_RANGE', "REMOTE: TCP/IP remote debugging: length of port range"],
48
- host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"],
49
- sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
50
- sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
51
- local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map],
52
- skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'],
53
- cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
54
- session_name: ['RUBY_DEBUG_SESSION_NAME', "REMOTE: Session name for differentiating multiple sessions"],
55
- chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"],
47
+ open: ['RUBY_DEBUG_OPEN', "REMOTE: Open remote port (same as `rdbg --open` option)"],
48
+ port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
49
+ port_range: ['RUBY_DEBUG_PORT_RANGE', "REMOTE: TCP/IP remote debugging: length of port range"],
50
+ host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"],
51
+ sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
52
+ sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
53
+ local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map],
54
+ skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'],
55
+ cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
56
+ session_name: ['RUBY_DEBUG_SESSION_NAME', "REMOTE: Session name for differentiating multiple sessions"],
57
+ chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"],
56
58
 
57
59
  # obsolete
58
- parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork", :bool, "false"],
60
+ parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork", :bool, "false"],
59
61
  }.freeze
60
62
 
61
63
  CONFIG_MAP = CONFIG_SET.map{|k, (ev, _)| [k, ev]}.to_h.freeze
data/lib/debug/console.rb CHANGED
@@ -153,21 +153,29 @@ module DEBUGGER__
153
153
  end
154
154
 
155
155
  def history_file
156
- history_file = CONFIG[:history_file]
157
-
158
- if !history_file.empty?
159
- File.expand_path(history_file)
156
+ case
157
+ when (path = CONFIG[:history_file]) && !path.empty?
158
+ path = File.expand_path(path)
159
+ when (path = File.expand_path("~/.rdbg_history")) && File.exist?(path) # for compatibility
160
+ # path
160
161
  else
161
- history_file
162
+ state_dir = ENV['XDG_STATE_HOME'] || File.join(Dir.home, '.local', 'state')
163
+ path = File.join(File.expand_path(state_dir), 'rdbg', 'history')
162
164
  end
165
+
166
+ require 'fileutils'
167
+ FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(path)
168
+ path
163
169
  end
164
170
 
165
171
  FH = "# Today's OMIKUJI: "
166
172
 
167
173
  def read_history_file
168
- if history && File.exist?(path = history_file)
174
+ if history && File.exist?(path = history_file())
169
175
  f = (['', 'DAI-', 'CHU-', 'SHO-'].map{|e| e+'KICHI'}+['KYO']).sample
170
- ["#{FH}#{f}".dup] + File.readlines(path)
176
+ # Read history file and scrub invalid characters to prevent encoding errors
177
+ lines = File.readlines(path).map(&:scrub)
178
+ ["#{FH}#{f}".dup] + lines
171
179
  else
172
180
  []
173
181
  end
@@ -186,15 +194,17 @@ module DEBUGGER__
186
194
  def deactivate
187
195
  if history && @init_history_lines
188
196
  added_records = history.to_a[@init_history_lines .. -1]
189
- path = history_file
197
+ path = history_file()
190
198
  max = CONFIG[:save_history]
191
199
 
192
200
  if !added_records.empty? && !path.empty?
193
201
  orig_records = read_history_file
194
- open(history_file, 'w'){|f|
202
+ open(history_file(), 'w'){|f|
195
203
  (orig_records + added_records).last(max).each{|line|
196
- if !line.start_with?(FH) && !line.strip.empty?
197
- f.puts line.strip
204
+ # Use scrub to handle encoding issues gracefully
205
+ scrubbed_line = line.scrub.strip
206
+ if !line.start_with?(FH) && !scrubbed_line.empty?
207
+ f.puts scrubbed_line
198
208
  end
199
209
  }
200
210
  }
@@ -204,6 +214,8 @@ module DEBUGGER__
204
214
 
205
215
  def load_history
206
216
  read_history_file.each{|line|
217
+ # Use scrub to handle encoding issues gracefully, then strip
218
+ line.scrub!
207
219
  line.strip!
208
220
  history << line unless line.empty?
209
221
  } if history.empty?
@@ -86,7 +86,9 @@ module DEBUGGER__
86
86
 
87
87
  def block_identifier
88
88
  return unless frame_type == :block
89
- _, level, block_loc = location.label.match(BLOCK_LABL_REGEXP).to_a
89
+ re_match = location.label.match(BLOCK_LABL_REGEXP)
90
+ _, level, block_loc = re_match ? re_match.to_a : [nil, nil, location.label]
91
+
90
92
  [level || "", block_loc]
91
93
  end
92
94
 
@@ -169,7 +171,7 @@ module DEBUGGER__
169
171
 
170
172
  private def get_singleton_class obj
171
173
  obj.singleton_class # TODO: don't use it
172
- rescue TypeError
174
+ rescue Exception
173
175
  nil
174
176
  end
175
177
 
data/lib/debug/server.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'socket'
4
+ require 'fileutils'
4
5
  require_relative 'config'
5
6
  require_relative 'version'
6
7
 
@@ -358,7 +358,7 @@ module DEBUGGER__
358
358
  }
359
359
  send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
360
360
  else
361
- send_response req, success: false, message: "#{req_path} is not available"
361
+ send_response req, breakpoints: (args['breakpoints'].map do |bp| {verified: false, message: "#{req_path} could not be located; specify source location in launch.json with \"localfsMap\" or \"localfs\""} end)
362
362
  end
363
363
 
364
364
  when 'setFunctionBreakpoints'
data/lib/debug/session.rb CHANGED
@@ -931,7 +931,6 @@ module DEBUGGER__
931
931
  register_command 'eval', 'call' do |arg|
932
932
  if arg == nil || arg.empty?
933
933
  show_help 'eval'
934
- @ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead."
935
934
  :retry
936
935
  else
937
936
  request_eval :call, arg
@@ -1144,7 +1143,7 @@ module DEBUGGER__
1144
1143
 
1145
1144
  def process_command line
1146
1145
  if line.empty?
1147
- if @repl_prev_line
1146
+ if @repl_prev_line && !CONFIG[:no_repeat]
1148
1147
  line = @repl_prev_line
1149
1148
  else
1150
1149
  return :retry
@@ -2301,11 +2300,20 @@ module DEBUGGER__
2301
2300
  end
2302
2301
 
2303
2302
  def self.load_rc
2304
- [[File.expand_path('~/.rdbgrc'), true],
2305
- [File.expand_path('~/.rdbgrc.rb'), true],
2306
- # ['./.rdbgrc', true], # disable because of security concern
2307
- [CONFIG[:init_script], false],
2308
- ].each{|(path, rc)|
2303
+ rc_file_paths = [
2304
+ [File.expand_path('~/.rdbgrc'), true],
2305
+ [File.expand_path('~/.rdbgrc.rb'), true],
2306
+ # ['./.rdbgrc', true], # disable because of security concern
2307
+ ]
2308
+
2309
+ if (xdg_home = ENV["XDG_CONFIG_HOME"])
2310
+ rc_file_paths << [File.expand_path(File.join(xdg_home, "rdbg", "config")), true]
2311
+ rc_file_paths << [File.expand_path(File.join(xdg_home, "rdbg", "config.rb")), true]
2312
+ end
2313
+
2314
+ rc_file_paths << [CONFIG[:init_script], false]
2315
+
2316
+ rc_file_paths.each{|(path, rc)|
2309
2317
  next unless path
2310
2318
  next if rc && CONFIG[:no_rc] # ignore rc
2311
2319
 
@@ -350,6 +350,7 @@ module DEBUGGER__
350
350
  next if tp.path.start_with?(__dir__)
351
351
  next if tp.path.start_with?('<internal:trace_point>')
352
352
  next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
353
+ next if skip_internal_path?(tp.path)
353
354
  loc = caller_locations(1, 1).first
354
355
  next if skip_location?(loc)
355
356
  next if iter && (iter -= 1) > 0
@@ -369,6 +370,7 @@ module DEBUGGER__
369
370
  next if tp.path.start_with?(__dir__)
370
371
  next if tp.path.start_with?('<internal:trace_point>')
371
372
  next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
373
+ next if skip_internal_path?(tp.path)
372
374
  loc = caller_locations(1, 1).first
373
375
  next if skip_location?(loc)
374
376
  next if iter && (iter -= 1) > 0
@@ -1079,13 +1081,13 @@ module DEBUGGER__
1079
1081
  when :up
1080
1082
  if @current_frame_index + 1 < @target_frames.size
1081
1083
  @current_frame_index += 1
1082
- show_src max_lines: 1
1084
+ show_src max_lines: CONFIG[:show_src_lines_frame]
1083
1085
  show_frame(@current_frame_index)
1084
1086
  end
1085
1087
  when :down
1086
1088
  if @current_frame_index > 0
1087
1089
  @current_frame_index -= 1
1088
- show_src max_lines: 1
1090
+ show_src max_lines: CONFIG[:show_src_lines_frame]
1089
1091
  show_frame(@current_frame_index)
1090
1092
  end
1091
1093
  when :set
@@ -1097,7 +1099,7 @@ module DEBUGGER__
1097
1099
  puts "out of frame index: #{index}"
1098
1100
  end
1099
1101
  end
1100
- show_src max_lines: 1
1102
+ show_src max_lines: CONFIG[:show_src_lines_frame]
1101
1103
  show_frame(@current_frame_index)
1102
1104
  else
1103
1105
  raise "unsupported frame operation: #{arg.inspect}"
@@ -1308,7 +1310,7 @@ module DEBUGGER__
1308
1310
  frame._local_variables = b.local_variables.map{|name|
1309
1311
  [name, b.local_variable_get(name)]
1310
1312
  }.to_h
1311
- frame._callee = b.eval('__callee__')
1313
+ frame._callee = b.eval('::Kernel.__callee__')
1312
1314
  end
1313
1315
  }
1314
1316
  append(frames)
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.10.0"
4
+ VERSION = "1.11.1"
5
5
  end