require 'forwardable' require 'byebug/helpers/eval' require 'byebug/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 def initialize(context) @context = context @proceed = false @prev_line = nil end def interface @interface ||= context.class.interface end def printer @printer ||= Printers::Plain.new end def frame @context.frame end extend Forwardable def_delegator :printer, :print, :pr def_delegator :printer, :print_collection, :prc def_delegator :printer, :print_variables, :prv def_delegators :interface, :errmsg, :puts, :confirm # # Available commands # def command_list @command_list ||= CommandList.new(commands) end def commands Byebug.commands 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_tracing puts "Tracing: #{context.full_location}" run_auto_commands(2) end def at_line process_commands end def at_return 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 private def auto_commands_for(run_level) command_list.select { |cmd| cmd.always_run >= run_level } end # # Run permanent commands. # def run_auto_commands(run_level) auto_commands_for(run_level).each { |cmd| cmd.new(self).execute } end def before_repl @proceed = false @prev_line = nil run_auto_commands(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 # # 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) command = command_list.match(input) return command.new(self, input).execute if command puts thread_safe_eval(input) rescue => e errmsg(e) end end end