-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlaunch.py
102 lines (82 loc) · 3.91 KB
/
launch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
102
import os, sublime, sublime_plugin, time, subprocess, functools
import re
class LaunchCommand(sublime_plugin.WindowCommand):
def run(self, command, cwd=None, variables={}):
# Populate variables if we don't have any
if not variables:
variables = self.populate_variables()
# Create a callback to be used if a replacement needs user input
def _input_callback(input):
variables[variable_name] = input
self.run(command, cwd, variables)
# Expand variables and ask for user input if necessary
try:
command = [self.expand_variables(arg, variables) for arg in command]
if cwd: cwd = self.expand_variables(cwd, variables)
except RequireUserInputError as e:
variable_name = e.name
self.window.show_input_panel('Launch Input: ' + e.prompt, e.default, _input_callback, None, None)
return
# We have clean params, launch it.
self.launch_it(command, cwd)
variables.clear()
# Inspired by sublime-text-shell-command
# Replaces variable tokens with their values or raises an exception for user input
def expand_variables(self, string, variables):
matches = re.findall(r'\${(.*?)}', string)
for variable_def in matches:
raw = '${' + variable_def + '}'
name, default, prompt = self.parse_variable(variable_def)
if not name in variables:
if prompt: raise RequireUserInputError(name, default, prompt)
if default: variables[name] = default
string = string.replace(raw, variables[name])
return string
def populate_variables(self):
view = self.window.active_view()
variables = {}
# Project variables
project = sublime.active_window().project_data()
if project:
if 'folders' in project:
# Add project folders
variables['project_folder'] = project['folders'][0]['path']
for i, folder in enumerate(project['folders']):
variables['project_folder[{0}]'.format(i)] = folder['path']
if 'launch_variables' in project:
# Merge project variables
variables.update(project['launch_variables'])
project_file = sublime.active_window().project_file_name()
if project_file:
variables['project'] = os.path.basename(os.path.splitext(project_file)[0])
# File variables
file = view.file_name()
if file:
variables['file'] = file
variables['file_path'] = os.path.split(file)[0]
variables['file_name'] = os.path.basename(file)
if project and ('folders' in project):
variables['file_project_path'] = os.path.relpath(file, project['folders'][0]['path'])
# Selected text variable
if (view.sel())[0].size() > 0:
# Combine all selections if there are more than one
variables['selected_text'] = functools.reduce((lambda a, b: a + view.substr(b)), view.sel(), '')
return variables
# Format: ${name:default:prompt}
def parse_variable(self, variable):
parts = variable.split(':')
return [parts[i] if i < len(parts) else None for i in range(3)]
def launch_it(self, command, cwd):
# Unfortunately we have to convert command to a string and add quotes to any strings with spaces
if sublime.platform() == "windows":
command = ' '.join(map(lambda c: '{!r}'.format(c) if ' ' in c else c, command))
print('Launching', command, *['in', cwd] if cwd else '')
try:
subprocess.Popen(command, cwd=cwd)
except Exception as e:
print('Error: ' + e.strerror)
class RequireUserInputError(Exception):
def __init__(self, name, default, prompt):
self.name = name
self.default = default
self.prompt = prompt