def do_finish(self, can_switch_to_pdf): self.output_view.run_command("do_finish_edit") if _HAS_PHANTOMS and self.show_errors_inline: self.create_errs_by_file() self.update_phantoms() # can_switch_to_pdf indicates a pdf should've been created if can_switch_to_pdf: # if using output_directory, follow the copy_output_on_build setting # files are copied to the same directory as the main tex file if self.output_directory is not None: copy_on_build = get_setting('copy_output_on_build', True) if copy_on_build is None or copy_on_build is True: shutil.copy2( os.path.join( self.output_directory, self.tex_base + u'.pdf' ), os.path.dirname(self.file_name) ) elif isinstance(copy_on_build, list): for ext in copy_on_build: shutil.copy2( os.path.join( self.output_directory, self.tex_base + ext ), os.path.dirname(self.file_name) ) if get_setting('open_pdf_on_build', True): self.view.run_command("jump_to_pdf", {"from_keybinding": False})
def _create_formatted_entries(self, bib_entries): # create the formatted entries autocomplete_format = get_setting("cite_autocomplete_format") panel_format = get_setting("cite_panel_format") meta_data = frozendict( cache_time=long(time.time()), version=_VERSION, autocomplete_format=autocomplete_format, panel_format=panel_format ) formatted_entries = tuple( frozendict(**{ "keyword": entry["keyword"], "<prefix_match>": bibformat.create_prefix_match_str(entry), "<panel_formatted>": tuple( bibformat.format_entry(s, entry) for s in panel_format ), "<autocomplete_formatted>": bibformat.format_entry(autocomplete_format, entry) }) for entry in bib_entries ) return meta_data, formatted_entries
def _create_formatted_entries(formatted_cache_name, bib_entries, cache_time): # create the formatted entries autocomplete_format = get_setting("cite_autocomplete_format") panel_format = get_setting("cite_panel_format") meta_data = { "cache_time": cache_time, "version": _VERSION, "autocomplete_format": autocomplete_format, "panel_format": panel_format } formatted_entries = [ { "keyword": entry["keyword"], "<prefix_match>": bibformat.create_prefix_match_str(entry), "<panel_formatted>": [ bibformat.format_entry(s, entry) for s in panel_format ], "<autocomplete_formatted>": bibformat.format_entry(autocomplete_format, entry) } for entry in bib_entries ] cache.write_global(formatted_cache_name, (meta_data, formatted_entries)) return formatted_entries
def _run_with_sumatra_exe(self, commands): def _no_binary(): message = ( 'Could not find SumatraPDF.exe. ' 'Please ensure the "sumatra" setting in your ' 'LaTeXTools settings is set and points to the location ' 'of Sumatra on your computer.' ) def _error_msg(): sublime.error_message(message) sublime.set_timeout(_error_msg, 1) print(message) # paranoia if not isinstance(commands, list): commands = [commands] startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = 4 # SHOWNOACTIVE # favour 'sumatra' setting under viewer_settings if # it exists, otherwise, use the platform setting sumatra_binary = get_setting('viewer_settings', {}).\ get('sumatra', get_setting('windows', {}). get('sumatra', 'SumatraPDF.exe')) if sumatra_binary == '' or sumatra_binary is None: sumatra_binary = self._find_sumatra_exe() if sumatra_binary is None: _no_binary() return try: subprocess.Popen( [sumatra_binary] + commands, startupinfo=startupinfo ) except OSError: exc_info = sys.exc_info() sumatra_exe = self._find_sumatra_exe() if sumatra_exe is not None and sumatra_exe != sumatra_binary: try: subprocess.Popen( [sumatra_exe] + commands, startupinfo=startupinfo ) except OSError: traceback.print_exc() _no_binary() return else: traceback.print_exception(*exc_info) _no_binary() return
def plugin_loaded(): # get additional entries from the settings _setting_entries = get_setting("fillall_helper_entries", []) _filter_invalid_entries(_setting_entries) _fillall_entries.extend(_setting_entries) _fillall_entries.extend([ { "regex": r'(?:edulcni|tupni)\\', "extensions": [e[1:] for e in get_tex_extensions()], "strip_extensions": [".tex"] }, { "regex": r'(?:\][^{}\[\]]*\[)?scihpargedulcni\\', "extensions": get_setting("image_types", [ "pdf", "png", "jpeg", "jpg", "eps" ]) }, { "regex": r'(?:\][^{}\[\]]*\[)?ecruoserbibdda\\', "extensions": ["bib"] }, { "regex": r'yhpargoilbib\\', "extensions": ["bib"], "strip_extensions": [".bib"], "comma_separated": True } ]) # update the fields of the entries _update_input_entries(_fillall_entries) _fillall_entries.extend([ { "regex": r'([^{}\[\]]*)\{(?:\][^{}\[\]]*\[)?ssalctnemucod\\', "type": "cached", "cache_name": "cls" }, { "regex": r'([^{}\[\]]*)\{(?:\][^{}\[\]]*\[)?egakcapesu\\', "type": "cached", "cache_name": "pkg" }, { "regex": r'([^{}\[\]]*)\{elytsyhpargoilbib\\', "type": "cached", "cache_name": "bst" } ]) global _TEX_INPUT_GROUP_MAPPING, TEX_INPUT_FILE_REGEX _TEX_INPUT_GROUP_MAPPING = dict((i, v) for i, v in enumerate(_fillall_entries)) TEX_INPUT_FILE_REGEX = re.compile( "(?:{0})".format("|".join(entry["regex"] for entry in _fillall_entries)) )
def run(self): # Retrieve root file and dirname. view = self.window.active_view() root_file = getTeXRoot.get_tex_root(view) if root_file is None: sublime.status_message('Could not find TEX root. Please ensure that either you have configured a TEX root in your project settings or have a LaTeX document open.') print('Could not find TEX root. Please ensure that either you have configured a TEX root in your project settings or have a LaTeX document open.') return if not os.path.isfile(root_file): message = "Could not find TEX root {0}.".format(root_file) sublime.status_message(message) print(message) return # clear the cache try: cache.delete_local_cache(root_file) except: print('Error while trying to delete local cache') traceback.print_exc() path = os.path.dirname(root_file) # Load the files to delete from the settings temp_files_exts = get_setting('temp_files_exts', ['.blg', '.bbl', '.aux', '.log', '.brf', '.nlo', '.out', '.dvi', '.ps', '.lof', '.toc', '.fls', '.fdb_latexmk', '.pdfsync', '.synctex.gz', '.ind', '.ilg', '.idx']) ignored_folders = get_setting('temp_files_ignored_folders', ['.git', '.svn', '.hg']) ignored_folders = set(ignored_folders) for dir_path, dir_names, file_names in os.walk(path): dir_names[:] = [d for d in dir_names if d not in ignored_folders] for file_name in file_names: for ext in temp_files_exts: if file_name.endswith(ext): file_name_to_del = os.path.join(dir_path, file_name) if os.path.exists(file_name_to_del): try: os.remove(file_name_to_del) except OSError: # basically here for locked files in Windows, # but who knows what we might find? print('Error while trying to delete {0}'.format(file_name_to_del)) traceback.print_exc() # exit extension break sublime.status_message("Deleted temp files")
def run(self, edit, insert_char=""): # get view and location of first selection, which we expect to be just the cursor position view = self.view point = view.sel()[0].b print (point) # Only trigger within LaTeX # Note using score_selector rather than match_selector if not view.score_selector(point, "text.tex.latex"): return if insert_char: # ed = view.begin_edit() # point += view.insert(ed, point, insert_char) # view.end_edit(ed) # The above was roundabout and did not work on ST3! point += view.insert(edit, point, insert_char) # Get prefs and toggles to see if we are auto-triggering # This is only the case if we also must insert , or {, so we don't need a separate arg do_ref = get_setting('ref_auto_trigger', True) do_cite = get_setting('cite_auto_trigger', True) else: # if we didn't autotrigger, we must surely run do_ref = True do_cite = True print (do_ref,do_cite) # Get the contents of the current line, from the beginning of the line to # the current point line = view.substr(sublime.Region(view.line(point).a, point)) # print line # Reverse line = line[::-1] if re.match(OLD_STYLE_REF_REGEX, line) or re.match(NEW_STYLE_REF_REGEX, line): if do_ref: print ("Dispatching ref") view.run_command("latex_ref") else: pass # Don't do anything if we match ref completion but we turned it off elif re.match(OLD_STYLE_CITE_REGEX, line) or re.match(NEW_STYLE_CITE_REGEX, line): if do_cite: print ("Dispatching cite") view.run_command("latex_cite") else: pass # ditto for cite else: # here we match nothing, so error out regardless of autotrigger settings sublime.error_message("Ref/cite: unrecognized format.") return
def on_load_async(self, view): if not view.score_selector(0, 'text.tex.latex'): return on_load = get_setting('cache_on_load', {}, view=view) if not on_load or not any(on_load.values()): return tex_root = get_tex_root(view) if tex_root is None: return self._TEX_CACHES[view.id()] = local_cache = LocalCache(tex_root) self._TEX_ROOT_REFS[tex_root] += 1 # because cache state is shared amongst all documents sharing a tex # root, this ensure we only load the analysis ONCE in the on_load # event if ( not local_cache.has('analysis') and on_load.get('analysis', False) ): self.run_analysis(tex_root) if tex_root not in self._BIB_CACHES: if on_load.get('bibliography', False): self.run_bib_cache(tex_root) self._BIB_CACHES[tex_root] = bib_caches = [] LocalCache(tex_root).invalidate('bib_files') bib_files = find_bib_files(tex_root) plugins = get_setting( 'bibliography_plugins', ['traditional'], view=view) if not isinstance(plugins, list): plugins = [plugins] if 'new' in plugins or 'new_bibliography' in plugins: for bib_file in bib_files: bib_caches.append(BibCache('new', bib_file)) if ( 'traditional' in plugins or 'traditional_bibliography' in plugins ): for bib_file in bib_files: bib_caches.append(BibCache('trad', bib_file)) self.run_cache_update()
def _run_with_sumatra_exe(self, commands): def _no_binary(): message = ( 'Could not find SumatraPDF.exe. ' 'Please ensure the "sumatra" setting in your ' 'LaTeXTools settings is set and points to the location ' 'of Sumatra on your computer.' ) def _error_msg(): sublime.error_message(message) sublime.set_timeout(_error_msg, 1) print(message) # paranoia if not isinstance(commands, list): commands = [commands] # favour 'sumatra' setting under viewer_settings if # it exists, otherwise, use the platform setting sumatra_binary = get_setting('viewer_settings', {}).\ get('sumatra', get_setting('windows', {}). get('sumatra', 'SumatraPDF.exe')) or 'SumatraPDF.exe' try: external_command( [sumatra_binary] + commands, use_texpath=False, show_window=True ) except OSError: exc_info = sys.exc_info() sumatra_exe = self._find_sumatra_exe() if sumatra_exe is not None and sumatra_exe != sumatra_binary: try: external_command( [sumatra_exe] + commands, use_texpath=False, show_window=True ) except OSError: traceback.print_exc() _no_binary() return else: traceback.print_exception(*exc_info) _no_binary() return
def __init__(self, ana, only_file=None): # retrieve the labels and the sections toc_section_commands = get_setting("toc_section_commands", []) toc_indentations = get_setting("toc_indentations", {}) toc_labels = get_setting("toc_labels", []) labels = ana.filter_commands(toc_section_commands + toc_labels) # filter the labels and sections to only get the labels # (faster than an additional query) secs = [c for c in labels if c.command in toc_section_commands] if only_file: labels = [l for l in labels if l.file_name == only_file] secs = [s for s in secs if s.file_name == only_file] # create the user readably captions # get the minimal indent (to lower the minimal section indent to 0) max_indent_value = max(toc_indentations.values()) indent_offset = min([ toc_indentations.get(com.command, max_indent_value) for com in secs ] + [0]) caption_secs = [_make_caption(toc_indentations, s, indent_offset) for s in secs] caption_labels = [_make_caption(toc_indentations, l, indent_offset) for l in labels] self.__only_sec = True # init the superclass with a copy of the section elements super(show_toc_quickpanel, self).__init__( list(caption_secs), list(secs)) # story necessary fields self.__secs = secs self.__labels = labels self.__caption_secs = caption_secs self.__caption_labels = caption_labels # add a item to show the labels self.add_item(quickpanel.AT_END, self.__show_string, done_handler=self.__show_labels) # register a function to hide the labels self.done_handler[self.__hide_string] = self.__hide_labels # show the quickpanel self.show_quickpanel()
def find_image(tex_root, file_name, tex_file_name=None): ana = analysis.get_analysis(tex_root) base_path = ana.tex_base_path(tex_file_name) image_types = get_setting( "image_types", [ "png", "pdf", "jpg", "jpeg", "eps" ]) file_path = os.path.normpath( os.path.join(base_path, file_name)) _, extension = os.path.splitext(file_path) extension = extension[1:] # strip the leading point if not extension: for ext in image_types: test_path = file_path + "." + ext print("Test file: '{0}'".format(test_path)) if os.path.exists(test_path): extension = ext file_path = test_path print("Found file: '{0}'".format(test_path)) break if not os.path.exists(file_path): return None return file_path
def on_post_save_async(self, view): if not view.score_selector(0, 'text.tex.latex'): return on_save = get_setting('cache_on_save', {}, view=view) if not on_save or not any(on_save.values()): return tex_root = get_tex_root(view) if tex_root is None: return _id = view.id() if _id not in self._TEX_CACHES: local_cache = self._TEX_CACHES[_id] = LocalCache(tex_root) else: local_cache = self._TEX_CACHES[_id] if on_save.get('analysis', False): # ensure the cache of bib_files is rebuilt on demand local_cache.invalidate('bib_files') self.run_analysis(tex_root) if on_save.get('bibliography', False): self.run_bib_cache(tex_root) self.run_cache_update()
def _directive_spellcheck_completions(view, value, ac=True): user_sc = get_setting("tex_spellcheck_paths", view=view, default={}) locales = sorted(user_sc.keys()) locales.extend(installed_locales) def get_locale(loc): try: loc = detect_spellcheck.normalize_locale(loc) dic = user_sc.get(loc) or detect_spellcheck.get_dict_path(loc) if ac: _, dic = os.path.split(dic) elif dic.startswith("Packages/"): dic = dic[len("Packages/"):] except: dic = "locale" return dic locales = [ loc for loc in map(_prettify_locale, locales) if loc.startswith(value) ] if ac: comp = [ ("{0}\t{1}".format(loc, get_locale(loc)), loc) for loc in locales ] else: comp = [[loc, get_locale(loc)] for loc in locales], locales return comp
def get_jobname(view_or_root): root = get_root(view_or_root) if root is None: return None # exit condition: texify and simple do not support jobname # so always return the root path if using_texify_or_simple(): return os.path.splitext( os.path.basename(root) )[0] jobname = get_directive(view_or_root, 'jobname') if (jobname is None or jobname == '') and view_or_root != root: jobname = get_directive(root, 'jobname') if jobname is None or jobname == '': jobname = get_setting('jobname') if jobname is None or jobname == '': return os.path.splitext( os.path.basename(root) )[0] return jobname
def _get_settings(self): ''' returns evince-related settings as a tuple (python, sync_wait) ''' linux_settings = get_setting('linux', {}) # TODO python2 should eventually be deprecated python = linux_settings.get('python') if python is None or python == '': python = linux_settings.get('python2') if python is None or python == '': if self.PYTHON is not None: python = self.PYTHON else: try: subprocess.check_call(['python', '-c', 'import dbus']) python = 'python' except subprocess.CalledProcessError: try: subprocess.check_call(['python3', '-c', 'import dbus']) python = 'python3' except subprocess.CalledProcessError: sublime.error_message( '''Cannot find a valid Python interpreter. Please set the python setting in your LaTeXTools settings. '''.strip() ) # exit the viewer process raise Exception('Cannot find a valid interpreter') self.PYTHON = python return ( python, linux_settings.get('sync_wait') or 1.0 )
def focus_st(): sublime_command = get_sublime_exe() if sublime_command is not None: platform = sublime.platform() # TODO: this does not work on OSX # and I don't know why... if platform == 'osx': return plat_settings = get_setting(platform, {}) wait_time = plat_settings.get('keep_focus_delay', 0.5) def keep_focus(): startupinfo = None shell = False if platform == 'windows': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW shell = _ST3 subprocess.Popen( sublime_command, startupinfo=startupinfo, shell=shell, env=os.environ ) if hasattr(sublime, 'set_async_timeout'): sublime.set_async_timeout(keep_focus, int(wait_time * 1000)) else: sublime.set_timeout(keep_focus, int(wait_time * 1000))
def on_query_completions(self, view, prefix, locations): # Only trigger within LaTeX if not view.match_selector(locations[0], "text.tex.latex"): return [] point = locations[0] try: completions, prefix, post_brace, new_point_a, new_point_b = get_cite_completions(view, point, autocompleting=True) except UnrecognizedCiteFormatError: return [] except NoBibFilesError: sublime.status_message("No bib files found!") return [] except BibParsingError as e: sublime.status_message("Bibliography " + e.filename + " is broken!") return [] if prefix: completions = [comp for comp in completions if prefix.lower() in "%s %s" % (comp[0].lower(), comp[1].lower())] prefix += " " # get preferences for formating of autocomplete entries cite_autocomplete_format = get_setting('cite_autocomplete_format', "{keyword}: {title}") r = [(prefix + cite_autocomplete_format.format(keyword=keyword, title=title, author=author, year=year, author_short=author_short, title_short=title_short, journal=journal), keyword + post_brace) for (keyword, title, author, year, author_short, title_short, journal) in completions] # print "%d bib entries matching %s" % (len(r), prefix) return r
def run(self, edit, **args): view = self.view window = view.window() default_settings = sublime.load_settings("LaTeXTools.sublime-settings") _current_settings = [[s, get_setting(s), default_settings.get(s)] for s in _toggle_settings] _panel_entries = [_make_panel_entry(t) for t in _current_settings] def toggle_setting(index): if index == -1: return name, value = _current_settings[index][0:2] new_value = not value message = "Set '{0}' to {1}".format(name, new_value) print(message) sublime.status_message(message) _current_settings[index][1] = new_value view.settings().set(name, new_value) _panel_entries[index] = _make_panel_entry(_current_settings[index]) # keep the index (only possible with ST3) flags = {"selected_index": index} if _ST3 else {} window.show_quick_panel(_panel_entries, toggle_setting, **flags) window.show_quick_panel(_panel_entries, toggle_setting)
def get_viewer(): default_viewer = DEFAULT_VIEWERS.get(sublime.platform(), None) viewer_name = get_setting('viewer', default_viewer) if viewer_name in ['', 'default']: viewer_name = default_viewer if viewer_name is None: sublime.error_message('No viewer could be found for your platform. ' 'Please configure the "viewer" setting in your LaTeXTools ' 'Preferences') raise NoViewerException() try: viewer = get_plugin(viewer_name + '_viewer') except NoSuchPluginException: sublime.error_message('Cannot find viewer ' + viewer_name + '.\n' + 'Please check your LaTeXTools Preferences.') raise NoViewerException() print(repr(viewer)) # assume no-args constructor viewer = viewer() if not viewer.supports_platform(sublime.platform()): sublime.error_message(viewer_name + ' does not support the ' + 'current platform. Please change the viewer in ' + 'your LaTeXTools Preferences.') raise NoViewerException() return viewer
def get_auto_completions(self, view, prefix, line): # Reverse, to simulate having the regex # match backwards (cool trick jps btw!) line = line[::-1] # Check the first location looks like a cite_, but backward old_style = OLD_STYLE_CITE_REGEX.match(line) # Do not match on plain "cite[a-zX*]*?" when autocompleting, # in case the user is typing something else if old_style and not prefix: return [] try: completions = get_cite_completions(view) except NoBibFilesError: print("No bib files found!") sublime.status_message("No bib files found!") return [] except BibParsingError as e: message = "Error occurred parsing {0}. {1}.".format( e.filename, e.message) print(message) traceback.print_exc() sublime.status_message(message) return [] if prefix: lower_prefix = prefix.lower() completions = [ c for c in completions if _is_prefix(lower_prefix, c) ] if len(completions) == 0: return [] cite_autocomplete_format = get_setting( 'cite_autocomplete_format', '{keyword}: {title}' ) def formatted_entry(entry): try: return entry['<autocomplete_formatted>'] except: return bibformat.format_entry(cite_autocomplete_format, entry) completions = [ ( formatted_entry(c), c['keyword'] ) for c in completions ] if old_style: return completions, '{' else: return completions
def forward_sync(self, pdf_file, tex_file, line, col, **kwargs): command = get_setting("viewer_settings", {}).get(sublime.platform(), {}).get("forward_sync_command") if command is None: self.view_file(pdf_file) return self._run_command(command, pdf_file, tex_file, line, col)
def view_file(self, pdf_file, **kwargs): command = get_setting("viewer_settings", {}).get(sublime.platform(), {}).get("view_command") if command is None: sublime.error_message("You must set the command setting in viewer_settings before " "using the viewer.") return self._run_command(command, pdf_file)
def get_texpath(): platform_settings = get_setting(sublime.platform(), {}) texpath = platform_settings.get("texpath", "") if not _ST3: return os.path.expandvars(texpath).encode(sys.getfilesystemencoding()) else: return os.path.expandvars(texpath)
def _get_synctex_editor(self): st_binary = get_sublime_exe() if st_binary is None: st_binary = get_setting('linux', {}).get('sublime', 'sublime_text') return '--synctex-editor-command={0} %{{input}}:%{{line}}'.format( st_binary )
def using_miktex(): platform_settings = get_setting(sublime.platform(), {}) distro = platform_settings.get('distro', '') if sublime.platform() == 'windows': return distro in ['miktex', ''] else: return distro == 'miktex'
def run(self, edit, **args): if get_setting('open_pdf_on_build', True): self.view.settings().set("open_pdf_on_build", False) sublime.status_message("Do not open PDF on build") print("Do not open PDF on build") else: self.view.settings().set("open_pdf_on_build", True) sublime.status_message("Open PDF on build") print("Open PDF on build")
def run(self): prefs_lin = get_setting('linux', {}) view = self.window.active_view() if not is_tex_file(view.file_name()): sublime.error_message("%s is not a TeX source file: cannot view." % (os.path.basename(view.file_name()),)) return quotes = ""# \"" MUST CHECK WHETHER WE NEED QUOTES ON WINDOWS!!! root = getTeXRoot.get_tex_root(view) rootFile, rootExt = os.path.splitext(root) pdfFile = quotes + rootFile + '.pdf' + quotes s = platform.system() script_path = None if s == "Darwin": # for inverse search, set up a "Custom" sync profile, using # "subl" as command and "%file:%line" as argument # you also have to put a symlink to subl somewhere on your path # Also check the box "check for file changes" viewercmd = ["open", "-a", "Skim"] elif s == "Windows": # with new version of SumatraPDF, can set up Inverse # Search in the GUI: under Settings|Options... # Under "Set inverse search command-line", set: # sublime_text "%f":%l prefs_win = get_setting("windows", {}) su_binary = prefs_win.get("sumatra", "SumatraPDF.exe") viewercmd = [su_binary, "-reuse-instance"] elif s == "Linux": # the required scripts are in the 'evince' subdir script_path = os.path.join(sublime.packages_path(), 'LaTeXTools', 'evince') ev_sync_exec = os.path.join(script_path, 'evince_sync') # so we get inverse search # Get python binary if set in preferences: py_binary = prefs_lin["python2"] or 'python' sb_binary = prefs_lin["sublime"] or 'sublime-text' viewercmd = ['sh', ev_sync_exec, py_binary, sb_binary] else: sublime.error_message("Platform as yet unsupported. Sorry!") return print (viewercmd + [pdfFile]) try: Popen(viewercmd + [pdfFile], cwd=script_path) except OSError: sublime.error_message("Cannot launch Viewer. Make sure it is on your PATH.")
def parse_cwl_file(parse_line): # Get cwl file list # cwl_path = sublime.packages_path() + "/LaTeX-cwl" cwl_file_list = get_setting('cwl_list', [ "tex.cwl", "latex-209.cwl", "latex-document.cwl", "latex-l2tabu.cwl", "latex-mathsymbols.cwl" ]) # ST3 can use load_resource api, while ST2 do not has this api # so a little different with implementation of loading cwl files. if _ST3: cwl_files = ['Packages/LaTeX-cwl/%s' % x for x in cwl_file_list] else: cwl_files = [os.path.normpath(sublime.packages_path() + "/LaTeX-cwl/%s" % x) for x in cwl_file_list] completions = [] for cwl in cwl_files: if _ST3: try: s = sublime.load_resource(cwl) except IOError: print(cwl + ' does not exist or could not be accessed') continue else: try: f = codecs.open(cwl, 'r', 'utf-8') except IOError: print(cwl + ' does not exist or could not be accessed') continue else: try: s = u''.join(f.readlines()) finally: f.close() method = os.path.splitext(os.path.basename(cwl))[0] for line in s.split('\n'): line = line.strip() if line == '': continue if line[0] == '#': continue result = parse_line(line) if result is None: continue (keyword, insertion) = result item = (u'%s\t%s' % (keyword, method), insertion) completions.append(item) return completions
def _check_if_cwl_enabled(): try: view = sublime.active_window().active_view() except AttributeError: return if view is None or not view.score_selector(0, "text.tex.latex"): return if get_setting('command_completion', 'prefixed', view=view) == 'never': return # Checking whether LaTeX-cwl is installed global CWL_COMPLETION_ENABLED if ( os.path.exists( os.path.join(sublime.packages_path(), "LaTeX-cwl") ) or os.path.exists( os.path.join( sublime.installed_packages_path(), "LaTeX-cwl.sublime-package" ) ) or os.path.exists( os.path.join(sublime.packages_path(), "User", "cwl") ) ): CWL_COMPLETION_ENABLED = True else: CWL_COMPLETION_ENABLED = False return # add `\` as an autocomplete trigger g_settings = sublime.load_settings("Preferences.sublime-settings") acts = g_settings.get("auto_complete_triggers", []) # Whether auto trigger is already set in # Preferences.sublime-settings TEX_AUTO_COM = False for i in acts: if ( i.get("selector") == "text.tex.latex" and i.get("characters") == "\\" ): TEX_AUTO_COM = True if not TEX_AUTO_COM: acts.append({ "characters": "\\", "selector": "text.tex.latex" }) g_settings.set("auto_complete_triggers", acts) # pre-load the completions get_cwl_completions().load_completions()
def _get_dyn_entries(): dyn_entries = get_setting("dynamic_fillall_helper_entries", []) if dyn_entries: _filter_invalid_entries(dyn_entries) _update_input_entries(dyn_entries) dyn_regex = re.compile("(?:{0})".format( "|".join(entry["regex"] for entry in dyn_entries))) return dyn_entries, dyn_regex else: return [], None
def _jumpto_image_file(view, window, tex_root, file_name): base_path = os.path.dirname(tex_root) image_types = get_setting("image_types", ["png", "pdf", "jpg", "jpeg", "eps"]) file_path = os.path.normpath(os.path.join(base_path, file_name)) _, extension = os.path.splitext(file_path) extension = extension[1:] # strip the leading point if not extension: for ext in image_types: test_path = file_path + "." + ext print("Test file: '{0}'".format(test_path)) if os.path.exists(test_path): extension = ext file_path = test_path print("Found file: '{0}'".format(test_path)) break if not os.path.exists(file_path): sublime.status_message("file does not exists: '{0}'".format(file_path)) return def run_command(command): if not _ST3: command = str(command) command = shlex.split(command) # if $file is used, substitute it by the file path if "$file" in command: command = [file_path if c == "$file" else c for c in command] # if $file is not used, append the file path else: command.append(file_path) print("RUN: {0}".format(command)) subprocess.Popen(command) psystem = sublime.platform() commands = get_setting("open_image_command", {}).get(psystem, None) print("Commands: '{0}'".format(commands)) print("Open File: '{0}'".format(file_path)) if commands is None: window.open_file(file_path) elif type(commands) is str: run_command(commands) else: for d in commands: print(d) # validate the entry if "command" not in d: message = "Invalid entry {0}, missing: 'command'"\ .format(str(d)) sublime.status_message(message) print(message) continue # check whether the extension matches if "extension" in d: if extension == d["extension"] or\ extension in d["extension"]: run_command(d["command"]) break # if no extension matches always run the command else: run_command(d["command"]) break else: sublime.status_message( "No opening command for {0} defined".format(extension)) window.open_file(file_path)
def on_query_completions(self, view, prefix, locations): if not CWL_COMPLETION_ENABLED: if CWL_COMPLETION_ENABLED is None: _check_if_cwl_enabled() if not CWL_COMPLETION_ENABLED: return [] else: return [] point = locations[0] if not view.score_selector(point, "text.tex.latex"): return [] point_before = point - len(prefix) char_before = view.substr(getRegion(point_before - 1, point_before)) is_prefixed = char_before == "\\" line = view.substr(getRegion(view.line(point).begin(), point)) line = line[::-1] is_env = bool(BEGIN_END_BEFORE_REGEX.match(line)) # default completion level is "prefixed" completion_level = get_setting("command_completion", "prefixed") do_complete = { "never": False, "prefixed": is_prefixed or is_env, "always": True }.get(completion_level, is_prefixed or is_env) if not do_complete: return [] # do not autocomplete if the leading backslash is escaped if ESCAPE_REGEX.match(line): # if there the autocompletion has been opened with the \ trigger # (no prefix) and the user has not enabled auto completion for the # scope, then hide the auto complete popup selector = view.settings().get("auto_complete_selector") if not prefix and not view.score_selector(point, selector): view.run_command("hide_auto_complete") return [] # Do not do completions in actions if (latex_input_completions.TEX_INPUT_FILE_REGEX not in ENV_DONOT_AUTO_COM): ENV_DONOT_AUTO_COM.append( latex_input_completions.TEX_INPUT_FILE_REGEX) for rex in ENV_DONOT_AUTO_COM: if match(rex, line) is not None: return [] # load the completions for the document if is_env: completions = CWL_COMPLETIONS.get_completions(env=True) + \ get_own_env_completion(view) else: completions = CWL_COMPLETIONS.get_completions() + \ get_own_command_completion(view) # autocompleting with slash already on line # this is necessary to work around a short-coming in ST where having a # keyed entry appears to interfere with it recognising that there is a # \ already on the line # # NB this may not work if there are other punctuation marks in the # completion if is_prefixed: completions = [(c[0], c[1][1:]) if _is_snippet(c) else c for c in completions] return (completions, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
def get_tex_extensions(): view = sublime.active_window().active_view() tex_file_exts = get_setting('tex_file_exts', ['.tex']) return [s.lower() for s in set(tex_file_exts)]
def get_sublime_executable(): 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 plat_settings = get_setting(sublime.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_executable, 'result'): return get_sublime_executable.result # are we on ST3 if hasattr(sublime, 'executable_path'): get_sublime_executable.result = sublime.executable_path() return get_sublime_executable.result # in ST2 the Python executable is actually "sublime_text" elif sys.executable != 'python' and os.path.isabs(sys.executable): get_sublime_executable.result = sys.executable return get_sublime_executable.result # guess-work for ST2 startupinfo = None shell = False if sublime.platform() == 'windows': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW shell = _ST3 version = sublime.version() result = check_processes() if result is not None: get_sublime_executable.result = result return result platform = sublime.platform() # guess the default install location for ST2 on Windows if platform == 'windows': st2_dir = os.path.expandvars("%PROGRAMFILES%\\Sublime Text 2") result = check_processes(st2_dir) if result is not None: get_sublime_executable.result = result return result # guess some locations for ST2 on Linux 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_executable.result = result return result get_sublime_executable.result = None sublime.status_message( 'Cannot determine the path to your Sublime installation. Please ' + 'set the "sublime_executable" setting in your LaTeXTools.sublime-settings ' + 'file.') return None
def run(self, edit, **args): # Check prefs for PDF focus and sync keep_focus = args.get('keep_focus', get_setting('keep_focus', True)) forward_sync = args.get('forward_sync', get_setting('forward_sync', True)) # If invoked from keybinding, we sync # Rationale: if the user invokes the jump command, s/he wants to see # the result of the compilation. # If the PDF viewer window is already visible, s/he probably wants to # sync, or s/he would have no need to invoke the command. And if it is # not visible, the natural way to just bring up the window without # syncing is by using the system's window management shortcuts. # As for focusing, we honor the toggles / prefs. from_keybinding = args.pop("from_keybinding", False) if from_keybinding: forward_sync = True print(from_keybinding, keep_focus, forward_sync) view = self.view if not is_tex_file(view.file_name()): sublime.error_message("%s is not a TeX source file: cannot jump." % (os.path.basename(view.fileName()), )) return root = getTeXRoot.get_tex_root(view) file_name = get_jobname(root) output_directory = get_output_directory(view) if output_directory is None: pdffile = os.path.join(os.path.dirname(root), file_name + u'.pdf') else: pdffile = os.path.join(output_directory, file_name + u'.pdf') if not os.path.exists(pdffile): pdffile = os.path.join(os.path.dirname(root), file_name + u'.pdf') if not os.path.exists(pdffile): print("Expected PDF file {0} not found".format(pdffile)) return pdffile = os.path.realpath(pdffile) (line, col) = self.view.rowcol(self.view.sel()[0].end()) print("Jump to: ", line, col) # column is actually ignored up to 0.94 # HACK? It seems we get better results incrementing line line += 1 # issue #625: we need to pass the path to the file to the viewer when # there are files in subfolders of the main folder. # Thanks rstein and arahlin for this code! srcfile = self.view.file_name() try: viewer = get_viewer() except NoViewerException: return if forward_sync: try: viewer.forward_sync(pdffile, srcfile, line, col, keep_focus=keep_focus) except (AttributeError, NotImplementedError): try: viewer.view_file(pdffile, keep_focus=keep_focus) except (AttributeError, NotImplementedError): traceback.print_exc() sublime.error_message( 'Your viewer does not appear to be a proper' 'LaTeXTools viewer plugin. ' 'Please contact the plugin author.') return else: try: viewer.view_file(pdffile, keep_focus=keep_focus) except (AttributeError, NotImplementedError): traceback.print_exc() sublime.error_message( 'Your viewer does not appear to be a proper' 'LaTeXTools viewer plugin. ' 'Please contact the plugin author.') return if keep_focus: try: if viewer.supports_keep_focus(): return except (AttributeError, NotImplementedError): pass focus_st()
def run(self, edit, insert_char=""): view = self.view point = view.sel()[0].b # Only trigger within LaTeX # Note using score_selector rather than match_selector if not view.score_selector(point, "text.tex.latex"): return if insert_char: # append the insert_char to the end of the current line if it # is given so this works when being triggered by pressing "{" point += view.insert(edit, point, insert_char) do_completion = get_setting("fill_auto_trigger", True) if not do_completion: add_closing_bracket(view, edit) return prefix, completions = parse_completions( view, view.substr(sublime.Region(view.line(point).a, point))) if len(completions) == 0: result = [] elif not type(completions[0]) is tuple: result = completions else: tex_root = getTeXRoot.get_tex_root(self.view) if tex_root: root_path = os.path.dirname(tex_root) else: print("Can't find TeXroot. Assuming current directory is {0}".format(os.curdir)) root_path = os.curdir result = [[ # Replace backslash with forward slash to fix Windows paths # LaTeX does not support forward slashes in paths os.path.normpath(os.path.join(relpath, filename)).replace('\\', '/'), os.path.normpath(os.path.join(root_path, relpath, filename)) ] for relpath, filename in completions] def on_done(i): # Doing Nothing if i < 0: return if type(result[i]) is list: # if result[i] is a list, it comes from input, include and includegraphics key = result[i][0] else: key = result[i] # close bracket if insert_char: key += "}" startpos = point - len(prefix) view.run_command("latex_tools_replace", {"a": startpos, "b": point, "replacement": key}) caret = view.sel()[0].b view.sel().subtract(view.sel()[0]) view.sel().add(sublime.Region(caret, caret)) # autocomplete bracket if we aren't doing anything if not result and insert_char: add_closing_bracket(view, edit) else: view.window().show_quick_panel(result, on_done)
def is_enabled(self): return get_setting("glossary_auto_trigger", True)
def complete_auto_match(self, view, edit, insert_char): ''' Completes brackets if auto_match is enabled; also implements the "smart_bracket_auto_trigger" logic, which tries to complete the nearest open bracket intelligently. :param view: the current view :param edit: the current edit :param insert_char: the character to try to automatch ''' if sublime.load_settings('Preferences.sublime-settings').get( 'auto_match_enabled', True): # simple case: we have an insert char, insert closing char, # if its defined if insert_char: self.insert_at_end(view, edit, self.get_match_char(insert_char)) # if the insert_char is a bracket, move cursor to middle of # bracket and return if insert_char in self.MATCH_CHARS: new_regions = [] for sel in view.sel(): if not sel.empty(): new_regions.append(sel) else: new_point = sel.end() - 1 new_regions.append(getRegion(new_point, new_point)) self.update_selections(view, new_regions) return elif get_setting('smart_bracket_auto_trigger', True): # more complex: if we do not have an insert_char, try to close # the nearest bracket that occurs before each selection new_regions = [] for sel in view.sel(): word_region = self.get_current_word(view, sel) close_bracket = self.get_closing_bracket(view, word_region) # we should close the bracket if close_bracket: # insert the closing bracket view.insert(edit, word_region.end(), close_bracket) if sel.empty(): if word_region.empty(): new_regions.append( getRegion(word_region.end(), word_region.end())) else: new_point = word_region.end() + \ len(close_bracket) new_regions.append( getRegion(new_point, new_point)) else: new_regions.append( getRegion( sel.begin(), word_region.end() + len(close_bracket))) else: new_regions.append(sel) self.update_selections(view, new_regions)
def _ensure_okular(self, **kwargs): if not self._is_okular_running(): self._run_okular(**kwargs) time.sleep(get_setting('linux', {}).get('sync_wait') or 1.0)
def get_tex_extensions(): tex_file_exts = get_setting('tex_file_exts', ['.tex']) return [s.lower() for s in set(tex_file_exts)]
def get_ref_completions(view, point, autocompleting=False): # Get contents of line from start up to point line = view.substr(sublime.Region(view.line(point).a, point)) # print line # Reverse, to simulate having the regex # match backwards (cool trick jps btw!) line = line[::-1] #print line # Check the first location looks like a ref, but backward rex = OLD_STYLE_REF_REGEX expr = match(rex, line) # print expr if expr: # Do not match on plain "ref" when autocompleting, # in case the user is typing something else if autocompleting and re.match( r"p?fer(?:" + _ref_special_commands + r")?\\?", expr): raise UnrecognizedRefFormatError() # Return the matched bits, for mangling prefix, has_p, special_command = rex.match(expr).groups() preformatted = False if prefix: prefix = prefix[::-1] # reverse prefix = prefix[1:] # chop off "_" else: prefix = "" #print prefix, has_p, special_command else: # Check to see if the location matches a preformatted "\ref{blah" rex = NEW_STYLE_REF_REGEX expr = match(rex, line) if not expr: raise UnrecognizedRefFormatError() preformatted = True # Return the matched bits (barely needed, in this case) prefix, special_command, has_p = rex.match(expr).groups() if prefix: prefix = prefix[::-1] # reverse else: prefix = "" #print prefix, has_p, special_command pre_snippet = "\\" + special_command[::-1] + "ref{" post_snippet = "}" # If we captured a parenthesis, we need to put it back in # However, if the user had paren automatching, we don't want to add # another one. So by default we don't, unless the user tells us to # in the settings. # (HACKISH: I don't actually remember why we matched the initial paren!) if has_p: pre_snippet = "(" + pre_snippet add_paren = get_setting("ref_add_parenthesis", False) if add_paren: post_snippet = post_snippet + ")" if not preformatted: # Replace ref_blah with \ref{blah # The "latex_tools_replace" command is defined in latex_ref_cite_completions.py view.run_command( "latex_tools_replace", { "a": point - len(expr), "b": point, "replacement": pre_snippet + prefix }) # save prefix begin and endpoints points new_point_a = point - len(expr) + len(pre_snippet) new_point_b = new_point_a + len(prefix) # view.end_edit(ed) else: # Don't include post_snippet if it's already present suffix = view.substr(sublime.Region(point, point + len(post_snippet))) new_point_a = point - len(prefix) new_point_b = point if post_snippet == suffix: post_snippet = "" completions = [] # Check the file buffer first: # 1) in case there are unsaved changes # 2) if this file is unnamed and unsaved, get_tex_root will fail view.find_all(r'\\label\{([^\{\}]+)\}', 0, '\\1', completions) root = getTeXRoot.get_tex_root(view) if root: print("TEX root: " + repr(root)) find_labels_in_files(os.path.dirname(root), root, completions) # remove duplicates completions = list(set(completions)) return completions, prefix, post_snippet, new_point_a, new_point_b
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 _get_texpath(view): texpath = get_setting(sublime.platform(), {}, view).get('texpath') return expand_vars(texpath) if texpath is not None else None
def run_plugin_command(command, *args, **kwargs): ''' This function is intended to run a command against a user-configurable list of bibliography plugins set using the `bibliography` setting. Parameters: `command`: a string representing the command to invoke, which should generally be the name of a function to be called on the plugin class. `*args`: the args to pass to the function `**kwargs`: the keyword args to pass to the function Additionally, the following keyword parameters can be specified to control how this function works: `stop_on_first`: if True (default), no more attempts will be made to run the command after the first plugin that returns a non-None result `expect_result`: if True (default), a BibPluginError will be raised if no plugin returns a non-None result Example: run_plugin_command('get_entries', *bib_files) This will attempt to invoke the `get_entries` method of any configured plugin, passing in the discovered bib_files, and returning the result. The general assumption of this function is that we only care about the first valid result returned from a plugin and that plugins that should not handle a request will either not implement the method or implement a version of the method which raises a NotImplementedError if that plugin should not handle the current situation. ''' stop_on_first = kwargs.pop('stop_on_first', True) expect_result = kwargs.pop('expect_result', True) def _run_command(plugin_name): plugin = None try: plugin = latextools_plugin.get_plugin(plugin_name) except latextools_plugin.NoSuchPluginException: pass if not plugin: error_message = 'Could not find bibliography plugin named {0}. Please ensure your LaTeXTools.sublime-settings is configured correctly.'.format( plugin_name) print(error_message) raise BibPluginError(error_message) # instantiate plugin try: plugin = plugin() except: error_message = 'Could not instantiate {0}. {0} must have a no-args __init__ method'.format( type(plugin).__name__, ) print(error_message) raise BibPluginError(error_message) try: result = getattr(plugin, command)(*args, **kwargs) except TypeError as e: if "'{0}()'".format(command) in str(e): error_message = '{1} is not properly implemented by {0}.'.format( type(plugin).__name__, command) print(error_message) raise BibPluginError(error_message) else: reraise(*sys.exc_info()) except AttributeError as e: if "'{0}'".format(command) in str(e): error_message = '{0} does not implement `{1}`'.format( type(plugin).__name__, command) print(error_message) raise BibPluginError(error_message) else: reraise(*sys.exc_info()) except NotImplementedError: return None return result plugins = get_setting('bibliography', ['traditional']) if not plugins: print('bibliography setting is blank. Loading traditional plugin.') plugins = 'traditional' result = None if isinstance(plugins, strbase): if not plugins.endswith('_bibliography'): plugins = '{0}_bibliography'.format(plugins) result = _run_command(plugins) else: for plugin_name in plugins: if not plugin_name.endswith('_bibliography'): plugin_name = '{0}_bibliography'.format(plugin_name) try: result = _run_command(plugin_name) except BibPluginError: continue if stop_on_first and result is not None: break if expect_result and result is None: raise BibPluginError( "Could not find a plugin to handle '{0}'. See the console for more details" .format(command)) return result
def run(self, edit, **args): # Check prefs for PDF focus and sync keep_focus = get_setting('keep_focus', True) forward_sync = get_setting('forward_sync', True) prefs_lin = get_setting("linux", {}) prefs_win = get_setting("windows", {}) # If invoked from keybinding, we sync # Rationale: if the user invokes the jump command, s/he wants to see the result of the compilation. # If the PDF viewer window is already visible, s/he probably wants to sync, or s/he would have no # need to invoke the command. And if it is not visible, the natural way to just bring up the # window without syncing is by using the system's window management shortcuts. # As for focusing, we honor the toggles / prefs. from_keybinding = args[ "from_keybinding"] if "from_keybinding" in args else False if from_keybinding: forward_sync = True print(from_keybinding, keep_focus, forward_sync) if not is_tex_file(self.view.file_name()): sublime.error_message("%s is not a TeX source file: cannot jump." % (os.path.basename(view.fileName()), )) return quotes = "\"" root = getTeXRoot.get_tex_root(self.view) print("!TEX root = ", repr(root)) # need something better here, but this works. rootName, rootExt = os.path.splitext(root) pdffile = rootName + u'.pdf' (line, col) = self.view.rowcol(self.view.sel()[0].end()) print("Jump to: ", line, col) # column is actually ignored up to 0.94 # HACK? It seems we get better results incrementing line line += 1 # issue #625: we need to pass the path to the file to the viewer when # there are files in subfolders of the main folder. # Thanks rstein and arahlin for this code! srcfile = self.view.file_name() # Query view settings to see if we need to keep focus or let the PDF viewer grab it # By default, we respect settings in Preferences # platform-specific code: plat = sublime_plugin.sys.platform if plat == 'darwin': options = ["-r", "-g"] if keep_focus else ["-r"] if forward_sync: path_to_skim = '/Applications/Skim.app/' if not os.path.exists(path_to_skim): path_to_skim = subprocess.check_output([ 'osascript', '-e', 'POSIX path of (path to app id "net.sourceforge.skim-app.skim")' ]).decode("utf8")[:-1] subprocess.Popen([ os.path.join(path_to_skim, "Contents/SharedSupport/displayline") ] + options + [str(line), pdffile, srcfile]) else: skim = os.path.join(sublime.packages_path(), 'LaTeXTools', 'skim', 'displayfile') subprocess.Popen(['sh', skim] + options + [pdffile]) elif plat == 'win32': # determine if Sumatra is running, launch it if not print("Windows, Calling Sumatra") si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW si.wShowWindow = 4 #constant for SHOWNOACTIVATE su_binary = prefs_win.get("sumatra", "SumatraPDF.exe") or 'SumatraPDF.exe' startCommands = [su_binary, "-reuse-instance"] if forward_sync: startCommands.append("-forward-search") startCommands.append(srcfile) startCommands.append(str(line)) startCommands.append(pdffile) subprocess.Popen(startCommands, startupinfo=si) if keep_focus: self.focus_st() elif 'linux' in plat: # for some reason, I get 'linux2' from sys.platform print("Linux!") # the required scripts are in the 'evince' subdir ev_path = os.path.join(sublime.packages_path(), 'LaTeXTools', 'evince') ev_fwd_exec = os.path.join(ev_path, 'evince_forward_search') ev_sync_exec = os.path.join(ev_path, 'evince_sync') # for inverse search! #print ev_fwd_exec, ev_sync_exec # Run evince if either it's not running, or if focus PDF was toggled # Sadly ST2 has Python <2.7, so no check_output: running_apps = subprocess.Popen( ['ps', 'xw'], stdout=subprocess.PIPE).communicate()[0] # If there are non-ascii chars in the output just captured, we will fail. # Thus, decode using the 'ignore' option to simply drop them---we don't need them running_apps = running_apps.decode( sublime_plugin.sys.getdefaultencoding(), 'ignore') # Run scripts through sh because the script files will lose their exec bit on github # Get python binary if set: py_binary = prefs_lin["python2"] or 'python' sb_binary = prefs_lin["sublime"] or 'sublime-text' # How long we should wait after launching sh before syncing sync_wait = prefs_lin["sync_wait"] or 1.0 evince_running = ("evince " + pdffile in running_apps) if (not keep_focus) or (not evince_running): print("(Re)launching evince") subprocess.Popen( ['sh', ev_sync_exec, py_binary, sb_binary, pdffile], cwd=ev_path) print("launched evince_sync") if not evince_running: # Don't wait if we have already shown the PDF time.sleep(sync_wait) if forward_sync: subprocess.Popen( [py_binary, ev_fwd_exec, pdffile, str(line), srcfile]) if keep_focus: self.focus_st() else: # ??? pass
def __init__(self, tex_root): self.tex_root = tex_root # although this could change, currently only the value when the # cache is created is relevant self.hide_cache = get_setting('hide_local_cache', True) super(LocalCache, self).__init__()
def _get_plugin_paths(): plugin_paths = get_setting('plugin_paths', []) return plugin_paths
def run(self, cmd="", file_regex="", path=""): # Try to handle killing with self.proc_lock: if self.proc: # if we are running, try to kill running process self.output("\n\n### Got request to terminate compilation ###") if sublime.platform() == 'windows': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW subprocess.call( 'taskkill /t /f /pid {pid}'.format(pid=self.proc.pid), startupinfo=startupinfo, shell=True) else: os.killpg(self.proc.pid, signal.SIGTERM) self.proc = None return else: # either it's the first time we run, or else we have no running processes self.proc = None view = self.view = self.window.active_view() if view.is_dirty(): print("saving...") view.run_command('save') # call this on view, not self.window if view.file_name() is None: sublime.error_message( 'Please save your file before attempting to build.') return self.file_name = getTeXRoot.get_tex_root(view) if not os.path.isfile(self.file_name): sublime.error_message(self.file_name + ": file not found.") return self.tex_base, self.tex_ext = os.path.splitext(self.file_name) tex_dir = os.path.dirname(self.file_name) if not is_tex_file(self.file_name): sublime.error_message( "%s is not a TeX source file: cannot compile." % (os.path.basename(view.file_name()), )) return # Output panel: from exec.py if not hasattr(self, 'output_view'): self.output_view = self.window.get_output_panel("exec") # Dumb, but required for the moment for the output panel to be picked # up as the result buffer self.window.get_output_panel("exec") self.output_view.settings().set( "result_file_regex", "^([^:\n\r]*):([0-9]+):?([0-9]+)?:? (.*)$") # self.output_view.settings().set("result_line_regex", line_regex) self.output_view.settings().set("result_base_dir", tex_dir) self.window.run_command("show_panel", {"panel": "output.exec"}) self.output_view.settings().set("result_file_regex", file_regex) self.plat = sublime.platform() if self.plat == "osx": self.encoding = "UTF-8" elif self.plat == "windows": self.encoding = getOEMCP() elif self.plat == "linux": self.encoding = "UTF-8" else: sublime.error_message("Platform as yet unsupported. Sorry!") return # Get platform settings, builder, and builder settings platform_settings = get_setting(self.plat, {}) builder_name = get_setting("builder", "traditional") self.hide_panel_level = get_setting("hide_build_panel", "never") self.display_bad_boxes = get_setting("display_bad_boxes", False) # This *must* exist, so if it doesn't, the user didn't migrate if builder_name is None: sublime.error_message( "LaTeXTools: you need to migrate your preferences. See the README file for instructions." ) return # Default to 'traditional' builder if builder_name in ['', 'default']: builder_name = 'traditional' # relative to ST packages dir! builder_path = get_setting("builder_path", "") builder_file_name = builder_name + 'Builder.py' builder_class_name = builder_name.capitalize() + 'Builder' builder_settings = get_setting("builder_settings", {}) # parse root for any %!TEX directives tex_directives = parse_tex_directives( self.file_name, multi_values=['options'], key_maps={'ts-program': 'program'}) # determine the engine engine = tex_directives.get( 'program', builder_settings.get("program", "pdflatex")) engine = engine.lower() # Sanity check: if "strange" engine, default to pdflatex (silently...) if engine not in [ 'pdflatex', "pdftex", 'xelatex', 'xetex', 'lualatex', 'luatex' ]: engine = 'pdflatex' options = builder_settings.get("options", []) if isinstance(options, strbase): options = [options] if 'options' in tex_directives: options.extend(tex_directives['options']) # Read the env option (platform specific) builder_platform_settings = builder_settings.get(self.plat) if builder_platform_settings: self.env = builder_platform_settings.get("env", None) else: self.env = None # Safety check: if we are using a built-in builder, disregard # builder_path, even if it was specified in the pref file if builder_name in ['simple', 'traditional', 'script', 'default', '']: builder_path = None # Now actually get the builder ltt_path = os.path.join(sublime.packages_path(), 'LaTeXTools', 'builders') if builder_path: bld_path = os.path.join(sublime.packages_path(), builder_path) else: bld_path = ltt_path bld_file = os.path.join(bld_path, builder_file_name) if not os.path.isfile(bld_file): sublime.error_message("Cannot find builder " + builder_name + ".\n" \ "Check your LaTeXTools Preferences") return # We save the system path and TEMPORARILY add the builders path to it, # so we can simply "import pdfBuilder" in the builder module # For custom builders, we need to add both the LaTeXTools builders # path, as well as the custom path specified above. # The mechanics are from http://effbot.org/zone/import-string.htm syspath_save = list(sys.path) sys.path.insert(0, ltt_path) if builder_path: sys.path.insert(0, bld_path) builder_module = __import__(builder_name + 'Builder') sys.path[:] = syspath_save print(repr(builder_module)) builder_class = getattr(builder_module, builder_class_name) print(repr(builder_class)) # We should now be able to construct the builder object self.builder = builder_class(self.file_name, self.output, engine, options, tex_directives, builder_settings, platform_settings) # Restore Python system path sys.path[:] = syspath_save # Now get the tex binary path from prefs, change directory to # that of the tex root file, and run! self.path = platform_settings['texpath'] os.chdir(tex_dir) CmdThread(self).start() print(threading.active_count())
def plugin_loaded(): # get additional entries from the settings _setting_entries = get_setting("fillall_helper_entries", []) _filter_invalid_entries(_setting_entries) _fillall_entries.extend(_setting_entries) _fillall_entries.extend([ # input/include { "regex": r'(?:edulcni|tupni)\\', "extensions": [e[1:] for e in get_tex_extensions()], "strip_extensions": [".tex"] }, # includegraphics { "regex": r'(?:\][^{}\[\]]*\[)?scihpargedulcni\\', "extensions": get_setting("image_types", ["pdf", "png", "jpeg", "jpg", "eps"]) }, # import/subimport { "regex": r'\*?(?:tropmibus)\\', "extensions": [e[1:] for e in get_tex_extensions()], "strip_extensions": [".tex"], "post_process": "path_only" }, { "regex": r'\}[^{}\[\]]*\{\*?(?:tropmi|morftupni|morfedulcni)?bus\\', "extensions": [e[1:] for e in get_tex_extensions()], "strip_extensions": [".tex"], "post_regex": (r'\\sub(?:import|includefrom|inputfrom)\*?' r'\{([^{}\[\]]*)\}\{[^\}]*?$'), "folder": "$base/$_1" }, { "regex": r'\}[^{}\[\]]*\{\*?(?:tropmi|morftupni|morfedulcni)\\', "extensions": [e[1:] for e in get_tex_extensions()], "strip_extensions": [".tex"], "post_regex": (r'\\(?:import|includefrom|inputfrom)\*?' r'\{([^{}\[\]]*)\}\{[^\}]*?$'), "folder": "$_1" }, { "regex": r'(?:\][^{}\[\]]*\[)?ecruoserbibdda\\', "extensions": ["bib"] }, { "regex": r'yhpargoilbib\\', "extensions": ["bib"], "strip_extensions": [".bib"], "comma_separated": True } ]) # update the fields of the entries _update_input_entries(_fillall_entries) _fillall_entries.extend([{ "regex": r'([^{}\[\]]*)\{(?:\][^{}\[\]]*\[)?ssalctnemucod\\', "type": "cached", "cache_name": "cls" }, { "regex": r'([^{}\[\]]*)\{(?:\][^{}\[\]]*\[)?egakcapesu\\', "type": "cached", "cache_name": "pkg" }, { "regex": r'([^{}\[\]]*)\{elytsyhpargoilbib\\', "type": "cached", "cache_name": "bst" }]) global _TEX_INPUT_GROUP_MAPPING, TEX_INPUT_FILE_REGEX _TEX_INPUT_GROUP_MAPPING = dict( (i, v) for i, v in enumerate(_fillall_entries)) TEX_INPUT_FILE_REGEX = re.compile("(?:{0})".format("|".join( entry["regex"] for entry in _fillall_entries)))
def parse_completions(view, line): # reverse line, copied from latex_cite_completions, very cool :) line = line[::-1] # Do matches! search = TEX_INPUT_FILE_REGEX.match(line) installed_cls = [] installed_bst = [] installed_pkg = [] input_file_types = None if search is not None: ( include_filter, input_filter, image_filter, svg_filter, addbib_filter, bib_filter, cls_filter, pkg_filter, bst_filter) = search.groups() else: return '', [] # it isn't always correct to include the extension in the output filename # esp. with \bibliography{}; here we provide a mechanism to permit this filter_exts = [] if include_filter is not None: # if is \include prefix = include_filter[::-1] # filter the . from the start of the extention input_file_types = [e[1:] for e in get_tex_extensions()] # only cut off the .tex extension filter_exts = ['.tex'] elif input_filter is not None: # if is \input search type set to tex prefix = input_filter[::-1] # filter the . from the start of the extension input_file_types = [e[1:] for e in get_tex_extensions()] # only cut off the .tex extension filter_exts = ['.tex'] elif image_filter is not None: # if is \includegraphics prefix = image_filter[::-1] # Load image types from configurations # In order to user input, "image_types" must be set in # LaTeXTools.sublime-settings configuration file or the # project settings for the current view. input_file_types = get_setting('image_types', [ 'pdf', 'png', 'jpeg', 'jpg', 'eps' ]) elif svg_filter is not None: # if is \includesvg prefix = svg_filter[::-1] # include only svg files input_file_types = ['svg'] # cut off the svg extention filter_exts = ['.svg'] elif addbib_filter is not None or bib_filter is not None: # For bibliography if addbib_filter is not None: prefix = addbib_filter[::-1] else: prefix = '' bib_filter[::-1] filter_exts = ['.bib'] input_file_types = ['bib'] elif cls_filter is not None or pkg_filter is not None or bst_filter is not None: # for packages, classes and bsts if _ST3: cache_path = os.path.normpath( os.path.join( sublime.cache_path(), "LaTeXTools" )) else: cache_path = os.path.normpath( os.path.join( sublime.packages_path(), "User" )) pkg_cache_file = os.path.normpath( os.path.join(cache_path, 'pkg_cache.cache' if _ST3 else 'latextools_pkg_cache.cache')) cache = None if not os.path.exists(pkg_cache_file): gen_cache = sublime.ok_cancel_dialog("Cache files for installed packages, " + "classes and bibliographystyles do not exists, " + "would you like to generate it? After generating complete, please re-run this completion action!" ) if gen_cache: sublime.active_window().run_command("latex_gen_pkg_cache") completions = [] else: with open(pkg_cache_file) as f: cache = json.load(f) if cache is not None: if cls_filter is not None: installed_cls = cache.get("cls") elif bst_filter is not None: installed_bst = cache.get("bst") else: installed_pkg = cache.get("pkg") prefix = '' else: prefix = '' if len(installed_cls) > 0: completions = installed_cls elif len(installed_bst) > 0: completions = installed_bst elif len(installed_pkg) > 0: completions = installed_pkg elif input_file_types is not None: root = getTeXRoot.get_tex_root(view) if root: completions = get_file_list(root, input_file_types, filter_exts) else: # file is unsaved completions = [] return prefix, completions
def _latextools_module_hack(): ''' Context manager to ensure sys.modules has certain white-listed modules, most especially latextools_plugins. This exposes some of the modules in LaTeXTools to plugins. It is intended primarily to expose library-esque functionality, such as the getTeXRoot module, but can be configured by the user as-needed. ''' # add any white-listed plugins to sys.modules under their own name plugins_whitelist = get_setting( 'plugins_whitelist', ['external', 'getTeXRoot', 'kpsewhich', 'latextools_utils']) # always include latextools_pluing plugins_whitelist.append('latextools_plugin') overwritten_modules = {} whitelist = [(name, None) for name in plugins_whitelist] whitelist.extend(internal._WHITELIST_ADDED) # put the directory containing this file on the sys.path __dir__ = os.path.dirname(__file__) # handles ST2s relative directory if __dir__ == '.': __dir__ = os.path.join(sublime.packages_path(), 'LaTeXTools') # insert the LaTeXTools directory on the path sys.path.insert(0, __dir__) for name, module in whitelist: if callable(module): module = module() if name in sys.modules: overwritten_modules[name] = sys.modules[name] # attempting to autoload module if module is None: # if the module has already been loaded by ST, we just use that latextools_module_name = _get_sublime_module_name(__dir__, name) if latextools_module_name in sys.modules: sys.modules[name] = sys.modules[latextools_module_name] else: try: sys.modules[name] = _load_module(name, name, __dir__) except ImportError: print( 'An error occurred while trying to load white-listed ' 'module {0}'.format(name)) traceback.print_exc() else: sys.modules[name] = module # remove the LaTeXTools directory from the path sys.path.pop(0) yield # restore any temporarily overwritten modules and clear our loaded modules for module in plugins_whitelist: if _get_sublime_module_name(__dir__, module) != module: sys.modules[module] = None if module in overwritten_modules: sys.modules[module] = overwritten_modules[module]
def run(self, file_regex="", program=None, builder=None, command=None, env=None, path=None, script_commands=None, update_phantoms_only=False, hide_phantoms_only=False, **kwargs): if update_phantoms_only: if self.show_errors_inline: self.update_phantoms() return if hide_phantoms_only: self.hide_phantoms() return # Try to handle killing with self.proc_lock: if self.proc: # if we are running, try to kill running process self.output("\n\n### Got request to terminate compilation ###") try: if sublime.platform() == 'windows': execute_command('taskkill /t /f /pid {pid}'.format( pid=self.proc.pid), use_texpath=False) else: os.killpg(self.proc.pid, signal.SIGTERM) except: print('Exception occurred while killing build') traceback.print_exc() self.proc = None return else: # either it's the first time we run, or else we have no running processes self.proc = None view = self.view = self.window.active_view() if _HAS_PHANTOMS: self.hide_phantoms() pref_settings = sublime.load_settings( "Preferences.sublime-settings") self.show_errors_inline = pref_settings.get( "show_errors_inline", True) if view.is_dirty(): print("saving...") view.run_command('save') # call this on view, not self.window if view.file_name() is None: sublime.error_message( 'Please save your file before attempting to build.') return self.file_name = getTeXRoot.get_tex_root(view) if not os.path.isfile(self.file_name): sublime.error_message(self.file_name + ": file not found.") return self.tex_base = get_jobname(view) self.tex_dir = os.path.dirname(self.file_name) if not is_tex_file(self.file_name): sublime.error_message( "%s is not a TeX source file: cannot compile." % (os.path.basename(view.file_name()), )) return # Output panel: from exec.py if not hasattr(self, 'output_view'): self.output_view = self.window.get_output_panel("latextools") output_view_settings = self.output_view.settings() output_view_settings.set("result_file_regex", file_regex) output_view_settings.set("result_base_dir", self.tex_dir) output_view_settings.set("line_numbers", False) output_view_settings.set("gutter", False) output_view_settings.set("scroll_past_end", False) if get_setting("highlight_build_panel", True, view=view): self.output_view.set_syntax_file( "Packages/LaTeXTools/LaTeXTools Console.hidden-tmLanguage") output_view_settings.set( "color_scheme", sublime.load_settings('Preferences.sublime-settings').get( 'color_scheme')) self.output_view.set_read_only(True) # Dumb, but required for the moment for the output panel to be picked # up as the result buffer self.window.get_output_panel("latextools") self.hide_panel_level = get_setting("hide_build_panel", "no_warnings", view=view) if self.hide_panel_level == "never": self.show_output_panel(force=True) self.plat = sublime.platform() if self.plat == "osx": self.encoding = "UTF-8" elif self.plat == "windows": self.encoding = getOEMCP() elif self.plat == "linux": self.encoding = "UTF-8" else: sublime.error_message("Platform as yet unsupported. Sorry!") return # Get platform settings, builder, and builder settings platform_settings = get_setting(self.plat, {}, view=view) self.display_bad_boxes = get_setting("display_bad_boxes", False, view=view) if builder is not None: builder_name = builder else: builder_name = get_setting("builder", "traditional", view=view) # Default to 'traditional' builder if builder_name in ['', 'default']: builder_name = 'traditional' # this is to convert old-style names (e.g. AReallyLongName) # to new style plugin names (a_really_long_name) builder_name = _classname_to_internal_name(builder_name) builder_settings = get_setting("builder_settings", {}, view=view) # override the command if command is not None: builder_settings.set("command", command) # parse root for any %!TEX directives tex_directives = parse_tex_directives( self.file_name, multi_values=['options'], key_maps={'ts-program': 'program'}) # determine the engine if program is not None: engine = program else: engine = tex_directives.get( 'program', builder_settings.get("program", "pdflatex")) engine = engine.lower() # Sanity check: if "strange" engine, default to pdflatex (silently...) if engine not in [ 'pdflatex', "pdftex", 'xelatex', 'xetex', 'lualatex', 'luatex' ]: engine = 'pdflatex' options = builder_settings.get("options", []) if isinstance(options, strbase): options = [options] if 'options' in tex_directives: options.extend(tex_directives['options']) # filter out --aux-directory and --output-directory options which are # handled separately options = [ opt for opt in options if (not opt.startswith('--aux-directory') and not opt.startswith( '--output-directory') and not opt.startswith('--jobname')) ] self.aux_directory = get_aux_directory(view) self.output_directory = get_output_directory(view) # Read the env option (platform specific) builder_platform_settings = builder_settings.get(self.plat, {}) if env is not None: self.env = env elif builder_platform_settings: self.env = builder_platform_settings.get("env", None) else: self.env = None # Safety check: if we are using a built-in builder, disregard # builder_path, even if it was specified in the pref file if builder_name in ['simple', 'traditional', 'script', 'basic']: builder_path = None else: # relative to ST packages dir! builder_path = get_setting("builder_path", "", view=view) if builder_path: bld_path = os.path.join(sublime.packages_path(), builder_path) add_plugin_path(bld_path) try: builder = get_plugin('{0}_builder'.format(builder_name)) except NoSuchPluginException: try: builder = get_plugin(builder_name) except NoSuchPluginException: sublime.error_message( "Cannot find builder {0}.\n" "Check your LaTeXTools Preferences".format(builder_name)) self.window.run_command('hide_panel', {"panel": "output.latextools"}) return if builder_name == 'script' and script_commands: builder_platform_settings['script_commands'] = script_commands builder_settings[self.plat] = builder_platform_settings print(repr(builder)) self.builder = builder(self.file_name, self.output, engine, options, self.aux_directory, self.output_directory, self.tex_base, tex_directives, builder_settings, platform_settings) # Now get the tex binary path from prefs, change directory to # that of the tex root file, and run! if path is not None: self.path = path else: self.path = get_texpath() or os.environ['PATH'] thread = CmdThread(self) thread.start() print(threading.active_count()) # setup the progress indicator display_message_length = long( get_setting('build_finished_message_length', 2.0, view=view) * 1000) # NB CmdThread will change the success message self.progress_indicator = ProgressIndicator( thread, 'Building', 'Build failed', display_message_length=display_message_length)
def is_enabled(self): return get_setting('ref_auto_trigger', True)
def run(self, cmd="", file_regex="", path=""): # Try to handle killing with self.proc_lock: if self.proc: # if we are running, try to kill running process self.output("\n\n### Got request to terminate compilation ###") if sublime.platform() == 'windows': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW subprocess.call( 'taskkill /t /f /pid {pid}'.format(pid=self.proc.pid), startupinfo=startupinfo, shell=True) else: os.killpg(self.proc.pid, signal.SIGTERM) self.proc = None return else: # either it's the first time we run, or else we have no running processes self.proc = None view = self.view = self.window.active_view() if view.is_dirty(): print("saving...") view.run_command('save') # call this on view, not self.window if view.file_name() is None: sublime.error_message( 'Please save your file before attempting to build.') return self.file_name = getTeXRoot.get_tex_root(view) if not os.path.isfile(self.file_name): sublime.error_message(self.file_name + ": file not found.") return self.tex_base = get_jobname(view) self.tex_dir = os.path.dirname(self.file_name) if not is_tex_file(self.file_name): sublime.error_message( "%s is not a TeX source file: cannot compile." % (os.path.basename(view.file_name()), )) return # Output panel: from exec.py if not hasattr(self, 'output_view'): self.output_view = self.window.get_output_panel("latextools") output_view_settings = self.output_view.settings() output_view_settings.set("result_file_regex", file_regex) output_view_settings.set("result_base_dir", self.tex_dir) output_view_settings.set("line_numbers", False) output_view_settings.set("gutter", False) output_view_settings.set("scroll_past_end", False) if get_setting("highlight_build_panel", True): self.output_view.set_syntax_file( "Packages/LaTeXTools/LaTeXTools Console.hidden-tmLanguage") output_view_settings.set( "color_scheme", sublime.load_settings('Preferences.sublime-settings').get( 'color_scheme')) self.output_view.set_read_only(True) # Dumb, but required for the moment for the output panel to be picked # up as the result buffer self.window.get_output_panel("latextools") self.hide_panel_level = get_setting("hide_build_panel", "never") if self.hide_panel_level != "always": self.window.run_command("show_panel", {"panel": "output.latextools"}) self.plat = sublime.platform() if self.plat == "osx": self.encoding = "UTF-8" elif self.plat == "windows": self.encoding = getOEMCP() elif self.plat == "linux": self.encoding = "UTF-8" else: sublime.error_message("Platform as yet unsupported. Sorry!") return # Get platform settings, builder, and builder settings platform_settings = get_setting(self.plat, {}) builder_name = get_setting("builder", "traditional") self.display_bad_boxes = get_setting("display_bad_boxes", False) # This *must* exist, so if it doesn't, the user didn't migrate if builder_name is None: sublime.error_message( "LaTeXTools: you need to migrate your preferences. See the README file for instructions." ) self.window.run_command('hide_panel', {"panel": "output.latextools"}) return # Default to 'traditional' builder if builder_name in ['', 'default']: builder_name = 'traditional' # this is to convert old-style names (e.g. AReallyLongName) # to new style plugin names (a_really_long_name) builder_name = _classname_to_internal_name(builder_name) builder_settings = get_setting("builder_settings", {}) # parse root for any %!TEX directives tex_directives = parse_tex_directives( self.file_name, multi_values=['options'], key_maps={'ts-program': 'program'}) # determine the engine engine = tex_directives.get( 'program', builder_settings.get("program", "pdflatex")) engine = engine.lower() # Sanity check: if "strange" engine, default to pdflatex (silently...) if engine not in [ 'pdflatex', "pdftex", 'xelatex', 'xetex', 'lualatex', 'luatex' ]: engine = 'pdflatex' options = builder_settings.get("options", []) if isinstance(options, strbase): options = [options] if 'options' in tex_directives: options.extend(tex_directives['options']) # filter out --aux-directory and --output-directory options which are # handled separately options = [ opt for opt in options if (not opt.startswith('--aux-directory') and not opt.startswith( '--output-directory') and not opt.startswith('--jobname')) ] self.aux_directory = get_aux_directory(self.file_name) self.output_directory = get_output_directory(self.file_name) # Read the env option (platform specific) builder_platform_settings = builder_settings.get(self.plat) if builder_platform_settings: self.env = builder_platform_settings.get("env", None) else: self.env = None # Now actually get the builder builder_path = get_setting("builder_path", "") # relative to ST packages dir! # Safety check: if we are using a built-in builder, disregard # builder_path, even if it was specified in the pref file if builder_name in ['simple', 'traditional', 'script', 'basic']: builder_path = None if builder_path: bld_path = os.path.join(sublime.packages_path(), builder_path) add_plugin_path(bld_path) try: builder = get_plugin('{0}_builder'.format(builder_name)) except NoSuchPluginException: sublime.error_message("Cannot find builder " + builder_name + ".\n" \ "Check your LaTeXTools Preferences") self.window.run_command('hide_panel', {"panel": "output.latextools"}) return print(repr(builder)) self.builder = builder(self.file_name, self.output, engine, options, self.aux_directory, self.output_directory, self.tex_base, tex_directives, builder_settings, platform_settings) # Now get the tex binary path from prefs, change directory to # that of the tex root file, and run! self.path = platform_settings['texpath'] CmdThread(self).start() print(threading.active_count())
def run(self, edit, insert_char=""): view = self.view point = view.sel()[0].b # Only trigger within LaTeX # Note using score_selector rather than match_selector if not view.score_selector(point, "text.tex.latex"): return if not is_cwl_available(): if insert_char: view.insert(edit, point, insert_char) add_closing_bracket(view, edit) return if insert_char: # append the insert_char to the end of the current line if it # is given so this works when being triggered by pressing "{" point += view.insert(edit, point, insert_char) do_completion = get_setting("env_auto_trigger", False) if not do_completion: add_closing_bracket(view, edit) return if not insert_char: # only use the prefix if all cursors have the same prefix = get_current_word(view, point)[0] for sel in view.sel(): other_prefix = get_current_word(view, sel.b)[0] if other_prefix != prefix: prefix = "" break else: prefix = "" completions = parse_cwl_file(parse_line_as_environment) if prefix: completions = [c for c in completions if c[1].startswith(prefix)] show_entries = [c[0].split("\t") for c in completions] def on_done(index): if index < 0: return key = completions[index][1] # close bracket if insert_char: key += "}" if prefix: for sel in view.sel(): point = sel.b startpoint = point - len(prefix) endpoint = point view.run_command('latex_tools_replace', { 'a': startpoint, 'b': endpoint, 'replacement': key }) else: view.run_command("insert", {"characters": key}) # autocomplete bracket if we aren't doing anything if not show_entries and insert_char: add_closing_bracket(view, edit) else: view.window().show_quick_panel(show_entries, on_done)
def on_query_context(self, view, key, *args): if (key != "overwrite_goto_overlay" or not view.score_selector(0, "text.tex.latex")): return None return get_setting("overwrite_goto_overlay")
def is_enabled(self): return get_setting("tex_directive_auto_trigger", True)
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 _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' ]) 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 using_texify_or_simple(): if using_miktex(): builder = get_setting('builder', 'traditional') if builder in ['', 'default', 'traditional', 'simple']: return True return False
def get_closing_bracket(self, view, sel): ''' Determines if the nearest bracket that occurs before the given selection is closed. If the bracket should be closed, returns the closing bracket to use. Note that this will not work if the arguments to the command span multiple lines, but we generally don't support that anyway. :param view: the current view :param sel: a sublime.Region indicating the selected area ''' # candidates stores matched bracket-pairs so that we only have # to find all matches once per bracket type # if the view has changed, we reset the candidates candidates = None if not hasattr(self, 'last_view') or self.last_view != view.id(): self.last_view = view.id() self.use_full_scan = get_setting( 'smart_bracket_scan_full_document', False) candidates = self.candidates = {} if not self.use_full_scan: # always clear the candidates when not using a full scan candidates = {} # when not using a full scan, get the number of lines to # look-behind try: look_around = int(get_setting('smart_bracket_look_around', 5)) except ValueError: look_around = 5 if candidates is None: try: candidates = self.candidates except: candidates = self.candidates = {} # first, find the nearest bracket if type(sel) is sublime.Region: start, end = sel.begin(), sel.end() else: start = end = sel if self.use_full_scan: prefix = view.substr(getRegion(0, start)) prefix_start = 0 suffix_end = view.size() else: prefix_lines = view.lines(getRegion(0, start)) if len(prefix_lines) >= look_around: prefix_start = prefix_lines[-look_around].begin() else: prefix_start = prefix_lines[0].begin() suffix_lines = view.lines(getRegion(end, view.size())) if len(suffix_lines) >= look_around: suffix_end = suffix_lines[look_around - 1].end() else: suffix_end = suffix_lines[-1].end() prefix = view.substr(getRegion(prefix_start, start)) open_bracket, last_index = None, -1 for char in self.MATCH_CHARS: index = prefix.rfind(char) if index > last_index: open_bracket, last_index = char, index if last_index == -1: # can't determine bracket to match return None close_bracket = self.MATCH_CHARS[open_bracket] open_brackets = [] # this is used to throw-away as many matches as possible # so subsequent requests don't need to consider every match closed_brackets = [] if open_bracket not in candidates: # find all open / close brackets in the current buffer, # removing all comments candidates[open_bracket] = results = [] start = prefix_start re_str = re.escape(open_bracket) + '|' + re.escape(close_bracket) while True: if start >= suffix_end: break c = view.find(re_str, start) if c is None or c.begin() == -1: break if c.end() > suffix_end: break if view.score_selector(c.begin(), 'comment') != 0: start = c.end() continue results.append(c) start = c.end() for candidate in candidates[open_bracket]: if view.substr(candidate) == open_bracket: if len(open_brackets) == 0 and candidate.begin() > end: break open_brackets.append(candidate) else: try: removed = open_brackets.pop() if candidate.end() < start: closed_brackets.append(removed) closed_brackets.append(candidate) except IndexError: # unbalanced close before open if candidate.end() > end: break if len(closed_brackets) > 0: candidates[open_bracket] = [ c for c in candidates[open_bracket] if c not in closed_brackets ] # if we have an open bracket left, then the current bracket needs to # be closed return close_bracket if len(open_brackets) > 0 else None