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

- old
+ new

@@ -1,11 +1,16 @@ module Byebug::DAP + # Implementation of a DAP command. + # @abstract Subclasses must implement {#execute} class Command + # The error message returned when a variable or expression cannot be evaluated. EVAL_ERROR = "*Error in evaluation*" include SafeHelpers + # The DAP command assocated with the receiver. + # @return [std:String] def self.command return @command_name if defined?(@command_name) raise "Not a command" if self == Byebug::DAP::Command raise "Not a command" unless self < Byebug::DAP::Command @@ -13,36 +18,54 @@ last = self.name.split('::').last @command_name = "#{last[0].downcase}#{last[1..]}" end + # Register the receiver as a DAP command. def self.register! (@@commands ||= {})[command] = self end + # Resolve the requested command. Calls {Session#respond!} indicating a + # failed request if the command cannot be found. + # @param session [Session] the debug session + # @param request [Protocol::Request] the DAP request + # @return [std:Class] the {Command} class def self.resolve!(session, request) cls = @@commands[request.command] return cls if cls session.respond! request, success: false, message: 'Invalid command' end + # Resolve and execute the requested command. The command is {.resolve! + # resolved}, {#initialize initialized}, and {#safe_execute safely executed}. + # @param session [Session] the debug session + # @param request [Protocol::Request] the DAP request + # @param args [std:Array] additional arguments for {#initialize} + # @return the return value of {#safe_execute} def self.execute(session, request, *args) return unless command = resolve!(session, request) command.new(session, request, *args).safe_execute end + # Create a new instance of the receiver. + # @param session [Session] the debug session + # @param request [Protocol::Request] the DAP request def initialize(session, request) @session = session @request = request end + # (see Session#log) def log(*args) @session.log(*args) end + # Call {#execute} safely, handling any errors that arise. + # @return the return value of {#execute} def safe_execute execute rescue InvalidRequestArgumentError => e message = @@ -89,16 +112,22 @@ @session.respond! @request, *args, **values return end + # Raises an error if the debugger is running + # @api private + # @!visibility public def stopped! return if !Byebug.started? respond! success: false, message: "Cannot #{@request.command} - debugger is already running" end + # Raises an error unless the debugger is running + # @api private + # @!visibility public def started! return if Byebug.started? respond! success: false, message: "Cannot #{@request.command} - debugger is not running" end @@ -109,10 +138,17 @@ def exception_description(ex) safe(-> { "#{ex.message} (#{ex.class.name})" }, :call) { EVAL_ERROR } end + # Execute a code block on the specified thread, {SafeHelpers#safe safely}. + # @param thnum [std:Integer] the thread number + # @param block [std:Proc] the code block + # @yield called on error + # @yieldparam ex [std:Exception] the execution error + # @api private + # @!visibility public def execute_on_thread(thnum, block, &on_error) return safe(block, :call, &on_error) if thnum == 0 || @context&.thnum == thnum p = find_thread(thnum).processor safe(-> { p.execute(&block) }, :call, &on_error) @@ -205,11 +241,13 @@ return nil unless condition.is_a?(String) return condition end def convert_breakpoint_hit_condition(condition) - return nil if condition.nil? || condition.empty? - return nil unless condition.is_a?(String) + # Because of https://github.com/deivid-rodriguez/byebug/issues/739, + # Breakpoint#hit_condition can't be set to nil. + return :ge, 0 if condition.nil? || condition.empty? + return :ge, 0 unless condition.is_a?(String) m = /^(?<op><|<=|=|==|===|=>|>|%)?\s*(?<value>[0-9]+)$/.match(condition) raise InvalidRequestArgumentError.new("'#{condition}' is not a valid hit condition") unless m v = m[:value].to_i