Toggle breakpoints, command dispatch refactor
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
// Additionally you need a field called "remedy_build_system" to signal which
|
// Additionally you need a field called "remedy_build_system" to signal which
|
||||||
// build system was chosen if you have more then 1 build system.
|
// build system was chosen if you have more then 1 build system.
|
||||||
"build_before_debugging": true,
|
"build_before_debugging": true,
|
||||||
|
"stop_debugging_on_build_command": true,
|
||||||
"executable": "remedybg.exe",
|
"executable": "remedybg.exe",
|
||||||
"vc_vars_cmd": "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/Build/vcvarsall.bat",
|
"vc_vars_cmd": "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Auxiliary/Build/vcvarsall.bat",
|
||||||
"vc_vars_arch": "amd64",
|
"vc_vars_arch": "amd64",
|
||||||
|
|||||||
193
remedy.py
193
remedy.py
@@ -20,62 +20,16 @@ class RemedyInstance:
|
|||||||
self.event_pipe = None
|
self.event_pipe = None
|
||||||
self.process = None
|
self.process = None
|
||||||
self.servername = ""
|
self.servername = ""
|
||||||
|
self.breakpoints = {}
|
||||||
|
|
||||||
def send_command(self, cmd, **cmd_args):
|
def begin_command(self, cmd):
|
||||||
if self.cmd_pipe is None: return 0
|
|
||||||
|
|
||||||
cmd_buffer = io.BytesIO()
|
cmd_buffer = io.BytesIO()
|
||||||
cmd_buffer.write(ctypes.c_uint16(cmd))
|
cmd_buffer.write(ctypes.c_uint16(cmd))
|
||||||
|
return cmd_buffer
|
||||||
|
|
||||||
if cmd == COMMAND_ADD_BREAKPOINT_AT_FILENAME_LINE:
|
def end_command(self, cmd_buffer):
|
||||||
filepath = cmd_args['filename']
|
if self.cmd_pipe == None:
|
||||||
cmd_buffer.write(ctypes.c_uint16(len(filepath)))
|
return 0
|
||||||
cmd_buffer.write(bytes(filepath, 'utf-8'))
|
|
||||||
cmd_buffer.write(ctypes.c_uint32(cmd_args['line']))
|
|
||||||
cmd_buffer.write(ctypes.c_uint16(0))
|
|
||||||
elif cmd == COMMAND_GOTO_FILE_AT_LINE:
|
|
||||||
filepath = cmd_args['filename']
|
|
||||||
cmd_buffer.write(ctypes.c_uint16(len(filepath)))
|
|
||||||
cmd_buffer.write(bytes(filepath, 'utf-8'))
|
|
||||||
cmd_buffer.write(ctypes.c_uint32(cmd_args['line']))
|
|
||||||
elif cmd == COMMAND_START_DEBUGGING:
|
|
||||||
cmd_buffer.write(ctypes.c_uint8(0))
|
|
||||||
elif cmd == COMMAND_STEP_INTO_BY_LINE:
|
|
||||||
pass
|
|
||||||
elif cmd == COMMAND_STEP_OVER_BY_LINE:
|
|
||||||
pass
|
|
||||||
elif cmd == COMMAND_STEP_OVER_BY_LINE:
|
|
||||||
pass
|
|
||||||
elif cmd == COMMAND_STOP_DEBUGGING:
|
|
||||||
pass
|
|
||||||
elif cmd == COMMAND_RESTART_DEBUGGING:
|
|
||||||
pass
|
|
||||||
elif cmd == COMMAND_CONTINUE_EXECUTION:
|
|
||||||
pass
|
|
||||||
elif cmd == COMMAND_RUN_TO_FILE_AT_LINE:
|
|
||||||
filepath = cmd_args['filename']
|
|
||||||
cmd_buffer.write(ctypes.c_uint16(len(filepath)))
|
|
||||||
cmd_buffer.write(bytes(filepath, 'utf-8'))
|
|
||||||
cmd_buffer.write(ctypes.c_uint32(cmd_args['line']))
|
|
||||||
elif cmd == COMMAND_GET_TARGET_STATE:
|
|
||||||
pass
|
|
||||||
elif cmd == COMMAND_ADD_WATCH:
|
|
||||||
expr = cmd_args['expr']
|
|
||||||
cmd_buffer.write(ctypes.c_uint8(1)) # watch window 1
|
|
||||||
cmd_buffer.write(ctypes.c_uint16(len(expr)))
|
|
||||||
cmd_buffer.write(bytes(expr, 'utf-8'))
|
|
||||||
cmd_buffer.write(ctypes.c_uint16(0))
|
|
||||||
elif cmd == COMMAND_SET_WINDOW_POS:
|
|
||||||
cmd_buffer.write(ctypes.c_int32(cmd_args['x']))
|
|
||||||
cmd_buffer.write(ctypes.c_int32(cmd_args['y']))
|
|
||||||
cmd_buffer.write(ctypes.c_int32(cmd_args['w']))
|
|
||||||
cmd_buffer.write(ctypes.c_int32(cmd_args['h']))
|
|
||||||
elif cmd == COMMAND_GET_WINDOW_POS:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
assert 0
|
|
||||||
return 0 # not implemented
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out_data = win32pipe.TransactNamedPipe(self.cmd_pipe, cmd_buffer.getvalue(), 8192, None)
|
out_data = win32pipe.TransactNamedPipe(self.cmd_pipe, cmd_buffer.getvalue(), 8192, None)
|
||||||
@@ -86,25 +40,83 @@ class RemedyInstance:
|
|||||||
|
|
||||||
out_buffer = io.BytesIO(out_data[1])
|
out_buffer = io.BytesIO(out_data[1])
|
||||||
result_code = int.from_bytes(out_buffer.read(2), 'little')
|
result_code = int.from_bytes(out_buffer.read(2), 'little')
|
||||||
if result_code == 1:
|
if result_code != 1:
|
||||||
if cmd == COMMAND_ADD_BREAKPOINT_AT_FILENAME_LINE:
|
cmd_buffer.seek(0)
|
||||||
bp_id = int.from_bytes(out_buffer.read(4), 'little')
|
cmd = int.from_bytes(out_buffer.read(2), 'little')
|
||||||
return 0
|
|
||||||
elif cmd == COMMAND_GET_TARGET_STATE:
|
|
||||||
return int.from_bytes(out_buffer.read(2), 'little')
|
|
||||||
elif cmd == COMMAND_ADD_WATCH:
|
|
||||||
return int.from_bytes(out_buffer.read(4), 'little')
|
|
||||||
elif cmd == COMMAND_GET_WINDOW_POS:
|
|
||||||
x = int.from_bytes(out_buffer.read(4), 'little')
|
|
||||||
y = int.from_bytes(out_buffer.read(4), 'little')
|
|
||||||
w = int.from_bytes(out_buffer.read(4), 'little')
|
|
||||||
h = int.from_bytes(out_buffer.read(4), 'little')
|
|
||||||
return (x, y, w, h)
|
|
||||||
else:
|
|
||||||
sublime.message_dialog('RemedyBG: ' + str(cmd) + ' failed')
|
sublime.message_dialog('RemedyBG: ' + str(cmd) + ' failed')
|
||||||
|
return out_buffer, result_code
|
||||||
|
|
||||||
|
def add_breakpoint_at_filename_line(self, view, filename, line, region):
|
||||||
|
buff = self.begin_command(COMMAND_ADD_BREAKPOINT_AT_FILENAME_LINE)
|
||||||
|
buff.write(ctypes.c_uint16(len(filename)))
|
||||||
|
buff.write(bytes(filename, 'utf-8'))
|
||||||
|
buff.write(ctypes.c_uint32(line))
|
||||||
|
buff.write(ctypes.c_uint16(0))
|
||||||
|
buff, result_code = self.end_command(buff)
|
||||||
|
if result_code == 1:
|
||||||
|
bp_id = int.from_bytes(buff.read(4), 'little')
|
||||||
|
key = filename + ":" + str(line)
|
||||||
|
self.breakpoints[key] = bp_id
|
||||||
|
view.add_regions(key, [region], scope="region.redish", icon="circle")
|
||||||
|
|
||||||
|
def delete_breakpoint(self, view, filename, line):
|
||||||
|
key = filename + ":" + str(line)
|
||||||
|
id = self.breakpoints.get(key)
|
||||||
|
if id:
|
||||||
|
buff = self.begin_command(COMMAND_DELETE_BREAKPOINT)
|
||||||
|
buff.write(ctypes.c_uint32(id))
|
||||||
|
buff, result_code = self.end_command(buff)
|
||||||
|
self.breakpoints.pop(key)
|
||||||
|
view.erase_regions(key)
|
||||||
|
|
||||||
|
def toggle_breakpoint(self, view, filename, line, region):
|
||||||
|
key = filename + ":" + str(line)
|
||||||
|
if key in self.breakpoints.keys():
|
||||||
|
self.delete_breakpoint(view, filename, line)
|
||||||
|
else:
|
||||||
|
self.add_breakpoint_at_filename_line(view, filename, line, region)
|
||||||
|
|
||||||
|
def run_to_file_at_line(self, filename, line):
|
||||||
|
buff = self.begin_command(COMMAND_RUN_TO_FILE_AT_LINE)
|
||||||
|
buff.write(ctypes.c_uint16(len(filename)))
|
||||||
|
buff.write(bytes(filename, 'utf-8'))
|
||||||
|
buff.write(ctypes.c_uint32(line))
|
||||||
|
buff, result_code = self.end_command(buff)
|
||||||
|
|
||||||
|
def goto_file_at_line(self, filename, line):
|
||||||
|
buff = self.begin_command(COMMAND_GOTO_FILE_AT_LINE)
|
||||||
|
buff.write(ctypes.c_uint16(len(filename)))
|
||||||
|
buff.write(bytes(filename, 'utf-8'))
|
||||||
|
buff.write(ctypes.c_uint32(line))
|
||||||
|
buff, result_code = self.end_command(buff)
|
||||||
|
|
||||||
|
def get_target_state(self):
|
||||||
|
buff = self.begin_command(COMMAND_GET_TARGET_STATE)
|
||||||
|
buff, result_code = self.end_command(buff)
|
||||||
|
if result_code == 1:
|
||||||
|
return int.from_bytes(buff.read(2), 'little')
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return 1
|
def add_watch(self, expr):
|
||||||
|
buff = self.begin_command(COMMAND_ADD_WATCH)
|
||||||
|
buff.write(ctypes.c_uint8(1)) # watch window 1
|
||||||
|
buff.write(ctypes.c_uint16(len(expr)))
|
||||||
|
buff.write(bytes(expr, 'utf-8'))
|
||||||
|
buff.write(ctypes.c_uint16(0))
|
||||||
|
buff, result_code = self.end_command(buff)
|
||||||
|
if result_code == 1:
|
||||||
|
return int.from_bytes(buff.read(4), 'little')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def send_command(self, cmd):
|
||||||
|
buff = self.begin_command(cmd)
|
||||||
|
if cmd == COMMAND_START_DEBUGGING:
|
||||||
|
buff.write(ctypes.c_uint8(0))
|
||||||
|
buff, result_code = self.end_command(buff)
|
||||||
|
|
||||||
|
def stop_debugging(self):
|
||||||
|
if self.get_target_state() != TARGETSTATE_NONE:
|
||||||
|
self.send_command(COMMAND_STOP_DEBUGGING)
|
||||||
|
|
||||||
def close(self, stop=True):
|
def close(self, stop=True):
|
||||||
if stop:
|
if stop:
|
||||||
@@ -122,6 +134,10 @@ class RemedyInstance:
|
|||||||
self.process.kill()
|
self.process.kill()
|
||||||
self.process = None
|
self.process = None
|
||||||
|
|
||||||
|
for bp in self.breakpoints.keys():
|
||||||
|
erase_regions(bp)
|
||||||
|
self.breakpoints = {}
|
||||||
|
|
||||||
print("RemedyBG: Connection closed")
|
print("RemedyBG: Connection closed")
|
||||||
|
|
||||||
def try_launching(self):
|
def try_launching(self):
|
||||||
@@ -246,22 +262,23 @@ class RemedyInstance:
|
|||||||
window = sublime.active_window()
|
window = sublime.active_window()
|
||||||
view = window.active_view()
|
view = window.active_view()
|
||||||
line = view.rowcol(view.sel()[0].b)[0] + 1
|
line = view.rowcol(view.sel()[0].b)[0] + 1
|
||||||
file = view.file_name()
|
filename = view.file_name()
|
||||||
self.send_command(COMMAND_RUN_TO_FILE_AT_LINE, filename=file, line=line)
|
self.run_to_file_at_line(filename, line)
|
||||||
|
|
||||||
def goto_cursor(self):
|
def goto_cursor(self):
|
||||||
window = sublime.active_window()
|
window = sublime.active_window()
|
||||||
view = window.active_view()
|
view = window.active_view()
|
||||||
line = view.rowcol(view.sel()[0].b)[0] + 1
|
line = view.rowcol(view.sel()[0].b)[0] + 1
|
||||||
file = view.file_name()
|
filename = view.file_name()
|
||||||
self.send_command(COMMAND_GOTO_FILE_AT_LINE, filename=file, line=line)
|
self.goto_file_at_line(filename, line)
|
||||||
|
|
||||||
def breakpoint_on_cursor(self):
|
def breakpoint_on_cursor(self):
|
||||||
window = sublime.active_window()
|
window = sublime.active_window()
|
||||||
view = window.active_view()
|
view = window.active_view()
|
||||||
line = view.rowcol(view.sel()[0].b)[0] + 1
|
sel = view.sel()[0].b
|
||||||
file = view.file_name()
|
line = view.rowcol(sel)[0] + 1
|
||||||
self.send_command(COMMAND_ADD_BREAKPOINT_AT_FILENAME_LINE, filename=file, line=line)
|
filename = view.file_name()
|
||||||
|
self.toggle_breakpoint(view, filename, line, sublime.Region(sel))
|
||||||
|
|
||||||
remedy_instance = RemedyInstance()
|
remedy_instance = RemedyInstance()
|
||||||
|
|
||||||
@@ -271,15 +288,6 @@ def get_remedy_executable():
|
|||||||
result = settings.get("executable", "remedybg")
|
result = settings.get("executable", "remedybg")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def execute_process(view, cmd, offset = 1):
|
|
||||||
line = view.rowcol(view.sel()[0].b)[0] + offset
|
|
||||||
line = str(line)
|
|
||||||
file = view.file_name()
|
|
||||||
window = sublime.active_window()
|
|
||||||
cmd = sublime.expand_variables(cmd, {"file": file, "line": line, "remedybg": get_remedy_executable()})
|
|
||||||
print(cmd)
|
|
||||||
subprocess.Popen(cmd)
|
|
||||||
|
|
||||||
def get_build_system(window):
|
def get_build_system(window):
|
||||||
project = window.project_data()
|
project = window.project_data()
|
||||||
build = None
|
build = None
|
||||||
@@ -371,7 +379,7 @@ class RemedyStartDebuggingCommand(sublime_plugin.WindowCommand):
|
|||||||
def run(self):
|
def run(self):
|
||||||
if remedy_instance.try_launching(): return
|
if remedy_instance.try_launching(): return
|
||||||
|
|
||||||
state = remedy_instance.send_command(COMMAND_GET_TARGET_STATE)
|
state = remedy_instance.get_target_state()
|
||||||
if state == TARGETSTATE_NONE:
|
if state == TARGETSTATE_NONE:
|
||||||
if should_build_before_debugging(self.window):
|
if should_build_before_debugging(self.window):
|
||||||
self.window.run_command("remedy_build", {"command": "start_debugging"})
|
self.window.run_command("remedy_build", {"command": "start_debugging"})
|
||||||
@@ -380,11 +388,10 @@ class RemedyStartDebuggingCommand(sublime_plugin.WindowCommand):
|
|||||||
elif state == TARGETSTATE_SUSPENDED:
|
elif state == TARGETSTATE_SUSPENDED:
|
||||||
remedy_instance.send_command(COMMAND_CONTINUE_EXECUTION)
|
remedy_instance.send_command(COMMAND_CONTINUE_EXECUTION)
|
||||||
|
|
||||||
|
|
||||||
class RemedyStopDebuggingCommand(sublime_plugin.WindowCommand):
|
class RemedyStopDebuggingCommand(sublime_plugin.WindowCommand):
|
||||||
def run(self):
|
def run(self):
|
||||||
if remedy_instance.try_launching(): return
|
if remedy_instance.try_launching(): return
|
||||||
remedy_instance.send_command(COMMAND_STOP_DEBUGGING)
|
remedy_instance.stop_debugging()
|
||||||
|
|
||||||
class RemedyRestartDebuggingCommand(sublime_plugin.WindowCommand):
|
class RemedyRestartDebuggingCommand(sublime_plugin.WindowCommand):
|
||||||
def run(self):
|
def run(self):
|
||||||
@@ -426,7 +433,7 @@ class RemedyAddToWatchCommand(sublime_plugin.TextCommand):
|
|||||||
region_cursor = self.view.word(region_cursor)
|
region_cursor = self.view.word(region_cursor)
|
||||||
settings.set("word_separators", old_boundaries)
|
settings.set("word_separators", old_boundaries)
|
||||||
|
|
||||||
remedy_instance.send_command(COMMAND_ADD_WATCH, expr=self.view.substr(region_cursor))
|
remedy_instance.add_watch(self.view.substr(region_cursor))
|
||||||
|
|
||||||
|
|
||||||
class RemedyAllInOneCommand(sublime_plugin.TextCommand):
|
class RemedyAllInOneCommand(sublime_plugin.TextCommand):
|
||||||
@@ -452,7 +459,7 @@ class RemedyAllInOneCommand(sublime_plugin.TextCommand):
|
|||||||
remedy_instance.send_command(COMMAND_START_DEBUGGING)
|
remedy_instance.send_command(COMMAND_START_DEBUGGING)
|
||||||
self.view.replace(edit, region_word_on_cursor, "")
|
self.view.replace(edit, region_word_on_cursor, "")
|
||||||
elif content == "rr":
|
elif content == "rr":
|
||||||
remedy_instance.send_command(COMMAND_STOP_DEBUGGING)
|
remedy_instance.stop_debugging()
|
||||||
self.view.replace(edit, region_word_on_cursor, "")
|
self.view.replace(edit, region_word_on_cursor, "")
|
||||||
elif content == "rrr":
|
elif content == "rrr":
|
||||||
remedy_instance.send_command(COMMAND_RESTART_DEBUGGING)
|
remedy_instance.send_command(COMMAND_RESTART_DEBUGGING)
|
||||||
@@ -461,5 +468,11 @@ class RemedyAllInOneCommand(sublime_plugin.TextCommand):
|
|||||||
remedy_instance.run_to_cursor()
|
remedy_instance.run_to_cursor()
|
||||||
self.view.replace(edit, region_word_on_cursor, "")
|
self.view.replace(edit, region_word_on_cursor, "")
|
||||||
else:
|
else:
|
||||||
remedy_instance.send_command(COMMAND_ADD_WATCH, expr=content)
|
remedy_instance.add_watch(content)
|
||||||
|
|
||||||
|
class RemedyOnBuildCommand(sublime_plugin.EventListener):
|
||||||
|
def on_window_command(self, window, command_name, args):
|
||||||
|
if command_name in ["build", "remedy_build"]:
|
||||||
|
settings = sublime.load_settings("Remedy.sublime-settings")
|
||||||
|
if settings.get("stop_debugging_on_build_command", False):
|
||||||
|
remedy_instance.stop_debugging()
|
||||||
|
|||||||
Reference in New Issue
Block a user