File: command_processor.rb

package info (click to toggle)
ruby-byebug 12.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,304 kB
  • sloc: ruby: 9,013; ansic: 1,678; sh: 5; makefile: 4
file content (173 lines) | stat: -rw-r--r-- 3,275 bytes parent folder | download | duplicates (4)
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# frozen_string_literal: true

require "forwardable"

require_relative "../helpers/eval"
require_relative "../errors"

module Byebug
  #
  # Processes commands in regular mode.
  #
  # You can override this class to create your own command processor that, for
  # example, whitelists only certain commands to be executed.
  #
  # @see PostMortemProcessor for a example
  #
  class CommandProcessor
    include Helpers::EvalHelper

    attr_accessor :prev_line
    attr_reader :context, :interface

    def initialize(context, interface = LocalInterface.new)
      @context = context
      @interface = interface

      @proceed = false
      @prev_line = nil
    end

    def printer
      @printer ||= Printers::Plain.new
    end

    extend Forwardable

    def_delegators :@context, :frame

    def_delegator :printer, :print, :pr
    def_delegator :printer, :print_collection, :prc
    def_delegator :printer, :print_variables, :prv

    def_delegators :interface, :errmsg, :puts, :confirm

    def_delegators :Byebug, :commands

    #
    # Available commands
    #
    def command_list
      @command_list ||= CommandList.new(commands)
    end

    def at_line
      process_commands
    end

    def at_tracing
      puts "Tracing: #{context.full_location}"

      run_auto_cmds(2)
    end

    def at_breakpoint(brkpt)
      number = Byebug.breakpoints.index(brkpt) + 1

      puts "Stopped by breakpoint #{number} at #{frame.file}:#{frame.line}"
    end

    def at_catchpoint(exception)
      puts "Catchpoint at #{context.location}: `#{exception}'"
    end

    def at_return(return_value)
      puts "Return value is: #{safe_inspect(return_value)}"

      process_commands
    end

    def at_end
      process_commands
    end

    #
    # Let the execution continue
    #
    def proceed!
      @proceed = true
    end

    #
    # Handle byebug commands.
    #
    def process_commands
      before_repl

      repl
    ensure
      after_repl
    end

    protected

    #
    # Prompt shown before reading a command.
    #
    def prompt
      "(byebug) "
    end

    def before_repl
      @proceed = false
      @prev_line = nil

      run_auto_cmds(1)
      interface.autorestore
    end

    def after_repl
      interface.autosave
    end

    #
    # Main byebug's REPL
    #
    def repl
      until @proceed
        cmd = interface.read_command(prompt)
        return if cmd.nil?

        next if cmd == ""

        run_cmd(cmd)
      end
    end

    private

    def auto_cmds_for(run_level)
      command_list.select { |cmd| cmd.always_run >= run_level }
    end

    #
    # Run permanent commands.
    #
    def run_auto_cmds(run_level)
      safely do
        auto_cmds_for(run_level).each { |cmd| cmd.new(self).execute }
      end
    end

    #
    # Executes the received input
    #
    # Instantiates a command matching the input and runs it. If a matching
    # command is not found, it evaluates the unknown input.
    #
    def run_cmd(input)
      safely do
        command = command_list.match(input)
        return command.new(self, input).execute if command

        puts safe_inspect(multiple_thread_eval(input))
      end
    end

    def safely
      yield
    rescue StandardError => e
      errmsg(e.message)
    end
  end
end