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
|