lib/byebug/dap/command_processor.rb in byebug-dap-0.1.3 vs lib/byebug/dap/command_processor.rb in byebug-dap-0.1.4

- old
+ new

@@ -1,38 +1,65 @@ module Byebug module DAP + # Processes thread-specific commands and handles Byebug/TracePoint events. class CommandProcessor extend Forwardable include SafeHelpers + # Indicates a timeout while sending a message to the context. class TimeoutError < StandardError + # The receiving context. + # @return [gem:byebug:Byebug::Context] attr_reader :context def initialize(context) @context = context end end - attr_reader :context, :last_exception + # The thread context. + # @return [gem:byebug:Byebug::Context] + attr_reader :context + + # The last exception that occured. + # @return [std:Exception] + attr_reader :last_exception + + # Indicates that the client requested a pause. + # @return [Boolean] + # @note This should only be set by {Command::Pause} + # @api private attr_writer :pause_requested + # Create a new command processor. + # @param context [gem:byebug:Byebug::Context] the thread context + # @param session [Session] the debugging session + # @note This should only be used by Byebug internals + # @api private def initialize(context, session) @context = context @session = session @requests = Channel.new @exec_mu = Mutex.new @exec_ch = Channel.new end + # (see Session#log) def log(*args) @session.log(*args) end + # Send a message to the thread context. + # @param message the message to send + # @note Raises a {TimeoutError timeout error} after 1 second if the thread is not paused or not responding. def <<(message) @requests.push(message, timeout: 1) { raise TimeoutError.new(context) } end + # Execute a code block in the thread. + # @yield the code block to execute + # @note This calls {#\<\<} and thus may raise a {TimeoutError timeout error}. def execute(&block) raise "Block required" unless block_given? r, err = nil, nil @exec_mu.synchronize { @@ -45,10 +72,55 @@ else r end end + # Line handler. + # @note This should only be called by Byebug internals + # @api private + def at_line + stopped! + end + + # End of class/module handler. + # @note This should only be called by Byebug internals + # @api private + def at_end + stopped! + end + + # Return handler. + # @note This should only be called by Byebug internals + # @api private + def at_return(return_value) + @at_return = return_value + stopped! + end + + # Tracing handler. + # @note This should only be called by Byebug internals + # @api private + def at_tracing + # @session.puts "Tracing: #{context.full_location}" + end + + # Breakpoint handler. + # @note This should only be called by Byebug internals + # @api private + def at_breakpoint(breakpoint) + @last_breakpoint = breakpoint + end + + # Catchpoint handler. + # @note This should only be called by Byebug internals + # @api private + def at_catchpoint(exception) + @last_exception = exception + end + + private + def process_requests loop do request = @requests.pop break unless request @@ -67,39 +139,10 @@ rescue StandardError => e log "\n! #{e.message} (#{e.class})", *e.backtrace end - def logpoint! - return false unless @last_breakpoint - - breakpoint, @last_breakpoint = @last_breakpoint, nil - expr = @session.get_log_point(breakpoint) - return false unless expr - - binding = @context.frame._binding - msg = expr.gsub(/\{([^\}]+)\}/) do |x| - safe(binding, :eval, x[1...-1]) { return true } # ignore bad log points - end - - body = { - category: 'console', - output: msg + "\n", - } - - if breakpoint.pos.is_a?(Integer) - body[:line] = breakpoint.pos - body[:source] = { - name: File.basename(breakpoint.source), - path: breakpoint.source, - } - end - - @session.event! 'output', **body - return true - end - def stopped! return if logpoint! case context.stop_reason when :breakpoint @@ -139,33 +182,36 @@ @session.event! 'stopped', threadId: context.thnum, **args if args process_requests end - alias at_line stopped! - alias at_end stopped! + def logpoint! + return false unless @last_breakpoint - def at_end - stopped! - end + breakpoint, @last_breakpoint = @last_breakpoint, nil + expr = @session.get_log_point(breakpoint) + return false unless expr - def at_return(return_value) - @at_return = return_value - stopped! - end + binding = @context.frame._binding + msg = expr.gsub(/\{([^\}]+)\}/) do |x| + safe(binding, :eval, x[1...-1]) { return true } # ignore bad log points + end - # def at_tracing - # @session.puts "Tracing: #{context.full_location}" + body = { + category: 'console', + output: msg + "\n", + } - # # run_auto_cmds(2) - # end + if breakpoint.pos.is_a?(Integer) + body[:line] = breakpoint.pos + body[:source] = { + name: File.basename(breakpoint.source), + path: breakpoint.source, + } + end - def at_breakpoint(breakpoint) - @last_breakpoint = breakpoint - end - - def at_catchpoint(exception) - @last_exception = exception + @session.event! 'output', **body + return true end end end end