forked from adampresley/sublime-view-in-browser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ViewInBrowserCommand.py
261 lines (219 loc) · 7.95 KB
/
ViewInBrowserCommand.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#
# History:
#
# 03/11/2016:
# - Fix issue where parenthesis in paths would cause a failure to load. Solves #52
#
# 10/06/2014:
# - Rewrite for version 2.0.0
# - Using subprocess instead of webbrowser. Seems to solve #19
# - Smaller, simplier sublime-settings file
#
# 05/15/2014:
# - Current view only saves if there are modifications
#
# 07/03/2013:
# - Changes to support Sublime Text 3 and Python 3
#
# 06/15/2013:
# - Forward slashes in paths on Windows are now converted prior to opening using local server path
#
# 03/07/2013:
# - Changed loading of settings so that getting shell folders for Windows is only called on a Windows platform
#
# 01/30/2013:
# - Changed to use the sublime-setting tiered loading scheme. This allow users to override
# settings in their own user file in the User directory
#
# 11/01/2012:
# - Altered command to open Safari on Mac
# - When invoked the current view is auto-saved
#
# 10/25/2012:
# - New settings.json file to map browser/commands to OSes
# - Plugin will use the specified browser to open files, or default to OS default when browser is unsupported
# - Addressed encoding issue when calling open_new_tab
# - Added ability to specify and respect local server config per project
#
# 05/21/2012:
# - Temp file only created if view is unsaved
#
# 05/18/2012:
# - Initial code
#
import os
import sys
import re
import json
import urllib
import sublime
import tempfile
import subprocess
import sublime_plugin
import webbrowser
PLUGIN_VERSION = "2.0.0"
class ViewInBrowserCommand(sublime_plugin.TextCommand):
_pythonVersion = sys.version_info[0]
#
# Takes a Windows variable, such as %APPDATA% and get the
# proper path.
#
def expandWindowsUserShellFolder(self, command):
browserCommand = ""
windowsFolders = self.getWindowsUserShellFolders()
specialFolder = re.sub(r"%([A-Za-z\s]+)%.*", "\\1", command)
if specialFolder != command:
expandedFolder = windowsFolders[specialFolder].replace("\\", "\\\\")
browserCommand = re.sub(r"%[A-Za-z\s]+%(.*)", "%s\\1" % expandedFolder, command)
else:
browserCommand = command
return browserCommand.encode("ascii", "ignore") if self._pythonVersion < 3 else browserCommand
#
# Returns the correct base command.
#
def getBaseCommand(self, command, osName):
baseCommand = command
if osName == "nt":
baseCommand = self.expandWindowsUserShellFolder(baseCommand)
return baseCommand
#
# Return the name of the running operating system.
# i.e. darwin, nt, linux
#
def getOsName(self):
return os.name
#
# Get the current running platform. i.e.
# posix, win32
#
def getPlatform(self):
return sys.platform
#
# Thanks to the Python for Windows site for this snippet.
# http://win32com.goermezer.de/content/view/221/285/
#
def getWindowsUserShellFolders(self):
# Routine to grab all the Windows Shell Folder locations from the registry. If successful, returns dictionary
# of shell folder locations indexed on Windows keyword for each; otherwise, returns an empty dictionary.
if self._pythonVersion < 3:
import _winreg
else:
import winreg as _winreg
return_dict = {}
# First open the registry hive
try:
Hive = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER)
except WindowsError:
print("Can't connect to registry hive HKEY_CURRENT_USER.")
return return_dict
# Then open the registry key where Windows stores the Shell Folder locations
try:
Key = _winreg.OpenKey(Hive, "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
except WindowsError:
print("Can't open registry key Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders.")
_winreg.CloseKey(Hive)
return return_dict
# Nothing failed above, so enumerate through all the Shell Folder values and return in a dictionary
# This relies on error at end of
try:
for i in range(0, _winreg.QueryInfoKey(Key)[1]):
name, value, val_type = _winreg.EnumValue(Key, i)
return_dict[name] = value.encode("ascii")
i += 1
_winreg.CloseKey(Key) # Only use with for loop
_winreg.CloseKey(Hive) # Only use with for loop
return return_dict # Only use with for loop
except WindowsError:
# In case of failure before read completed, don't return partial results
_winreg.CloseKey(Key)
_winreg.CloseKey(Hive)
return {}
def giveFileAProjectPath(self, fileToOpen, basePath, baseUrl):
return re.sub(r"\\", "/", fileToOpen.replace(basePath, baseUrl)).replace(" ", "%20").replace("(", "%28").replace(")", "%29")
def loadPluginSettings(self, defaultBrowser):
result = {
"browser": "",
"baseCommand": ""
}
#
# Load default/user settings. The browser choice may
# be overridden by custom commands.
#
settings = sublime.load_settings("View In Browser.sublime-settings")
if not defaultBrowser:
result["browser"] = settings.get("browser")
else:
result["browser"] = defaultBrowser
#
# Get the correct command based on platform and OS
#
osName = self.getOsName()
platform = self.getPlatform()
selectedOs = settings.get(osName)
result["baseCommand"] = self.getBaseCommand(selectedOs[platform][result["browser"]], osName)
return result
def loadProjectSettings(self, view):
return view.settings().get("sublime-view-in-browser")
def normalizePath(self, fileToOpen):
fileToOpen = fileToOpen.replace("\\", "/")
fileToOpen = "file:///%s" % fileToOpen.replace(" ", "%20").replace("(", "%28").replace(")", "%29")
return fileToOpen
def openBrowser(self, command, osName):
useShell = False if osName != "posix" else True
subprocess.Popen(command, shell=useShell)
def run(self, edit, browser=None):
print("View In Browser plugin v{0}, Python {1}".format(PLUGIN_VERSION, self._pythonVersion))
#
# Load plugin settings and project settings, if any. A project settings may
# affect the file to open based on local server
# environment settings.
#
pluginSettings = self.loadPluginSettings(browser)
projectSettings = self.loadProjectSettings(self.view)
fileToOpen = self.view.file_name()
#
# If we've specified settings for a local server environment
# use them
#
if projectSettings:
fileToOpen = self.giveFileAProjectPath(fileToOpen, projectSettings["basePath"], projectSettings["baseUrl"])
#
# If the current view has not been saved, put it into
# a temp file and open that instead. If the view
# DOES have a name make sure it is save before
# opening.
#
if fileToOpen == None:
fileToOpen = self.normalizePath(self.saveCurrentViewInTempFile(self.view))
else:
if self.view.is_dirty():
print("File %s is dirty. Saving..." % (fileToOpen,))
self.view.window().run_command("save")
if not projectSettings:
fileToOpen = self.normalizePath(fileToOpen)
#
# And open. If the settings file contains a valid selected browser use that
# command to open this file. Otherwise use the system default.
#
if pluginSettings["baseCommand"]:
command = "%s %s" % (pluginSettings["baseCommand"], fileToOpen.decode().encode(sys.getfilesystemencoding()) if self._pythonVersion < 3 else fileToOpen,)
print(command)
self.openBrowser(command, self.getOsName())
else:
if self._pythonVersion < 3:
webbrowser.open_new_tab(fileToOpen.encode(sys.getfilesystemencoding()))
else:
webbrowser.open_new_tab(fileToOpen)
def saveCurrentViewInTempFile(self, view):
#
# Create a temporary file to hold our contents
#
tempFile = tempfile.NamedTemporaryFile(suffix = ".htm", delete = False)
#
# Get the contents of the current view
#
region = sublime.Region(0, view.size())
text = view.substr(region)
tempFile.write(text.encode("utf-8"))
tempFile.close()
return tempFile.name