Init repository
This commit is contained in:
30
Default.sublime-commands
Normal file
30
Default.sublime-commands
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"caption": "RemedyBG: Launch",
|
||||||
|
"command": "remedy_launch",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "RemedyBG: Goto the sublime cursor in remedy",
|
||||||
|
"command": "remedy_go_to_cursor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "RemedyBG: Start debugging",
|
||||||
|
"command": "remedy_start_debugging",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "RemedyBG: Stop debugging",
|
||||||
|
"command": "remedy_stop_debugging",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "RemedyBG: Run to cursor, launch and stop at cursor",
|
||||||
|
"command": "remedy_run_to_cursor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "RemedyBG: Restart debugging",
|
||||||
|
"command": "remedy_restart_debugging",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "RemedyBG: Add selection or word under cursor to watch window",
|
||||||
|
"command": "remedy_restart_debugging",
|
||||||
|
},
|
||||||
|
]
|
||||||
7
Default.sublime-keymap
Normal file
7
Default.sublime-keymap
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
{ "keys": ["ctrl+f10"], "command": "remedy_run_to_cursor" },
|
||||||
|
{ "keys": ["f5"], "command": "remedy_start_debugging" },
|
||||||
|
{ "keys": ["shift+f5"], "command": "remedy_stop_debugging" },
|
||||||
|
{ "keys": ["ctrl+shift+f5"], "command": "remedy_restart_debugging" },
|
||||||
|
{ "keys": ["ctrl+t"], "command": "remedy_all_in_one" },
|
||||||
|
]
|
||||||
9
Default.sublime-mousemap
Normal file
9
Default.sublime-mousemap
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"button": "button3",
|
||||||
|
"count": 1,
|
||||||
|
"modifiers": [],
|
||||||
|
"command": "remedy_all_in_one",
|
||||||
|
"press_command": "drag_select"
|
||||||
|
}
|
||||||
|
]
|
||||||
7
dependencies.json
Normal file
7
dependencies.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"windows": {
|
||||||
|
"*": [
|
||||||
|
"python-pywin32"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
438
remedy.py
Normal file
438
remedy.py
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
import subprocess
|
||||||
|
import os, io, ctypes
|
||||||
|
|
||||||
|
import sublime
|
||||||
|
import sublime_plugin
|
||||||
|
from Default.exec import ExecCommand
|
||||||
|
|
||||||
|
import win32pipe, win32file, pywintypes
|
||||||
|
from .remedy_api import *
|
||||||
|
|
||||||
|
class RemedyInstance:
|
||||||
|
def __init__(self):
|
||||||
|
self.cmd_pipe = None
|
||||||
|
self.event_pipe = None
|
||||||
|
self.process = None
|
||||||
|
self.servername = ""
|
||||||
|
|
||||||
|
def send_command(self, cmd, **cmd_args):
|
||||||
|
if self.cmd_pipe is None: return 0
|
||||||
|
|
||||||
|
cmd_buffer = io.BytesIO()
|
||||||
|
cmd_buffer.write(ctypes.c_uint16(cmd))
|
||||||
|
|
||||||
|
if cmd == COMMAND_ADD_BREAKPOINT_AT_FILENAME_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']))
|
||||||
|
cmd_buffer.write(ctypes.c_uint16(0))
|
||||||
|
elif cmd == COMMAND_DELETE_BREAKPOINT:
|
||||||
|
if cmd_args['id'] in self.breakpoints:
|
||||||
|
rdbg_id = self.breakpoints[cmd_args['id']]
|
||||||
|
cmd_buffer.write(ctypes.c_uint32(rdbg_id))
|
||||||
|
self.breakpoints.pop(cmd_args['id'])
|
||||||
|
if rdbg_id in self.breakpoints_rdbg:
|
||||||
|
self.breakpoints_rdbg.pop(rdbg_id)
|
||||||
|
else:
|
||||||
|
return 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:
|
||||||
|
print(cmd_args)
|
||||||
|
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_UPDATE_BREAKPOINT_LINE:
|
||||||
|
if cmd_args['id'] in self.breakpoints:
|
||||||
|
rdbg_id = self.breakpoints[cmd_args['id']]
|
||||||
|
cmd_buffer.write(ctypes.c_uint32(rdbg_id))
|
||||||
|
cmd_buffer.write(ctypes.c_uint32(cmd_args['line']))
|
||||||
|
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:
|
||||||
|
out_data = win32pipe.TransactNamedPipe(self.cmd_pipe, cmd_buffer.getvalue(), 8192, None)
|
||||||
|
except pywintypes.error as pipe_error:
|
||||||
|
print('RDBG', pipe_error)
|
||||||
|
self.close(stop=False)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
out_buffer = io.BytesIO(out_data[1])
|
||||||
|
result_code = int.from_bytes(out_buffer.read(2), 'little')
|
||||||
|
if result_code == 1:
|
||||||
|
if cmd == COMMAND_ADD_BREAKPOINT_AT_FILENAME_LINE:
|
||||||
|
return 0
|
||||||
|
# bp_id = int.from_bytes(out_buffer.read(4), 'little')
|
||||||
|
# if bp_id not in self.breakpoints_rdbg:
|
||||||
|
# self.breakpoints[cmd_args['id']] = bp_id
|
||||||
|
# self.breakpoints_rdbg[bp_id] = (cmd_args['id'], cmd_args['filename'], cmd_args['line'])
|
||||||
|
# else:
|
||||||
|
# print('RDBG: Breakpoint (%i) %s@%i skipped, because it will not get triggered' % (cmd_args['id'], cmd_args['filename'], cmd_args['line']))
|
||||||
|
# self.ignore_next_remove_breakpoint = True
|
||||||
|
# Editor.RemoveBreakpointById(cmd_args['id'])
|
||||||
|
# return bp_id
|
||||||
|
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('RDBG: ' + str(cmd) + ' failed')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def close(self, stop=True):
|
||||||
|
if stop:
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
if self.cmd_pipe:
|
||||||
|
win32file.CloseHandle(self.cmd_pipe)
|
||||||
|
self.cmd_pipe = None
|
||||||
|
|
||||||
|
if self.event_pipe is not None:
|
||||||
|
win32file.CloseHandle(self.event_pipe)
|
||||||
|
self.event_pipe = None
|
||||||
|
|
||||||
|
if self.process is not None:
|
||||||
|
self.process.kill()
|
||||||
|
self.process = None
|
||||||
|
|
||||||
|
print("RDBG: Connection closed")
|
||||||
|
|
||||||
|
def try_launching(self):
|
||||||
|
if self.process == None:
|
||||||
|
self.figure_out_target_and_launch()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def cmd_pipe_name(self):
|
||||||
|
return "\\\\.\\pipe\\" + self.servername
|
||||||
|
|
||||||
|
def event_pipe_name(self):
|
||||||
|
return "\\\\.\\pipe\\" + self.servername + "-events"
|
||||||
|
|
||||||
|
def figure_out_target_and_launch(self):
|
||||||
|
self.window = sublime.active_window()
|
||||||
|
|
||||||
|
remedy_target = None
|
||||||
|
if remedy_target == None:
|
||||||
|
project = self.window.project_data()
|
||||||
|
if project and project.get("remedy_target"):
|
||||||
|
remedy_target = project.get("remedy_target")
|
||||||
|
|
||||||
|
if remedy_target:
|
||||||
|
self.launch(remedy_target)
|
||||||
|
|
||||||
|
if remedy_target == None:
|
||||||
|
vars = self.window.extract_variables()
|
||||||
|
self.current_dir = vars.get("project_path")
|
||||||
|
if self.current_dir == None:
|
||||||
|
self.current_dir = vars.get("folder")
|
||||||
|
if self.current_dir == None:
|
||||||
|
self.current_dir = vars.get("file_path")
|
||||||
|
if self.current_dir == None:
|
||||||
|
sublime.message_dialog("RemedyBG: Trying to launch but cant figure out starting directory, open a file or project")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.filelist = os.listdir(self.current_dir)
|
||||||
|
def walk_the_user_to_executable(item_index):
|
||||||
|
if item_index == -1:
|
||||||
|
return
|
||||||
|
item = self.filelist[item_index]
|
||||||
|
item_path = self.current_dir + "/" + item
|
||||||
|
if os.path.isdir(item_path):
|
||||||
|
self.current_dir += "/" + item
|
||||||
|
self.filelist = os.listdir(self.current_dir)
|
||||||
|
self.window.show_quick_panel(self.filelist, walk_the_user_to_executable)
|
||||||
|
elif os.path.isfile(item_path):
|
||||||
|
self.launch(item_path)
|
||||||
|
self.window.show_quick_panel(self.filelist, walk_the_user_to_executable)
|
||||||
|
|
||||||
|
def launch(self, target):
|
||||||
|
try:
|
||||||
|
self.servername = "default"
|
||||||
|
window = sublime.active_window()
|
||||||
|
vars = window.extract_variables()
|
||||||
|
project = vars.get("project_base_name")
|
||||||
|
if project:
|
||||||
|
self.servername = project + hex(hash(vars["project"]))
|
||||||
|
else:
|
||||||
|
folder = vars.get("folder")
|
||||||
|
if folder:
|
||||||
|
self.servername = hex(hash(folder))
|
||||||
|
print("RemedyBG: Server name = ", self.servername)
|
||||||
|
|
||||||
|
|
||||||
|
cmd = [get_remedy_executable(), "--servername", self.servername, target]
|
||||||
|
print("Launching Remedy with command: " + str(cmd))
|
||||||
|
self.process = subprocess.Popen(cmd)
|
||||||
|
|
||||||
|
import time
|
||||||
|
wait_time = 0.1
|
||||||
|
time.sleep(wait_time)
|
||||||
|
pipe_success = False
|
||||||
|
for retry in range(0, 5):
|
||||||
|
try:
|
||||||
|
self.cmd_pipe = win32file.CreateFile(self.cmd_pipe_name(), win32file.GENERIC_READ|win32file.GENERIC_WRITE, \
|
||||||
|
0, None, win32file.OPEN_EXISTING, 0, None)
|
||||||
|
except pywintypes.error:
|
||||||
|
time.sleep(wait_time)
|
||||||
|
wait_time = wait_time*2.0
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
sublime.error_message('RemedyBG: Pipe error:' + str(e))
|
||||||
|
return False
|
||||||
|
pipe_success = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not pipe_success:
|
||||||
|
sublime.error_message('RemedyBG: Named pipe could not be opened to remedybg. Make sure remedybg version is above 0.3.8')
|
||||||
|
return False
|
||||||
|
|
||||||
|
win32pipe.SetNamedPipeHandleState(self.cmd_pipe, win32pipe.PIPE_READMODE_MESSAGE, None, None)
|
||||||
|
|
||||||
|
assert self.event_pipe == None
|
||||||
|
self.event_pipe = win32file.CreateFile(self.event_pipe_name(), win32file.GENERIC_READ|256, \
|
||||||
|
0, None, win32file.OPEN_EXISTING, 0, None)
|
||||||
|
win32pipe.SetNamedPipeHandleState(self.event_pipe, win32pipe.PIPE_READMODE_MESSAGE, None, None)
|
||||||
|
|
||||||
|
print("RemedyBG: Connected")
|
||||||
|
|
||||||
|
def update():
|
||||||
|
global remedy_instance
|
||||||
|
if self.process is None:
|
||||||
|
return
|
||||||
|
if self.process is not None and self.process.poll() is not None:
|
||||||
|
print('RemedyBG: quit with code: %i' % (self.process.poll()))
|
||||||
|
self.process = None
|
||||||
|
self.close(stop=False)
|
||||||
|
return
|
||||||
|
|
||||||
|
sublime.set_timeout(update, 1000)
|
||||||
|
sublime.set_timeout(update, 1000)
|
||||||
|
except FileNotFoundError as not_found:
|
||||||
|
sublime.error_message("RemedyBG: " + str(not_found) + ': ' + target)
|
||||||
|
except pywintypes.error as connection_error:
|
||||||
|
sublime.error_message("RemedyBG: " + str(connection_error))
|
||||||
|
except OSError as os_error:
|
||||||
|
sublime.error_message("RemedyBG: " + str(os_error))
|
||||||
|
|
||||||
|
def run_to_cursor(self):
|
||||||
|
window = sublime.active_window()
|
||||||
|
view = window.active_view()
|
||||||
|
line = view.rowcol(view.sel()[0].b)[0] + 1
|
||||||
|
file = view.file_name()
|
||||||
|
self.send_command(COMMAND_RUN_TO_FILE_AT_LINE, filename=file, line=line)
|
||||||
|
|
||||||
|
def goto_cursor(self):
|
||||||
|
window = sublime.active_window()
|
||||||
|
view = window.active_view()
|
||||||
|
line = view.rowcol(view.sel()[0].b)[0] + 1
|
||||||
|
file = view.file_name()
|
||||||
|
self.send_command(COMMAND_GOTO_FILE_AT_LINE, filename=file, line=line)
|
||||||
|
|
||||||
|
|
||||||
|
remedy_instance = RemedyInstance()
|
||||||
|
|
||||||
|
def get_remedy_executable():
|
||||||
|
window = sublime.active_window()
|
||||||
|
settings = window.settings()
|
||||||
|
result = settings.get("remedy_executable")
|
||||||
|
if result == None:
|
||||||
|
result = "remedybg"
|
||||||
|
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)
|
||||||
|
|
||||||
|
class RemedyBuildCommand(ExecCommand):
|
||||||
|
def run(self, **kwargs):
|
||||||
|
self.command = kwargs.get("command")
|
||||||
|
if self.command == None:
|
||||||
|
sublime.message_dialog("RemedyBG: remedy_build expects a command, one of [run_to_cursor, start_debugging, goto_cursor]\n\nexample :: \"args\":{\"command\": \"run_to_cursor\"}")
|
||||||
|
|
||||||
|
project = self.window.project_data()
|
||||||
|
build = None
|
||||||
|
if project:
|
||||||
|
bs = project.get("build_systems")
|
||||||
|
rbs = project.get("remedy_build_system")
|
||||||
|
if bs:
|
||||||
|
if len(bs) == 1:
|
||||||
|
build = bs[0]
|
||||||
|
elif rbs:
|
||||||
|
for i in bs:
|
||||||
|
if rbs == i["name"]:
|
||||||
|
build = i
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
if project == None or build == None:
|
||||||
|
sublime.error_message("""
|
||||||
|
RemedyBG: You need a project and a build system inside that project to call this function,
|
||||||
|
Sublime API doesnt allow for querying the selected build system.
|
||||||
|
Look here to figure out the project format: https://www.sublimetext.com/docs/projects.html
|
||||||
|
Additionally you need a field called "remedy_build_system" to signal which
|
||||||
|
build system was chosen
|
||||||
|
""")
|
||||||
|
return
|
||||||
|
|
||||||
|
if remedy_instance.try_launching():
|
||||||
|
return
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
"cmd": build.get("cmd", None),
|
||||||
|
"shell_cmd": build.get("shell_cmd", None),
|
||||||
|
"file_regex": build.get("file_regex", ""),
|
||||||
|
"line_regex": build.get("line_regex", ""),
|
||||||
|
"working_dir": build.get("working_dir", ""),
|
||||||
|
"encoding": build.get("encoding", "utf-8"),
|
||||||
|
"env": build.get("env", {}),
|
||||||
|
"quiet": build.get("quiet", False),
|
||||||
|
"kill": build.get("kill", False),
|
||||||
|
"kill_previous": build.get("kill_previous", False),
|
||||||
|
"update_annotations_only": build.get("update_annotations_only", False),
|
||||||
|
"word_wrap": build.get("word_wrap", True),
|
||||||
|
"syntax": build.get("syntax", "Packages/Text/Plain text.tmLanguage"),
|
||||||
|
}
|
||||||
|
super().run(**kwargs)
|
||||||
|
def on_finished(self, proc):
|
||||||
|
super().on_finished(proc)
|
||||||
|
if self.command == "run_to_cursor":
|
||||||
|
remedy_instance.run_to_cursor()
|
||||||
|
elif self.command == "start_debugging":
|
||||||
|
remedy_instance.send_command(COMMAND_START_DEBUGGING)
|
||||||
|
elif self.command == "goto_cursor":
|
||||||
|
remedy_instance.goto_cursor()
|
||||||
|
else: # @warning: While adding here also need to change error message !!!!
|
||||||
|
sublime.message_dialog("RemedyBG: Unrecognized command =", self.command)
|
||||||
|
|
||||||
|
class RemedyLaunchCommand(sublime_plugin.WindowCommand):
|
||||||
|
def run(self):
|
||||||
|
remedy_instance.figure_out_target_and_launch()
|
||||||
|
|
||||||
|
class RemedyStartDebuggingCommand(sublime_plugin.WindowCommand):
|
||||||
|
def run(self):
|
||||||
|
if remedy_instance.try_launching(): return
|
||||||
|
remedy_instance.send_command(COMMAND_START_DEBUGGING)
|
||||||
|
|
||||||
|
class RemedyStopDebuggingCommand(sublime_plugin.WindowCommand):
|
||||||
|
def run(self):
|
||||||
|
if remedy_instance.try_launching(): return
|
||||||
|
remedy_instance.send_command(COMMAND_STOP_DEBUGGING)
|
||||||
|
|
||||||
|
class RemedyRestartDebuggingCommand(sublime_plugin.WindowCommand):
|
||||||
|
def run(self):
|
||||||
|
if remedy_instance.try_launching(): return
|
||||||
|
remedy_instance.send_command(COMMAND_RESTART_DEBUGGING)
|
||||||
|
|
||||||
|
class RemedyRunToCursorCommand(sublime_plugin.TextCommand):
|
||||||
|
def run(self, edit):
|
||||||
|
if remedy_instance.try_launching(): return
|
||||||
|
remedy_instance.run_to_cursor()
|
||||||
|
|
||||||
|
class RemedyGotoCursorCommand(sublime_plugin.TextCommand):
|
||||||
|
def run(self, edit):
|
||||||
|
if remedy_instance.try_launching(): return
|
||||||
|
remedy_instance.goto_cursor()
|
||||||
|
|
||||||
|
class RemedyAddToWatchCommand(sublime_plugin.TextCommand):
|
||||||
|
def run(self, edit):
|
||||||
|
if remedy_instance.try_launching(): return
|
||||||
|
|
||||||
|
sel = self.view.sel()
|
||||||
|
if len(sel) > 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
region_cursor = sel[0]
|
||||||
|
if region_cursor.a - region_cursor.b == 0:
|
||||||
|
settings = self.view.settings()
|
||||||
|
old_boundaries = settings.get("word_separators")
|
||||||
|
settings.set("word_separators"," ;,")
|
||||||
|
region_cursor = self.view.word(region_cursor)
|
||||||
|
settings.set("word_separators", old_boundaries)
|
||||||
|
|
||||||
|
remedy_instance.send_command(COMMAND_ADD_WATCH, expr=self.view.substr(region_cursor))
|
||||||
|
|
||||||
|
|
||||||
|
class RemedyAllInOneCommand(sublime_plugin.TextCommand):
|
||||||
|
def run(self, edit):
|
||||||
|
if remedy_instance.try_launching():
|
||||||
|
return
|
||||||
|
|
||||||
|
sel = self.view.sel()
|
||||||
|
if len(sel) > 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
region_cursor = sel[0]
|
||||||
|
settings = self.view.settings()
|
||||||
|
old_boundaries = settings.get("word_separators")
|
||||||
|
settings.set("word_separators"," ;,")
|
||||||
|
region_word_on_cursor = self.view.word(region_cursor)
|
||||||
|
settings.set("word_separators", old_boundaries)
|
||||||
|
|
||||||
|
remedy_instance.goto_cursor()
|
||||||
|
|
||||||
|
content = self.view.substr(region_word_on_cursor)
|
||||||
|
if content == "r":
|
||||||
|
remedy_instance.send_command(COMMAND_START_DEBUGGING)
|
||||||
|
self.view.replace(edit, region_word_on_cursor, "")
|
||||||
|
elif content == "rr":
|
||||||
|
remedy_instance.send_command(COMMAND_STOP_DEBUGGING)
|
||||||
|
self.view.replace(edit, region_word_on_cursor, "")
|
||||||
|
elif content == "rrr":
|
||||||
|
remedy_instance.send_command(COMMAND_RESTART_DEBUGGING)
|
||||||
|
self.view.replace(edit, region_word_on_cursor, "")
|
||||||
|
elif content == "rt":
|
||||||
|
remedy_instance.run_to_cursor()
|
||||||
|
self.view.replace(edit, region_word_on_cursor, "")
|
||||||
|
else:
|
||||||
|
remedy_instance.send_command(COMMAND_ADD_WATCH, expr=content)
|
||||||
|
|
||||||
78
remedy_api.py
Normal file
78
remedy_api.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
TARGETSTATE_NONE = 1
|
||||||
|
TARGETSTATE_SUSPENDED = 2
|
||||||
|
TARGETSTATE_EXECUTING = 3
|
||||||
|
|
||||||
|
COMMAND_BRING_DEBUGGER_TO_FOREGROUND = 50
|
||||||
|
COMMAND_SET_WINDOW_POS = 51
|
||||||
|
COMMAND_GET_WINDOW_POS = 52
|
||||||
|
COMMAND_COMMAND_EXIT_DEBUGGER = 75
|
||||||
|
COMMAND_GET_IS_SESSION_MODIFIED = 100
|
||||||
|
COMMAND_GET_SESSION_FILENAME = 101
|
||||||
|
COMMAND_NEW_SESSION = 102
|
||||||
|
COMMAND_OPEN_SESSION = 103
|
||||||
|
COMMAND_SAVE_SESSION = 104
|
||||||
|
COMMAND_SAVE_AS_SESSION = 105
|
||||||
|
COMMAND_GOTO_FILE_AT_LINE = 200
|
||||||
|
COMMAND_CLOSE_FILE = 201
|
||||||
|
COMMAND_CLOSE_ALL_FILES = 202
|
||||||
|
COMMAND_GET_CURRENT_FILE = 203
|
||||||
|
COMMAND_GET_TARGET_STATE = 300
|
||||||
|
COMMAND_START_DEBUGGING = 301
|
||||||
|
COMMAND_STOP_DEBUGGING = 302
|
||||||
|
COMMAND_RESTART_DEBUGGING = 303
|
||||||
|
COMMAND_STEP_INTO_BY_LINE = 307
|
||||||
|
COMMAND_STEP_OVER_BY_LINE = 309
|
||||||
|
COMMAND_STEP_OUT = 311,
|
||||||
|
COMMAND_CONTINUE_EXECUTION = 312
|
||||||
|
COMMAND_RUN_TO_FILE_AT_LINE = 313
|
||||||
|
COMMAND_GET_BREAKPOINT_LOCATIONS = 601
|
||||||
|
COMMAND_ADD_BREAKPOINT_AT_FILENAME_LINE = 604
|
||||||
|
COMMAND_UPDATE_BREAKPOINT_LINE = 608
|
||||||
|
COMMAND_DELETE_BREAKPOINT = 610
|
||||||
|
COMMAND_DELETE_ALL_BREAKPOINTS = 611
|
||||||
|
COMMAND_ADD_WATCH = 701
|
||||||
|
|
||||||
|
BREAKPOINTKIND_FUNCTION_NAME = 1
|
||||||
|
BREAKPOINTKIND_FILENAME_LINE = 2
|
||||||
|
BREAKPOINTKIND_ADDRESS = 3
|
||||||
|
BREAKPOINTKIND_PROCESSOR = 4
|
||||||
|
|
||||||
|
COMMANDRESULT_UNKNOWN = 0
|
||||||
|
COMMANDRESULT_OK = 1
|
||||||
|
COMMANDRESULT_FAIL = 2
|
||||||
|
COMMANDRESULT_ABORTED = 3
|
||||||
|
COMMANDRESULT_INVALID_COMMAND = 4
|
||||||
|
COMMANDRESULT_BUFFER_TOO_SMALL = 5
|
||||||
|
COMMANDRESULT_FAILED_OPENING_FILE = 6
|
||||||
|
COMMANDRESULT_FAILED_SAVING_SESSION = 7
|
||||||
|
COMMANDRESULT_INVALID_ID = 8
|
||||||
|
COMMANDRESULT_INVALID_TARGET_STATE = 9
|
||||||
|
COMMANDRESULT_FAILED_NO_ACTIVE_CONFIG = 10
|
||||||
|
COMMANDRESULT_INVALID_BREAKPOINT_KIND = 11
|
||||||
|
|
||||||
|
SOURCELOCCHANGEDREASON_UNSPECIFIED = 0
|
||||||
|
SOURCELOCCHANGEDREASON_COMMAND_LINE = 1
|
||||||
|
SOURCELOCCHANGEDREASON_DRIVER = 2
|
||||||
|
SOURCELOCCHANGEDREASON_BREAKPOINT_SELECTED = 3
|
||||||
|
SOURCELOCCHANGEDREASON_CURRENT_FRAME_CHANGED = 4
|
||||||
|
SOURCELOCCHANGEDREASON_THREAD_CHANGED = 5
|
||||||
|
SOURCELOCCHANGEDREASON_BREAKPOINT_HIT = 6
|
||||||
|
SOURCELOCCHANGEDREASON_EXCEPTION_HIT = 7
|
||||||
|
SOURCELOCCHANGEDREASON_STEP_OVER = 8
|
||||||
|
SOURCELOCCHANGEDREASON_STEP_IN = 9
|
||||||
|
SOURCELOCCHANGEDREASON_STEP_OUT = 10
|
||||||
|
SOURCELOCCHANGEDREASON_NON_USER_BREAKPOINT = 11
|
||||||
|
SOURCELOCCHANGEDREASON_DEBUG_BREAK = 12
|
||||||
|
|
||||||
|
EVENTTYPE_EXIT_PROCESS = 100
|
||||||
|
EVENTTYPE_TARGET_STARTED = 101
|
||||||
|
EVENTTYPE_TARGET_ATTACHED = 102
|
||||||
|
EVENTTYPE_TARGET_DETACHED = 103
|
||||||
|
EVENTTYPE_TARGET_CONTINUED = 104
|
||||||
|
EVENTTYPE_KIND_BREAKPOINT_HIT = 600
|
||||||
|
EVENTTYPE_KIND_BREAKPOINT_RESOLVED = 601
|
||||||
|
EVENTTYPE_OUTPUT_DEBUG_STRING = 800
|
||||||
|
EVENTTYPE_BREAKPOINT_ADDED = 602
|
||||||
|
EVENTTYPE_BREAKPOINT_MODIFIED = 603
|
||||||
|
EVENTTYPE_BREAKPOINT_REMOVED = 604
|
||||||
|
EVENTTYPE_SOURCE_LOCATION_CHANGED = 200
|
||||||
112
setup_vsvars.py
Normal file
112
setup_vsvars.py
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import sublime
|
||||||
|
import sublime_plugin
|
||||||
|
|
||||||
|
from threading import Thread
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
from os import environ
|
||||||
|
|
||||||
|
# Related reading;
|
||||||
|
# https://stackoverflow.com/questions/39881091/how-to-run-sublimetext-with-visual-studio-environment-enabled/
|
||||||
|
|
||||||
|
# For the unfamiliar, Visual Studio ships with a batch file which sets up the
|
||||||
|
# environment variables you need to be able to run visual studio tools from a
|
||||||
|
# command prompt.
|
||||||
|
#
|
||||||
|
# This pluguin was written in response to someone that wanted to know how you
|
||||||
|
# could run Sublime and have it have the visual studio environment already set
|
||||||
|
# up.
|
||||||
|
#
|
||||||
|
# This plugin will use a subprocess to execute the batch file in the background
|
||||||
|
# and then issue the 'set' command to get the command interpreter to output the
|
||||||
|
# state of the environment before it exits.
|
||||||
|
#
|
||||||
|
# This output is gathered and parsed to come up with a dictionary similar to
|
||||||
|
# the environ table that python uses. From here we can easily detect what new
|
||||||
|
# environment variables were added and the values of those that changed, and
|
||||||
|
# set them as appropriate.
|
||||||
|
#
|
||||||
|
# As written Sublime needs to be restarted in order to execute the batch file
|
||||||
|
# again. A more elegant solution would be to save the environment prior to
|
||||||
|
# modifying it so that it could be restored and a new environment applied.
|
||||||
|
|
||||||
|
# To use this, you need to specify a setting in your user preferences named
|
||||||
|
# 'vc_vars_cmd' which should contain a complete path to the batch file you want
|
||||||
|
# to execute. Optionally you can also specify 'vc_vars_arch', which will be
|
||||||
|
# passed as a command line argument to the batch file executed. Remember that
|
||||||
|
# the preferences are JSON, so you need to quote all path separators.
|
||||||
|
|
||||||
|
SENTINEL="SUBL_VC_VARS"
|
||||||
|
|
||||||
|
def _get_vc_env():
|
||||||
|
"""
|
||||||
|
Run the batch file specified in the vc_vars_cmd setting (with an
|
||||||
|
optional architecture type) and return back a dictionary of the
|
||||||
|
environment that the batch file sets up.
|
||||||
|
|
||||||
|
Returns None if the preference is missing or the batch file fails.
|
||||||
|
"""
|
||||||
|
settings = sublime.load_settings("Preferences.sublime-settings")
|
||||||
|
vars_cmd = settings.get("vc_vars_cmd")
|
||||||
|
vars_arch = settings.get("vc_vars_arch", "amd64")
|
||||||
|
|
||||||
|
if vars_cmd is None:
|
||||||
|
print("set_vc_vars: Cannot set Visual Studio Environment")
|
||||||
|
print("set_vc_vars: Add 'vc_vars_cmd' setting to settings and restart")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Run the batch, outputting a sentinel value so we can separate out
|
||||||
|
# any error messages the batch might generate.
|
||||||
|
shell_cmd = "\"{0}\" {1} && echo {2} && set".format(
|
||||||
|
vars_cmd, vars_arch, SENTINEL)
|
||||||
|
|
||||||
|
output = Popen(shell_cmd, stdout=PIPE, shell=True).stdout.read()
|
||||||
|
|
||||||
|
lines = [line.strip() for line in output.decode("utf-8").splitlines()]
|
||||||
|
env_lines = lines[lines.index(SENTINEL) + 1:]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Convert from var=value to dictionary key/value pairs. We upper case the
|
||||||
|
# keys, since Python does that to the mapping it stores in environ.
|
||||||
|
env = {}
|
||||||
|
for env_var in env_lines:
|
||||||
|
parts = env_var.split("=", maxsplit=1)
|
||||||
|
env[parts[0].upper()] = parts[1]
|
||||||
|
|
||||||
|
return env
|
||||||
|
|
||||||
|
def install_vc_env():
|
||||||
|
"""
|
||||||
|
Try to collect the appropriate Visual Studio environment variables and
|
||||||
|
set them into the current environment.
|
||||||
|
"""
|
||||||
|
vc_env = _get_vc_env()
|
||||||
|
if vc_env is None:
|
||||||
|
print("set_vc_vars: Unable to fetch the Visual Studio Environment")
|
||||||
|
return sublime.status_message("Error fetching VS Environment")
|
||||||
|
|
||||||
|
# Add newly set environment variables
|
||||||
|
for key in vc_env.keys():
|
||||||
|
if key not in environ:
|
||||||
|
environ[key] = vc_env[key]
|
||||||
|
|
||||||
|
# Update existing variables whose values changed.
|
||||||
|
for key in environ:
|
||||||
|
if key in vc_env and environ[key] != vc_env[key]:
|
||||||
|
environ[key] = vc_env[key]
|
||||||
|
|
||||||
|
# Set a sentinel variable so we know not to try setting up the path again.
|
||||||
|
environ[SENTINEL] = "BOOTSTRAPPED"
|
||||||
|
sublime.status_message("VS Environment enabled")
|
||||||
|
|
||||||
|
def plugin_loaded():
|
||||||
|
if sublime.platform() != "windows":
|
||||||
|
return sublime.status_message("VS is not supported on this platform")
|
||||||
|
|
||||||
|
# To reload the environment if it changes, restart Sublime.
|
||||||
|
if SENTINEL in environ:
|
||||||
|
return sublime.status_message("VS Environment already enabled")
|
||||||
|
|
||||||
|
# Update in the background so we don't block the UI
|
||||||
|
Thread(target=install_vc_env).start()
|
||||||
Reference in New Issue
Block a user