Class: Byebug::DAP::Command Abstract

Inherits:
Object
  • Object
show all
Includes:
SafeHelpers
Defined in:
lib/byebug/dap/command.rb

Overview

This class is abstract.

Subclasses must implement #execute

Implementation of a DAP command.

Defined Under Namespace

Classes: Attach, BreakpointLocations, ConfigurationDone, Continue, Disconnect, Evaluate, ExceptionInfo, Initialize, Launch, Next, Pause, Scopes, SetBreakpoints, SetExceptionBreakpoints, SetFunctionBreakpoints, Source, StackTrace, StepIn, StepOut, Threads, Variables

Constant Summary collapse

EVAL_ERROR =

The error message returned when a variable or expression cannot be evaluated.

"*Error in evaluation*"

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SafeHelpers

#safe

Constructor Details

#initialize(session, request) ⇒ Command

Create a new instance of the receiver.

Parameters:

  • session (Session)

    the debug session

  • request (Protocol::Request)

    the DAP request



55
56
57
58
# File 'lib/byebug/dap/command.rb', line 55

def initialize(session, request)
  @session = session
  @request = request
end

Class Method Details

.commandstd:String

The DAP command assocated with the receiver.

Returns:

  • (std:String)


12
13
14
15
16
17
18
19
20
21
# File 'lib/byebug/dap/command.rb', line 12

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
  raise "Not a command" unless self.name.start_with?('Byebug::DAP::Command::')

  last = self.name.split('::').last
  @command_name = "#{last[0].downcase}#{last[1..]}"
end

.execute(session, request, *args) ⇒ Object

Resolve and execute the requested command. The command is resolved, initialized, and safely executed.

Parameters:

  • session (Session)

    the debug session

  • request (Protocol::Request)

    the DAP request

  • args (std:Array)

    additional arguments for #initialize

Returns:



46
47
48
49
50
# File 'lib/byebug/dap/command.rb', line 46

def self.execute(session, request, *args)
  return unless command = resolve!(session, request)

  command.new(session, request, *args).safe_execute
end

.register!Object

Register the receiver as a DAP command.



24
25
26
# File 'lib/byebug/dap/command.rb', line 24

def self.register!
  (@@commands ||= {})[command] = self
end

.resolve!(session, request) ⇒ std:Class

Resolve the requested command. Calls Session#respond! indicating a failed request if the command cannot be found.

Parameters:

  • session (Session)

    the debug session

  • request (Protocol::Request)

    the DAP request

Returns:



33
34
35
36
37
38
# File 'lib/byebug/dap/command.rb', line 33

def self.resolve!(session, request)
  cls = @@commands[request.command]
  return cls if cls

  session.respond! request, success: false, message: 'Invalid command'
end

Instance Method Details

#execute_on_thread(thnum, block) {|ex| ... } ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Execute a code block on the specified thread, safely.

Parameters:

  • thnum (std:Integer)

    the thread number

  • block (std:Proc)

    the code block

Yields:

  • called on error

Yield Parameters:

  • ex (std:Exception)

    the execution error



150
151
152
153
154
155
# File 'lib/byebug/dap/command.rb', line 150

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)
end

#log(*args) ⇒ Object

Write a message to the log.



61
62
63
# File 'lib/byebug/dap/command.rb', line 61

def log(*args)
  @session.log(*args)
end

#safe_executeObject

Call #execute safely, handling any errors that arise.

Returns:

  • the return value of #execute



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
# File 'lib/byebug/dap/command.rb', line 67

def safe_execute
  execute

rescue InvalidRequestArgumentError => e
  message =
    case e.error
    when String
      e.error

    when :missing_argument
      "Argument is unspecified: #{e.scope}"

    when :missing_entry
      "Cannot locate #{e.scope} ##{e.value}"

    when :invalid_entry
      "Error resolving #{e.scope}: #{e.value}"

    else
      log "#{e.message} (#{e.class})", *e.backtrace
      "An internal error occured"
    end

  respond! success: false, message: message

rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
  :disconnected

rescue CommandProcessor::TimeoutError => e
  respond! success: false, message: "Debugger on thread ##{e.context.thnum} is not responding"

rescue StandardError => e
  respond! success: false, message: "An internal error occured"
  log "#{e.message} (#{e.class})", *e.backtrace
end

#started!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises an error unless the debugger is running



129
130
131
132
133
# File 'lib/byebug/dap/command.rb', line 129

def started!
  return if Byebug.started?

  respond! success: false, message: "Cannot #{@request.command} - debugger is not running"
end

#stopped!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises an error if the debugger is running



120
121
122
123
124
# File 'lib/byebug/dap/command.rb', line 120

def stopped!
  return if !Byebug.started?

  respond! success: false, message: "Cannot #{@request.command} - debugger is already running"
end