@@ -5,28 +5,68 @@ module IRB
55
66  module  ExtendCommand 
77    class  Debug  < Nop 
8+       BINDING_IRB_FRAME_REGEXPS  =  [ 
9+         '<internal:prelude>' , 
10+         binding . method ( :irb ) . source_location . first , 
11+       ] . map  {  |file | /\A #{ Regexp . escape ( file ) } \d +:in `irb'\z /  } 
12+       IRB_DIR  =  File . expand_path ( '..' ,  __dir__ ) 
13+ 
814      def  execute ( *args ) 
9-         require  "debug/session" 
10-         DEBUGGER__ . start ( nonstop : true ) 
11-         DEBUGGER__ . singleton_class . send ( :alias_method ,  :original_capture_frames ,  :capture_frames ) 
12- 
13-         def  DEBUGGER__ . capture_frames ( skip_path_prefix ) 
14-           frames  =  original_capture_frames ( skip_path_prefix ) 
15-           frames . reject!  do  |frame |
16-             frame . realpath &.start_with? ( ::IRB ::Irb ::DIR_NAME )  || frame . path . match? ( /internal:prelude/ ) 
17-           end 
18-           frames 
15+         unless  binding_irb? 
16+           puts  "`debug` command is only available when IRB is started with binding.irb" 
17+           return 
1918        end 
2019
20+         unless  setup_debugger 
21+           puts  <<~MSG 
22+             You need to install the debug gem before using this command. 
23+             If you use `bundle exec`, please add `gem "debug"` into your Gemfile. 
24+           MSG 
25+           return 
26+         end 
27+ 
28+         # To make debugger commands like `next` or `continue` work without asking 
29+         # the user to quit IRB after that, we need to exit IRB first and then hit 
30+         # a TracePoint on #debug_break. 
2131        file ,  lineno  =  IRB ::Irb . instance_method ( :debug_break ) . source_location 
2232        DEBUGGER__ ::SESSION . add_line_breakpoint ( file ,  lineno  + 1 ,  oneshot : true ,  hook_call : false ) 
2333        # exit current Irb#run call 
2434        throw  :IRB_EXIT 
25-       rescue  LoadError  =>  e 
26-         puts  <<~MSG 
27-           You need to install the debug gem before using this command. 
28-           If you use `bundle exec`, please add `gem "debug"` into your Gemfile. 
29-         MSG 
35+       end 
36+ 
37+       private 
38+ 
39+       def  binding_irb? 
40+         caller . any?  do  |frame |
41+           BINDING_IRB_FRAME_REGEXPS . any?  do  |regexp |
42+             frame . match? ( regexp ) 
43+           end 
44+         end 
45+       end 
46+ 
47+       def  setup_debugger 
48+         unless  defined? ( DEBUGGER__ ::SESSION ) 
49+           begin 
50+             require  "debug/session" 
51+           rescue  LoadError 
52+             return  false 
53+           end 
54+           DEBUGGER__ . start ( nonstop : true ) 
55+         end 
56+ 
57+         unless  DEBUGGER__ . respond_to? ( :capture_frames_without_irb ) 
58+           DEBUGGER__ . singleton_class . send ( :alias_method ,  :capture_frames_without_irb ,  :capture_frames ) 
59+ 
60+           def  DEBUGGER__ . capture_frames ( *args ) 
61+             frames  =  capture_frames_without_irb ( *args ) 
62+             frames . reject!  do  |frame |
63+               frame . realpath &.start_with? ( IRB_DIR )  || frame . path  == "<internal:prelude>" 
64+             end 
65+             frames 
66+           end 
67+         end 
68+ 
69+         true 
3070      end 
3171    end 
3272  end 
0 commit comments