Init repository

This commit is contained in:
Krzosa Karol
2023-01-22 10:31:55 +01:00
commit 6ffb2aed80
7 changed files with 681 additions and 0 deletions

30
Default.sublime-commands Normal file
View 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
View 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
View File

@@ -0,0 +1,9 @@
[
{
"button": "button3",
"count": 1,
"modifiers": [],
"command": "remedy_all_in_one",
"press_command": "drag_select"
}
]

7
dependencies.json Normal file
View File

@@ -0,0 +1,7 @@
{
"windows": {
"*": [
"python-pywin32"
]
}
}

438
remedy.py Normal file
View 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
View 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
View 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()