summaryrefslogtreecommitdiff
path: root/lib/irb/debug/ui.rb
blob: 307097b8c95bd54ab65872c7f082a5d0131118af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
require 'io/console/size'
require 'debug/console'

module IRB
  module Debug
    class UI < DEBUGGER__::UI_Base
      def initialize(irb)
        @irb = irb
      end

      def remote?
        false
      end

      def activate session, on_fork: false
      end

      def deactivate
      end

      def width
        if (w = IO.console_size[1]) == 0 # for tests PTY
          80
        else
          w
        end
      end

      def quit n
        yield
        exit n
      end

      def ask prompt
        setup_interrupt do
          print prompt
          ($stdin.gets || '').strip
        end
      end

      def puts str = nil
        case str
        when Array
          str.each{|line|
            $stdout.puts line.chomp
          }
        when String
          str.each_line{|line|
            $stdout.puts line.chomp
          }
        when nil
          $stdout.puts
        end
      end

      def readline _
        setup_interrupt do
          tc = DEBUGGER__::SESSION.instance_variable_get(:@tc)
          cmd = @irb.debug_readline(tc.current_frame.binding || TOPLEVEL_BINDING)

          case cmd
          when nil # when user types C-d
            "continue"
          else
            cmd
          end
        end
      end

      def setup_interrupt
        DEBUGGER__::SESSION.intercept_trap_sigint false do
          current_thread = Thread.current # should be session_server thread

          prev_handler = trap(:INT){
            current_thread.raise Interrupt
          }

          yield
        ensure
          trap(:INT, prev_handler)
        end
      end

      def after_fork_parent
        parent_pid = Process.pid

        at_exit{
          DEBUGGER__::SESSION.intercept_trap_sigint_end
          trap(:SIGINT, :IGNORE)

          if Process.pid == parent_pid
            # only check child process from its parent
            begin
              # wait for all child processes to keep terminal
              Process.waitpid
            rescue Errno::ESRCH, Errno::ECHILD
            end
          end
        }
      end
    end
  end
end