From 00872d120b017de2270fe18068cea2d37d41ed71 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Fri, 18 Nov 2022 09:11:19 +0000 Subject: [PATCH] [ruby/irb] Add debug command (https://github.com/ruby/irb/pull/446) https://github.com/ruby/irb/commit/30faa13fa3 --- lib/irb.rb | 13 +++++++++++++ lib/irb/cmd/debug.rb | 33 +++++++++++++++++++++++++++++++++ lib/irb/extend-command.rb | 4 ++++ 3 files changed, 50 insertions(+) create mode 100644 lib/irb/cmd/debug.rb diff --git a/lib/irb.rb b/lib/irb.rb index 1c38960cc0..1cd89d295c 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -393,6 +393,8 @@ module IRB end class Irb + DIR_NAME = __dir__ + ASSIGNMENT_NODE_TYPES = [ # Local, instance, global, class, constant, instance, and index assignment: # "foo = bar", @@ -434,6 +436,16 @@ module IRB @scanner = RubyLex.new end + def debug_break + # it means the debug command is executed + if defined?(DEBUGGER__) && DEBUGGER__.respond_to?(:original_capture_frames) + # after leaving this initial breakpoint, revert the capture_frames patch + DEBUGGER__.singleton_class.send(:alias_method, :capture_frames, :original_capture_frames) + # and remove the redundant method + DEBUGGER__.singleton_class.send(:undef_method, :original_capture_frames) + end + end + def run(conf = IRB.conf) conf[:IRB_RC].call(context) if conf[:IRB_RC] conf[:MAIN_CONTEXT] = context @@ -931,5 +943,6 @@ class Binding binding_irb = IRB::Irb.new(workspace) binding_irb.context.irb_path = File.expand_path(source_location[0]) binding_irb.run(IRB.conf) + binding_irb.debug_break end end diff --git a/lib/irb/cmd/debug.rb b/lib/irb/cmd/debug.rb new file mode 100644 index 0000000000..8aab40cf84 --- /dev/null +++ b/lib/irb/cmd/debug.rb @@ -0,0 +1,33 @@ +require_relative "nop" + +module IRB + # :stopdoc: + + module ExtendCommand + class Debug < Nop + def execute(*args) + require "debug/session" + DEBUGGER__.start(nonstop: true) + DEBUGGER__.singleton_class.send(:alias_method, :original_capture_frames, :capture_frames) + + def DEBUGGER__.capture_frames(skip_path_prefix) + frames = original_capture_frames(skip_path_prefix) + frames.reject! do |frame| + frame.realpath&.start_with?(::IRB::Irb::DIR_NAME) || frame.path.match?(/internal:prelude/) + end + frames + end + + file, lineno = IRB::Irb.instance_method(:debug_break).source_location + DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, oneshot: true, hook_call: false) + # exit current Irb#run call + throw :IRB_EXIT + rescue LoadError => e + puts <<~MSG + You need to install the debug gem before using this command. + If you use `bundle exec`, please add `gem "debug"` into your Gemfile. + MSG + end + end + end +end diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb index acc23c9920..7da75fe147 100644 --- a/lib/irb/extend-command.rb +++ b/lib/irb/extend-command.rb @@ -116,6 +116,10 @@ module IRB # :nodoc: [:kill, OVERRIDE_PRIVATE_ONLY], ], + [ + :irb_debug, :Debug, "cmd/debug", + [:debug, NO_OVERRIDE], + ], [ :irb_help, :Help, "cmd/help", [:help, NO_OVERRIDE],