def _focus_zathura(self, pid): if which('xdotool') is not None: try: self._focus_xdotool(pid) return except: pass if which('wmctrl') is not None: try: self._focus_wmctrl(pid) except: pass
def get_sublime_exe(): ''' Utility function to get the full path to the currently executing Sublime instance. ''' processes = ['subl', 'sublime_text'] def check_processes(st2_dir=None): if st2_dir is None or os.path.exists(st2_dir): for process in processes: try: if st2_dir is not None: process = os.path.join(st2_dir, process) m = SUBLIME_VERSION.search( check_output([process, '-v'], use_texpath=False)) if m and m.group(1) == version: return process except: pass return None platform = sublime.platform() plat_settings = get_setting(platform, {}) sublime_executable = plat_settings.get('sublime_executable', None) if sublime_executable: return sublime_executable # we cache the results of the other checks, if possible if hasattr(get_sublime_exe, 'result'): return get_sublime_exe.result # are we on ST3 if hasattr(sublime, 'executable_path'): get_sublime_exe.result = sublime.executable_path() # on osx, the executable does not function the same as subl if platform == 'osx': get_sublime_exe.result = os.path.normpath( os.path.join(os.path.dirname(get_sublime_exe.result), '..', 'SharedSupport', 'bin', 'subl')) # on linux, it is preferable to use subl if it points to the # correct version see issue #710 for a case where this is useful elif (platform == 'linux' and not get_sublime_exe.result.endswith('subl')): subl = which('subl') if subl is not None: try: m = SUBLIME_VERSION.search( check_output([subl, '-v'], use_texpath=False)) if m and m.group(1) == sublime.version(): get_sublime_exe.result = subl except: pass return get_sublime_exe.result # in ST2 on Windows the Python executable is actually "sublime_text" elif platform == 'windows' and sys.executable != 'python' and \ os.path.isabs(sys.executable): get_sublime_exe.result = sys.executable return get_sublime_exe.result # guess-work for ST2 version = sublime.version() # hope its on the path result = check_processes() if result is not None: get_sublime_exe.result = result return result # guess the default location if platform == 'windows': st2_dir = os.path.expandvars('%PROGRAMFILES%\\Sublime Text 2') result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result elif platform == 'linux': for path in [ '$HOME/bin', '$HOME/sublime_text_2', '$HOME/sublime_text', '/opt/sublime_text_2', '/opt/sublime_text', '/usr/local/bin', '/usr/bin' ]: st2_dir = os.path.expandvars(path) result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result else: st2_dir = '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin' result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result try: folder = check_output( ['mdfind', '"kMDItemCFBundleIdentifier == com.sublimetext.2"'], use_texpath=False) st2_dir = os.path.join(folder, 'Contents', 'SharedSupport', 'bin') result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result except: pass print('Cannot determine the path to your Sublime installation. Please ' 'set the "sublime_executable" setting in your settings for your ' 'platform.') return None
def _on_main_thread(self, results): builder_name = get_setting( 'builder', 'traditional', view=self.view ) if builder_name in ['', 'default']: builder_name = 'traditional' builder_settings = get_setting('builder_settings', view=self.view) builder_path = get_setting('builder_path', view=self.view) if builder_name in ['simple', 'traditional', 'script']: builder_path = None else: bld_path = os.path.join(sublime.packages_path(), builder_path) add_plugin_path(bld_path) builder_name = _classname_to_internal_name(builder_name) try: get_plugin('{0}_builder'.format(builder_name)) builder_available = True except NoSuchPluginException: traceback.print_exc() builder_available = False results.append([ [u'Builder', u'Status'], [ builder_name, u'available' if builder_available else u'missing' ] ]) if builder_path: results.append([[u'Builder Path'], [builder_path]]) if builder_settings is not None: table = [[u'Builder Setting', u'Value']] for key in sorted(builder_settings.keys()): value = builder_settings[key] table.append([key, value]) results.append(table) # is current view a TeX file? view = self.view if view.score_selector(0, 'text.tex.latex') != 0: tex_root = get_tex_root(view) tex_directives = parse_tex_directives( tex_root, multi_values=['options'], key_maps={'ts-program': 'program'} ) results.append([[u'TeX Root'], [tex_root]]) results.append([ [u'LaTeX Engine'], [ tex_directives.get( 'program', get_setting( 'program', 'pdflatex', self.view ) ) ] ]) table = [[u'LaTeX Output Setting', u'Value']] output_directory = get_output_directory(view) if output_directory: table.append( ['output_directory', output_directory] ) aux_directory = get_aux_directory(view) if aux_directory: table.append(['aux_directory', aux_directory]) jobname = get_jobname(view) if jobname and jobname != os.path.splitext( os.path.basename(tex_root) )[0]: table.append(['jobname', jobname]) if len(table) > 1: results.append(table) options = get_setting('builder_settings', {}, self.view).\ get('options', []) if isinstance(options, strbase): options = [options] options.extend(tex_directives.get('options', [])) if len(options) > 0: table = [[u'LaTeX Options']] for option in options: table.append([option]) results.append(table) default_viewer = DEFAULT_VIEWERS.get(sublime.platform(), None) viewer_name = get_setting('viewer', default_viewer) if viewer_name in ['', 'default']: viewer_name = default_viewer try: viewer_plugin = get_plugin(viewer_name + '_viewer') viewer_available = True except NoSuchPluginException: viewer_available = False viewer_location = 'N/A' if viewer_available: if viewer_name == 'command': # assume the command viewer is always valid viewer_location = 'N/A' elif viewer_name in ('evince', 'okular', 'zathura'): viewer_location = which(viewer_name) viewer_available = bool(viewer_location) elif viewer_name == 'preview': viewer_location = '/Applications/Preview.app' if not os.path.exists(viewer_location): try: viewer_location = check_output([ 'osascript', '-e', 'POSIX path of ' '(path to app id "com.apple.Preview")' ], use_texpath=False) except subprocess.CalledProcessError: viewer_location = None viewer_available = False \ if not viewer_location else os.path.exists(viewer_location) elif viewer_name == 'skim': viewer_location = '/Applications/Skim.app' if not os.path.exists(viewer_location): try: viewer_location = check_output([ 'osascript', '-e', 'POSIX path of ' '(path to app id "net.sourceforge.skim-app.skim")' ], use_texpath=False) except subprocess.CalledProcessError: viewer_location = None viewer_available = False \ if not viewer_location else os.path.exists(viewer_location) elif viewer_name == 'sumatra': sumatra_exe = get_setting('viewer_settings', {}).\ get('sumatra', get_setting('windows', {}). get('sumatra', 'SumatraPDF.exe')) or \ 'SumatraPDF.exe' viewer_location = which(sumatra_exe) if not bool(viewer_location): viewer_location = viewer_plugin()._find_sumatra_exe() viewer_available = bool(viewer_location) if not viewer_available: viewer_location = 'N/A' results.append([ [u'Viewer', u'Status', u'Location'], [ viewer_name, u'available' if viewer_available else u'missing', viewer_location ] ]) if callable(self.on_done): self.on_done(results)
def run(self): texpath = self.texpath results = [] env = copy.deepcopy(os.environ) if texpath is not None: env['PATH'] = texpath if self.build_env is not None: update_environment(env, self.build_env) table = [ ['Variable', 'Value'] ] table.append(['PATH', env.get('PATH', '')]) if self.uses_miktex: get_tex_path_variable = get_tex_path_variable_miktex should_run = which('findtexmf', path=texpath) is not None else: get_tex_path_variable = get_tex_path_variable_texlive should_run = which('kpsewhich', path=texpath) is not None if should_run: for var in ['TEXINPUTS', 'BIBINPUTS', 'BSTINPUTS']: table.append([var, get_tex_path_variable(var, env)]) if self.uses_miktex: for var in ['BIBTEX', 'LATEX', 'PDFLATEX', 'MAKEINDEX', 'MAKEINFO', 'TEX', 'PDFTEX', 'TEXINDEX']: value = env.get(var, None) if value is not None: table.append([var, value]) results.append(table) table = [ ['Program', 'Location', 'Status', 'Version'] ] # skip sublime_exe on OS X # we only use this for the hack to re-focus on ST # which doesn't work on OS X anyway if sublime.platform() != 'osx': sublime_exe = self.sublime_exe available = sublime_exe is not None if available: if not os.path.isabs(sublime_exe): sublime_exe = which(sublime_exe) basename, extension = os.path.splitext(sublime_exe) if extension is not None: sublime_exe = ''.join((basename, extension.lower())) version_info = get_version_info( sublime_exe, env=env ) if available else None table.append([ 'sublime', sublime_exe if available and version_info is not None else u'', (u'available' if available and version_info is not None else u'missing'), version_info if version_info is not None else u'unavailable' ]) # a list of programs, each program is either a string or a list # of alternatives (e.g. 32/64 bit version) programs = [ 'latexmk' if not self.uses_miktex else 'texify', 'pdflatex', 'xelatex', 'lualatex', 'biber', 'bibtex', 'bibtex8', 'kpsewhich' ] if _HAS_PREVIEW: # ImageMagick requires gs to work with PDFs programs += [['magick', 'convert']] for program in programs: if isinstance(program, list): program_list = program program = program_list[0] location = None for p in program_list: location = which(p, path=texpath) if location is not None: program = p break else: location = which(program, path=texpath) # convert.exe on Windows can refer to %sysroot%\convert.exe, # which should not be used; in that case, simple report magick.exe # as not existing if program == 'convert' and sublime.platform() == 'windows': system_root = get_system_root().lower() if location.lower().startswith(system_root): program = 'magick' location = None available = location is not None if available: basename, extension = os.path.splitext(location) if extension is not None: location = ''.join((basename, extension.lower())) version_info = get_version_info( location, env=env ) if available else None available_str = ( u'available' if available and version_info is not None else u'missing' ) if (available and program in ['magick', 'convert'] and not convert_installed()): available_str = u'restart required' table.append([ program, location if available and version_info is not None else u'', available_str, version_info if version_info is not None else u'unavailable' ]) program = 'ghostscript' location = get_gs_command() available = location is not None if available: basename, extension = os.path.splitext(location) if extension is not None: location = ''.join((basename, extension.lower())) version_info = get_version_info( location, env=env ) if available else None available_str = ( u'available' if available and version_info is not None else u'missing' ) if available and _HAS_PREVIEW and not ghostscript_installed(): available_str = u'restart required' table.append([ program, location if available and version_info is not None else u'', available_str, version_info if version_info is not None else u'unavailable' ]) results.append(table) # This really only works for the default template # Note that no attempt is made to find other packages that the # included package depends on if (_HAS_PREVIEW and ghostscript_installed() and get_setting('preview_math_template_file') is None and get_setting("preview_math_mode", view=self.view) != "none"): find_package_re = re.compile( r'\\usepackage(?:\[[^\]]*\])?\{(?P<pkg>[^\}]*)\}' ) packages = ["standalone.cls", "preview.sty", "xcolor.sty"] package_settings = get_setting( "preview_math_template_packages", [], view=self.view) # extract all packages from each package line for pkg_str in package_settings: # search for all \usepackage in the line for m in find_package_re.finditer(pkg_str): pkg_arg = m.group("pkg") # search for each package in the \usepackage argument for pkg in pkg_arg.split(","): pkg = pkg.strip() if pkg: packages.append(pkg + ".sty") if packages: table = [[u'Packages for equation preview', u'Status']] for package in packages: available = kpsewhich(package) is not None package_name = package.split(".")[0] table.append([ package_name, (u'available' if available else u'missing') ]) results.append(table) run_on_main_thread(partial(self._on_main_thread, results), timeout=30)
def run(self): texpath = self.texpath results = [] env = copy.deepcopy(os.environ) if texpath is not None: env['PATH'] = texpath if self.build_env is not None: update_environment(env, self.build_env) table = [ ['Variable', 'Value'] ] table.append(['PATH', env.get('PATH', '')]) if self.uses_miktex: get_tex_path_variable = get_tex_path_variable_miktex should_run = which('findtexmf', path=texpath) is not None else: get_tex_path_variable = get_tex_path_variable_texlive should_run = which('kpsewhich', path=texpath) is not None if should_run: for var in ['TEXINPUTS', 'BIBINPUTS', 'BSTINPUTS']: table.append([var, get_tex_path_variable(var, env)]) if self.uses_miktex: for var in ['BIBTEX', 'LATEX', 'PDFLATEX', 'MAKEINDEX', 'MAKEINFO', 'TEX', 'PDFTEX', 'TEXINDEX']: value = env.get(var, None) if value is not None: table.append([var, value]) results.append(table) table = [ ['Program', 'Location', 'Status', 'Version'] ] # skip sublime_exe on OS X # we only use this for the hack to re-focus on ST # which doesn't work on OS X anyway if sublime.platform() != 'osx': sublime_exe = self.sublime_exe available = sublime_exe is not None if available: if not os.path.isabs(sublime_exe): sublime_exe = which(sublime_exe) basename, extension = os.path.splitext(sublime_exe) if extension is not None: sublime_exe = ''.join((basename, extension.lower())) version_info = get_version_info( sublime_exe, env=env ) if available else None table.append([ 'sublime', sublime_exe, (u'available' if available and version_info is not None else u'missing'), version_info if version_info is not None else u'unavailable' ]) # a list of programs, each program is either a string or a list # of alternatives (e.g. 32/64 bit version) programs = [ 'latexmk' if not self.uses_miktex else 'texify', 'pdflatex', 'xelatex', 'lualatex', 'biber', 'bibtex', 'bibtex8', 'kpsewhich', ('gs' if sublime.platform() != 'windows' else ['gswin32c', 'gswin64c', 'gs']) ] if sublime.version() >= '3118': # ImageMagick requires gs to work with PDFs programs += [['magick', 'convert']] for program in programs: if isinstance(program, list): program_list = program program = program_list[0] location = None for p in program_list: location = which(p, path=texpath) if location is not None: program = p break else: location = which(program, path=texpath) available = location is not None if available: basename, extension = os.path.splitext(location) if extension is not None: location = ''.join((basename, extension.lower())) version_info = get_version_info( location, env=env ) if available else None available_str = ( u'available' if available and version_info is not None else u'missing') if (available and program in ['magick', 'convert'] and not convert_installed()): available_str = u'restart required' table.append([ program, location, available_str, version_info if version_info is not None else u'unavailable' ]) results.append(table) run_on_main_thread(partial(self._on_main_thread, results), timeout=30)
def _on_main_thread(self, results): builder_name = get_setting('builder', 'traditional', view=self.view) if builder_name in ['', 'default']: builder_name = 'traditional' builder_settings = get_setting('builder_settings', view=self.view) builder_path = get_setting('builder_path', view=self.view) if builder_name in ['simple', 'traditional', 'script']: builder_path = None else: bld_path = os.path.join(sublime.packages_path(), builder_path) add_plugin_path(bld_path) builder_name = _classname_to_internal_name(builder_name) try: get_plugin('{0}_builder'.format(builder_name)) builder_available = True except NoSuchPluginException: traceback.print_exc() builder_available = False results.append( [[u'Builder', u'Status'], [builder_name, u'available' if builder_available else u'missing']]) if builder_path: results.append([[u'Builder Path'], [builder_path]]) if builder_settings is not None: table = [[u'Builder Setting', u'Value']] for key in sorted(builder_settings.keys()): value = builder_settings[key] table.append([key, value]) results.append(table) # is current view a TeX file? view = self.view if view.score_selector(0, 'text.tex.latex') != 0: tex_root = get_tex_root(view) tex_directives = parse_tex_directives( tex_root, multi_values=['options'], key_maps={'ts-program': 'program'}) results.append([[u'TeX Root'], [tex_root]]) results.append([[u'LaTeX Engine'], [ tex_directives.get( 'program', get_setting('program', 'pdflatex', self.view)) ]]) table = [[u'LaTeX Output Setting', u'Value']] output_directory = get_output_directory(tex_root) if output_directory: table.append(['output_directory', output_directory]) aux_directory = get_aux_directory(tex_root) if aux_directory: table.append(['aux_directory', aux_directory]) jobname = get_jobname(tex_root) if jobname and jobname != os.path.splitext( os.path.basename(tex_root))[0]: table.append(['jobname', jobname]) if len(table) > 1: results.append(table) options = get_setting('builder_settings', {}, self.view).\ get('options', []) options.extend(tex_directives.get('options', [])) if len(options) > 0: table = [[u'LaTeX Options']] for option in options: table.append([option]) results.append(table) default_viewer = DEFAULT_VIEWERS.get(sublime.platform(), None) viewer_name = get_setting('viewer', default_viewer) if viewer_name in ['', 'default']: viewer_name = default_viewer try: viewer_plugin = get_plugin(viewer_name + '_viewer') viewer_available = True except NoSuchPluginException: viewer_available = False viewer_location = 'N/A' if viewer_available: if viewer_name == 'command': # assume the command viewer is always valid viewer_location = 'N/A' elif viewer_name in ('evince', 'okular', 'zathura'): viewer_location = which(viewer_name) viewer_available = bool(viewer_location) elif viewer_name == 'preview': viewer_location = '/Applications/Preview.app' if not os.path.exists(viewer_location): try: viewer_location = check_output([ 'osascript', '-e', 'POSIX path of ' '(path to app id "com.apple.Preview")' ], use_texpath=False) except subprocess.CalledProcessError: viewer_location = None viewer_available = False \ if not viewer_location else os.path.exists(viewer_location) elif viewer_name == 'skim': viewer_location = '/Applications/Skim.app' if not os.path.exists(viewer_location): try: viewer_location = check_output([ 'osascript', '-e', 'POSIX path of ' '(path to app id "net.sourceforge.skim-app.skim")' ], use_texpath=False) except subprocess.CalledProcessError: viewer_location = None viewer_available = False \ if not viewer_location else os.path.exists(viewer_location) elif viewer_name == 'sumatra': sumatra_exe = get_setting('viewer_settings', {}).\ get('sumatra', get_setting('windows', {}). get('sumatra', 'SumatraPDF.exe')) or \ 'SumatraPDF.exe' viewer_location = which(sumatra_exe) if not bool(viewer_location): viewer_location = viewer_plugin()._find_sumatra_exe() viewer_available = bool(viewer_location) if not viewer_available: viewer_location = 'N/A' results.append([[u'Viewer', u'Status', u'Location'], [ viewer_name, u'available' if viewer_available else u'missing', viewer_location ]]) if callable(self.on_done): self.on_done(results)
def run(self): texpath = self.texpath results = [] env = copy.deepcopy(os.environ) if texpath is not None: env['PATH'] = texpath if self.build_env is not None: update_environment(env, self.build_env) table = [['Variable', 'Value']] table.append(['PATH', env.get('PATH', '')]) if self.uses_miktex: get_tex_path_variable = get_tex_path_variable_miktex should_run = which('findtexmf', path=texpath) is not None else: get_tex_path_variable = get_tex_path_variable_texlive should_run = which('kpsewhich', path=texpath) is not None if should_run: for var in ['TEXINPUTS', 'BIBINPUTS', 'BSTINPUTS']: table.append([var, get_tex_path_variable(var, env)]) if self.uses_miktex: for var in [ 'BIBTEX', 'LATEX', 'PDFLATEX', 'MAKEINDEX', 'MAKEINFO', 'TEX', 'PDFTEX', 'TEXINDEX' ]: value = env.get(var, None) if value is not None: table.append([var, value]) results.append(table) table = [['Program', 'Location', 'Status', 'Version']] # skip sublime_exe on OS X # we only use this for the hack to re-focus on ST # which doesn't work on OS X anyway if sublime.platform() != 'osx': sublime_exe = self.sublime_exe available = sublime_exe is not None if available: if not os.path.isabs(sublime_exe): sublime_exe = which(sublime_exe) basename, extension = os.path.splitext(sublime_exe) if extension is not None: sublime_exe = ''.join((basename, extension.lower())) version_info = get_version_info(sublime_exe, env=env) if available else None table.append([ 'sublime', sublime_exe, (u'available' if available and version_info is not None else u'missing'), version_info if version_info is not None else u'unavailable' ]) # a list of programs, each program is either a string or a list # of alternatives (e.g. 32/64 bit version) programs = [ 'latexmk' if not self.uses_miktex else 'texify', 'pdflatex', 'xelatex', 'lualatex', 'biber', 'bibtex', 'bibtex8', 'kpsewhich' ] if _HAS_PREVIEW: # ImageMagick requires gs to work with PDFs programs += [['magick', 'convert']] for program in programs: if isinstance(program, list): program_list = program program = program_list[0] location = None for p in program_list: location = which(p, path=texpath) if location is not None: program = p break else: location = which(program, path=texpath) available = location is not None if available: basename, extension = os.path.splitext(location) if extension is not None: location = ''.join((basename, extension.lower())) version_info = get_version_info(location, env=env) if available else None available_str = (u'available' if available and version_info is not None else u'missing') if (available and program in ['magick', 'convert'] and not convert_installed()): available_str = u'restart required' table.append([ program, location, available_str, version_info if version_info is not None else u'unavailable' ]) program = 'ghostscript' location = get_gs_command() available = location is not None if available: basename, extension = os.path.splitext(location) if extension is not None: location = ''.join((basename, extension.lower())) version_info = get_version_info(location, env=env) if available else None available_str = (u'available' if available and version_info is not None else u'missing') if available and _HAS_PREVIEW and not ghostscript_installed(): available_str = u'restart required' table.append([ program, location, available_str, version_info if version_info is not None else u'unavailable' ]) results.append(table) # This really only works for the default template # Note that no attempt is made to find other packages that the # included package depends on if (_HAS_PREVIEW and convert_installed() and get_setting('preview_math_template_file') is None and get_setting("preview_math_mode", view=self.view) != "none"): find_package_re = re.compile( r'\\usepackage(?:\[[^\]]*\])?\{(?P<pkg>[^\}]*)\}') packages = ["standalone.cls", "preview.sty", "xcolor.sty"] package_settings = get_setting("preview_math_template_packages", [], view=self.view) # extract all packages from each package line for pkg_str in package_settings: # search for all \usepackage in the line for m in find_package_re.finditer(pkg_str): pkg_arg = m.group("pkg") # search for each package in the \usepackage argument for pkg in pkg_arg.split(","): pkg = pkg.strip() if pkg: packages.append(pkg + ".sty") if packages: table = [[u'Packages for equation preview', u'Status']] for package in packages: available = kpsewhich(package) is not None package_name = package.split(".")[0] table.append([ package_name, (u'available' if available else u'missing') ]) results.append(table) run_on_main_thread(partial(self._on_main_thread, results), timeout=30)
def external_command(command, cwd=None, shell=False, env=None, stdin=__sentinel__, stdout=__sentinel__, stderr=__sentinel__, preexec_fn=None, use_texpath=True, show_window=False): ''' Takes a command object to be passed to subprocess.Popen. Returns a subprocess.Popen object for the corresponding process. Raises OSError if command not found ''' if command is None: raise ValueError('command must be a string or list of strings') _env = dict(os.environ) if use_texpath: _env['PATH'] = get_texpath() or os.environ['PATH'] if env is not None: update_env(_env, env) # if command is a string rather than a list, convert it to a list # unless shell is set to True on a non-Windows platform if ( (shell is False or sublime.platform() == 'windows') and isinstance(command, strbase) ): if sys.version_info < (3,): command = str(command) command = split(command) if sys.version_info < (3,): command = [unicode(c) for c in command] elif ( shell is True and sublime.platform() != 'windows' and (isinstance(command, list) or isinstance(command, tuple)) ): command = u' '.join(command) # Windows-specific adjustments startupinfo = None if sublime.platform() == 'windows': # ensure console window doesn't show startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW if show_window: startupinfo.wShowWindow = 1 if not os.path.isabs(command[0]): _command = which( command[0], path=_env['PATH'] or os.environ['PATH'] ) if command: command[0] = _command # encode cwd in the file system encoding; this is necessary to support # some non-ASCII paths; see PR #878. Thanks to anamewing for the # suggested fix if not _ST3 and cwd: cwd = cwd.encode(sys.getfilesystemencoding()) if stdin is __sentinel__: stdin = None if stdout is __sentinel__: stdout = PIPE if stderr is __sentinel__: stderr = STDOUT try: print(u'Running "{0}"'.format(u' '.join([quote(s) for s in command]))) except UnicodeError: try: print(u'Running "{0}"'.format(command)) except: pass p = Popen( command, stdin=stdin, stdout=stdout, stderr=stderr, startupinfo=startupinfo, preexec_fn=preexec_fn, shell=shell, env=_env, cwd=cwd ) return p
def external_command(command, cwd=None, shell=False, env=None, stdin=__sentinel__, stdout=__sentinel__, stderr=__sentinel__, preexec_fn=None, use_texpath=True, show_window=False): ''' Takes a command object to be passed to subprocess.Popen. Returns a subprocess.Popen object for the corresponding process. Raises OSError if command not found ''' if command is None: raise ValueError('command must be a string or list of strings') _env = dict(os.environ) if use_texpath: _env['PATH'] = get_texpath() or os.environ['PATH'] if env is not None: update_env(_env, env) # if command is a string rather than a list, convert it to a list # unless shell is set to True on a non-Windows platform if ( (shell is False or sublime.platform() == 'windows') and isinstance(command, strbase) ): if sys.version_info < (3,): command = str(command) command = split(command) if sys.version_info < (3,): command = [unicode(c) for c in command] elif ( shell is True and sublime.platform() != 'windows' and (isinstance(command, list) or isinstance(command, tuple)) ): command = u' '.join(command) # Windows-specific adjustments startupinfo = None if sublime.platform() == 'windows': # ensure console window doesn't show startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW if show_window: startupinfo.wShowWindow = 1 if not os.path.isabs(command[0]): _command = which( command[0], path=_env['PATH'] or os.environ['PATH'] ) if _command: command[0] = _command # encode cwd in the file system encoding; this is necessary to support # some non-ASCII paths; see PR #878. Thanks to anamewing for the # suggested fix if not _ST3 and cwd: cwd = cwd.encode(sys.getfilesystemencoding()) if stdin is __sentinel__: stdin = None if stdout is __sentinel__: stdout = PIPE if stderr is __sentinel__: stderr = STDOUT try: print(u'Running "{0}"'.format(u' '.join([quote(s) for s in command]))) except UnicodeError: try: print(u'Running "{0}"'.format(command)) except: pass p = Popen( command, stdin=stdin, stdout=stdout, stderr=stderr, startupinfo=startupinfo, preexec_fn=preexec_fn, shell=shell, env=_env, cwd=cwd ) return p
def get_sublime_exe(): ''' Utility function to get the full path to the currently executing Sublime instance. ''' processes = ['subl', 'sublime_text'] def check_processes(st2_dir=None): if st2_dir is None or os.path.exists(st2_dir): for process in processes: try: if st2_dir is not None: process = os.path.join(st2_dir, process) p = subprocess.Popen( [process, '-v'], stdout=subprocess.PIPE, startupinfo=startupinfo, shell=shell, env=os.environ ) except: pass else: stdout, _ = p.communicate() if p.returncode == 0: m = SUBLIME_VERSION.search(stdout.decode('utf8')) if m and m.group(1) == version: return process return None platform = sublime.platform() plat_settings = get_setting(platform, {}) sublime_executable = plat_settings.get('sublime_executable', None) if sublime_executable: return sublime_executable # we cache the results of the other checks, if possible if hasattr(get_sublime_exe, 'result'): return get_sublime_exe.result # are we on ST3 if hasattr(sublime, 'executable_path'): get_sublime_exe.result = sublime.executable_path() # on osx, the executable does not function the same as subl if platform == 'osx': get_sublime_exe.result = os.path.normpath( os.path.join( os.path.dirname(get_sublime_exe.result), '..', 'SharedSupport', 'bin', 'subl' ) ) # on linux, it is preferable to use subl if it points to the # correct version see issue #710 for a case where this is useful elif ( platform == 'linux' and not get_sublime_exe.result.endswith('subl') ): subl = which('subl') if subl is not None: try: p = subprocess.Popen( [subl, '-v'], stdout=subprocess.PIPE, env=os.environ ) except: pass else: stdout, _ = p.communicate() if p.returncode == 0: m = SUBLIME_VERSION.search(stdout.decode('utf8')) if m and m.group(1) == sublime.version(): get_sublime_exe.result = subl return get_sublime_exe.result # in ST2 on Windows the Python executable is actually "sublime_text" elif platform == 'windows' and sys.executable != 'python' and \ os.path.isabs(sys.executable): get_sublime_exe.result = sys.executable return get_sublime_exe.result # guess-work for ST2 version = sublime.version() startupinfo = None shell = False if platform == 'windows': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW shell = sublime.version() >= '3000' # hope its on the path result = check_processes() if result is not None: get_sublime_exe.result = result return result # guess the default location if platform == 'windows': st2_dir = os.path.expandvars('%PROGRAMFILES%\\Sublime Text 2') result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result elif platform == 'linux': for path in [ '$HOME/bin', '$HOME/sublime_text_2', '$HOME/sublime_text', '/opt/sublime_text_2', '/opt/sublime_text', '/usr/local/bin', '/usr/bin' ]: st2_dir = os.path.expandvars(path) result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result else: st2_dir = '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin' result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result try: p = subprocess.Popen( ['mdfind', '"kMDItemCFBundleIdentifier == com.sublimetext.2"'], stdout=subprocess.PIPE, env=os.environ ) except: pass else: stdout, _ = p.communicate() if p.returncode == 0: st2_dir = os.path.join( stdout.decode('utf8'), 'Contents', 'SharedSupport', 'bin' ) result = check_processes(st2_dir) if result is not None: get_sublime_exe.result = result return result print( 'Cannot determine the path to your Sublime installation. Please ' 'set the "sublime_executable" setting in your settings for your ' 'platform.' ) return None