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