def forward_sync(self, pdf_file, tex_file, line, col, **kwargs): keep_focus = kwargs.pop('keep_focus', True) # we check for the pid here as this is only necessary if # we aren't otherwise creating the window pid = self._get_zathura_pid(pdf_file) if pid is None: pid = self._run_zathura(pdf_file) if keep_focus: self.focus_st() command = [ 'zathura', '--synctex-forward', '{line}:{col}:{tex_file}'.format(**locals()), ] if pid is None: command.append(self._get_synctex_editor()) else: command.append('--synctex-pid={pid}'.format(pid=pid)) command.append(pdf_file) external_command(command, use_texpath=False) if pid is not None and not keep_focus: self._focus_zathura(pid)
def _run_command(self, command, pdf_file, tex_file=None, line='', col=''): if isinstance(command, strbase): if PY2: command = str(command) command = shlex.split(command) if PY2: command = [unicode(c) for c in command] substitution_made = False for i, component in enumerate(command): command[i], replaced = self._replace_vars(component, pdf_file, tex_file, line, col) substitution_made = substitution_made or replaced if not replaced: command.append(pdf_file) external_command( command, cwd=os.path.split(pdf_file)[0], # show the Window if not using a Windows shell, i.e., powershell or # cmd show_window=not bool(WINDOWS_SHELL.match(command[0])) if sublime.platform() == 'windows' else False)
def _run_command(self, command, pdf_file, tex_file=None, line='', col=''): if isinstance(command, strbase): if PY2: command = str(command) command = shlex.split(command) if PY2: command = [unicode(c) for c in command] substitution_made = False for i, component in enumerate(command): command[i], replaced = self._replace_vars( component, pdf_file, tex_file, line, col) substitution_made = substitution_made or replaced if not replaced: command.append(pdf_file) external_command( command, cwd=os.path.split(pdf_file)[0], # show the Window if not using a Windows shell, i.e., powershell or # cmd show_window=not bool(WINDOWS_SHELL.match(command[0])) if sublime.platform() == 'windows' else False )
def forward_sync(self, pdf_file, tex_file, line, col, **kwargs): keep_focus = kwargs.pop('keep_focus', True) # we check for the pid here as this is only necessary if # we aren't otherwise creating the window pid = self._get_zathura_pid(pdf_file) if pid is None: pid = self._run_zathura(pdf_file) if keep_focus: self.focus_st() command = [ 'zathura', '--synctex-forward', '{line}:{col}:{tex_file}'.format(**locals()), ] if pid is None: command.append(self._get_synctex_editor()) else: command.append('--synctex-pid={pid}'.format(pid=pid)) command.append(pdf_file) external_command(command, use_texpath=False) if pid is not None and not keep_focus: self._focus_zathura(pid)
def view_file(self, pdf_file, **kwargs): tex_filename = pdf_file.rsplit(".", 1)[0] + ".pdf" cmd = self._get_run_command(pdf_file, tex_filename=tex_filename, tex_line_no=1, tex_col_no=1) print("BASIC VIEWING CHROME") external_command(cmd, use_texpath=False)
def _run_okular(self, locator=None, **kwargs): keep_focus = kwargs.pop('keep_focus', True) command = ['okular', '--unique'] if keep_focus: command.append('--noraise') if locator is not None: command.append(locator) external_command(command, use_texpath=False)
def view_file(self, pdf_file, **kwargs): keep_focus = kwargs.pop('keep_focus', True) command = ['open'] if keep_focus: command.append('-g') command += ['-a', 'Preview', pdf_file] external_command(command, use_texpath=False)
def keep_focus(): external_command( [ 'osascript', '-e', 'tell application "{0}" to activate'.format( sublime_app ) ], use_texpath=False )
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) external_command(command)
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) external_command(command)
def view_file(self, pdf_file, **kwargs): keep_focus = kwargs.pop("keep_focus", True) command = [ "/bin/sh", os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "skim", "displayfile")), "-r", ] if keep_focus: command.append("-g") command.append(pdf_file) external_command(command, use_texpath=False)
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 _view_texdoc(file): if file is None: raise Exception('File must be specified') if not isinstance(file, strbase): raise TypeError('File must be a string') command = ['texdoc'] if sublime.platform() == 'windows' and using_miktex(): command.append('--view') command.append(file) try: external_command(command) except OSError: traceback.print_exc() sublime.error_message('Could not run texdoc. Please ensure that your texpath setting is configured correctly in the LaTeXTools settings.')
def view_file(self, pdf_file, **kwargs): keep_focus = kwargs.pop('keep_focus', True) command = [ '/bin/sh', os.path.normpath( os.path.join(os.path.dirname(__file__), '..', 'skim', 'displayfile')), '-r' ] if keep_focus: command.append('-g') command.append(pdf_file) external_command(command, use_texpath=False)
def _launch_evince(self, pdf_file): ev_path = self._get_evince_folder() py_binary, _ = self._get_settings() st_binary = get_sublime_exe() if st_binary is None: linux_settings = get_setting('linux', {}) st_binary = linux_settings.get('sublime', 'sublime_text') external_command( [ 'sh', os.path.join(ev_path, 'evince_sync'), py_binary, st_binary, pdf_file ], cwd=ev_path, use_texpath=False )
def forward_sync(self, pdf_file, tex_file, line, col, **kwargs): keep_focus = kwargs.pop("keep_focus", True) path_to_skim = "/Applications/Skim.app" if not os.path.exists(path_to_skim): path_to_skim = check_output( ["osascript", "-e", 'POSIX path of (path to app id "net.sourceforge.skim-app.skim")'], use_texpath=False ) command = [os.path.join(path_to_skim, "Contents", "SharedSupport", "displayline"), "-r"] if keep_focus: command.append("-g") command += [str(line), pdf_file, tex_file] external_command(command, use_texpath=False)
def _focus_wmctrl(self, pid): window_id = None try: windows = check_output(['wmctrl', '-l', '-p'], use_texpath=False) except: pass else: pid = ' {0} '.format(pid) for window in windows.splitlines(): if pid in window: window_id = window.split(' ', 1)[0] break if window_id is None: raise Exception('Cannot find window for Zathura') external_command(['wmctrl', '-a', window_id, '-i'], use_texpath=False)
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 Exception: 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 Exception: traceback.print_exc() _no_binary() return else: traceback.print_exception(*exc_info) _no_binary() return
def _run_command(self, command, pdf_file, tex_file=None, line="", col=""): if isinstance(command, strbase): if PY2: command = str(command) command = shlex.split(command) if PY2: command = [unicode(c) for c in command] substitution_made = False for i, component in enumerate(command): command[i], replaced = self._replace_vars(component, pdf_file, tex_file, line, col) substitution_made = substitution_made or replaced if not replaced: command.append(pdf_file) external_command(command, cwd=os.path.split(pdf_file)[0])
def _focus_wmctrl(self, pid): window_id = None try: windows = check_output( ['wmctrl', '-l', '-p'], use_texpath=False ) except: pass else: pid = ' {0} '.format(pid) for window in windows.splitlines(): if pid in window: window_id = window.split(' ', 1)[0] break if window_id is None: raise Exception('Cannot find window for Zathura') external_command(['wmctrl', '-a', window_id, '-i'], use_texpath=False)
def _run_command(self, command, pdf_file, tex_file=None, line='', col=''): if isinstance(command, strbase): if PY2: command = str(command) command = shlex.split(command) if PY2: command = [unicode(c) for c in command] substitution_made = False for i, component in enumerate(command): command[i], replaced = self._replace_vars(component, pdf_file, tex_file, line, col) substitution_made = substitution_made or replaced if not replaced: command.append(pdf_file) external_command(command, cwd=os.path.split(pdf_file)[0])
def forward_sync(self, pdf_file, tex_file, line, col, **kwargs): keep_focus = kwargs.pop('keep_focus', True) path_to_skim = '/Applications/Skim.app' if not os.path.exists(path_to_skim): path_to_skim = check_output([ 'osascript', '-e', 'POSIX path of (path to app id "net.sourceforge.skim-app.skim")' ], use_texpath=False) command = [ os.path.join(path_to_skim, 'Contents', 'SharedSupport', 'displayline'), '-r' ] if keep_focus: command.append('-g') command += [str(line), pdf_file, tex_file] external_command(command, use_texpath=False)
def forward_sync(self, pdf_file, tex_file, line, col, **kwargs): keep_focus = kwargs.pop('keep_focus', True) bring_evince_forward = get_setting('viewer_settings', {}).get( 'bring_evince_forward', False ) ev_path = self._get_evince_folder() py_binary, sync_wait = self._get_settings() evince_running = self._is_evince_running(pdf_file) if not keep_focus or not evince_running or bring_evince_forward: self._launch_evince(pdf_file) if keep_focus: self.focus_st() time.sleep(sync_wait) external_command( [ py_binary, os.path.join(ev_path, 'evince_forward_search'), pdf_file, str(line), tex_file ], use_texpath=False )
def run_bibtex(self, command=None): if command is None: command = [self.bibtex] elif isinstance(command, strbase): command = [command] # to get bibtex to work with the output directory, we change the # cwd to the output directory and add the main directory to # BIBINPUTS and BSTINPUTS env = dict(os.environ) cwd = self.tex_dir output_directory = ( self.aux_directory_full or self.output_directory_full ) if output_directory is not None: # cwd is, at the point, the path to the main tex file if _ST3: env['BIBINPUTS'] = cwd + os.pathsep + env.get('BIBINPUTS', '') env['BSTINPUTS'] = cwd + os.pathsep + env.get('BSTINPUTS', '') else: env['BIBINPUTS'] = \ (cwd + os.pathsep + env.get('BIBINPUTS', '')).encode( sys.getfilesystemencoding()) env['BSTINPUTS'] = \ (cwd + os.pathsep + env.get('BSTINPUTS', '')).encode( sys.getfilesystemencoding()) # now we modify cwd to be the output directory # NOTE this cwd is not reused by any of the other command cwd = output_directory env['PATH'] = get_texpath() command.append(self.job_name) return external_command( command, env=env, cwd=cwd, preexec_fn=os.setsid if sublime.platform() != 'windows' else None, use_texpath=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
def run_bibtex(self, command=None): if command is None: command = [self.bibtex] elif isinstance(command, strbase): command = [command] # to get bibtex to work with the output directory, we change the # cwd to the output directory and add the main directory to # BIBINPUTS and BSTINPUTS env = dict(os.environ) cwd = self.tex_dir output_directory = ( self.aux_directory_full or self.output_directory_full ) if output_directory is not None: # cwd is, at the point, the path to the main tex file if _ST3: env['BIBINPUTS'] = cwd + os.pathsep + env.get('BIBINPUTS', '') env['BSTINPUTS'] = cwd + os.pathsep + env.get('BSTINPUTS', '') else: env['BIBINPUTS'] = \ (cwd + os.pathsep + env.get('BIBINPUTS', '')).encode( sys.getfilesystemencoding()) env['BSTINPUTS'] = \ (cwd + os.pathsep + env.get('BSTINPUTS', '')).encode( sys.getfilesystemencoding()) # now we modify cwd to be the output directory # NOTE this cwd is not reused by any of the other command cwd = output_directory env['PATH'] = get_texpath() command.append(self.job_name) return external_command( command, env=env, cwd=cwd, preexec_fn=os.setsid if sublime.platform() != 'windows' else None, use_texpath=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
def _focus_xdotool(self, pid): external_command([ 'xdotool', 'search', '--pid', pid, '--class', 'Zathura', 'windowactivate', '%2' ], use_texpath=False)
def keep_focus(): external_command([ 'osascript', '-e', 'tell application "{0}" to activate'.format(sublime_app) ], use_texpath=False)
def keep_focus(): external_command([sublime_command], use_texpath=False)
def forward_sync(self, pdf_file, tex_file, line, col, **kwargs): cmd = self._get_run_command(pdf_file, tex_file, line, col) print("FORWARD SYNCING CHROME COMMAND IS:") print(cmd) external_command(cmd, use_texpath=True)
def _run_zathura(self, pdf_file): return external_command([ 'zathura', self._get_synctex_editor(), pdf_file ], use_texpath=False).pid
def run(self): print("Welcome to thread " + self.getName()) self.caller.output("[Compiling " + self.caller.file_name + "]") env = dict(os.environ) if self.caller.path: env['PATH'] = self.caller.path # Handle custom env variables if self.caller.env: update_env(env, self.caller.env) # Now, iteratively call the builder iterator # cmd_iterator = self.caller.builder.commands() try: for (cmd, msg) in cmd_iterator: # If there is a message, display it if msg: self.caller.output(msg) # If there is nothing to be done, exit loop # (Avoids error with empty cmd_iterator) if cmd == "": break if isinstance(cmd, strbase) or isinstance(cmd, list): # Now create a Popen object try: proc = external_command( cmd, env=env, use_texpath=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=os.setsid if self.caller.plat != 'windows' else None, cwd=self.caller.tex_dir) except: self.caller.show_output_panel() self.caller.output("\n\nCOULD NOT COMPILE!\n\n") self.caller.output("Attempted command:") self.caller.output(" ".join(cmd)) self.caller.output("\nBuild engine: " + self.caller.builder.name) self.caller.proc = None traceback.print_exc() return # Abundance of caution / for possible future extensions: elif isinstance(cmd, subprocess.Popen): proc = cmd else: # don't know what the command is continue # Now actually invoke the command, making sure we allow for killing # First, save process handle into caller; then communicate (which blocks) with self.caller.proc_lock: self.caller.proc = proc out, err = proc.communicate() self.caller.builder.set_output( out.decode(self.caller.encoding, "ignore")) # Here the process terminated, but it may have been killed. If so, stop and don't read log # Since we set self.caller.proc above, if it is None, the process must have been killed. # TODO: clean up? with self.caller.proc_lock: if not self.caller.proc: print(proc.returncode) self.caller.output( "\n\n[User terminated compilation process]\n") self.caller.finish( False) # We kill, so won't switch to PDF anyway return # Here we are done cleanly: with self.caller.proc_lock: self.caller.proc = None print("Finished normally") print(proc.returncode) # At this point, out contains the output from the current command; # we pass it to the cmd_iterator and get the next command, until completion except: self.caller.show_output_panel() self.caller.output("\n\nCOULD NOT COMPILE!\n\n") self.caller.output("\nBuild engine: " + self.caller.builder.name) self.caller.proc = None traceback.print_exc() return # Clean up cmd_iterator.close() try: # Here we try to find the log file... # 1. Check the aux_directory if there is one # 2. Check the output_directory if there is one # 3. Assume the log file is in the same folder as the main file log_file_base = self.caller.tex_base + ".log" if self.caller.aux_directory is None: if self.caller.output_directory is None: log_file = os.path.join(self.caller.tex_dir, log_file_base) else: log_file = os.path.join(self.caller.output_directory, log_file_base) if not os.path.exists(log_file): log_file = os.path.join(self.caller.tex_dir, log_file_base) else: log_file = os.path.join(self.caller.aux_directory, log_file_base) if not os.path.exists(log_file): if (self.caller.output_directory is not None and self.caller.output_directory != self.caller.aux_directory): log_file = os.path.join(self.caller.output_directory, log_file_base) if not os.path.exists(log_file): log_file = os.path.join(self.caller.tex_dir, log_file_base) # CHANGED 12-10-27. OK, here's the deal. We must open in binary mode # on Windows because silly MiKTeX inserts ASCII control characters in # over/underfull warnings. In particular it inserts EOFs, which # stop reading altogether; reading in binary prevents that. However, # that's not the whole story: if a FS character is encountered, # AND if we invoke splitlines on a STRING, it sadly breaks the line # in two. This messes up line numbers in error reports. If, on the # other hand, we invoke splitlines on a byte array (? whatever read() # returns), this does not happen---we only break at \n, etc. # However, we must still decode the resulting lines using the relevant # encoding. # Note to self: need to think whether we don't want to codecs.open # this, too... Also, we may want to move part of this logic to the # builder... with open(log_file, 'rb') as f: data = f.read() except IOError: traceback.print_exc() self.caller.show_output_panel() content = [ '', 'Could not read log file {0}.log'.format(self.caller.tex_base), '' ] if out is not None: content.extend( ['Output from compilation:', '', out.decode('utf-8')]) if err is not None: content.extend( ['Errors from compilation:', '', err.decode('utf-8')]) self.caller.output(content) # if we got here, there shouldn't be a PDF at all self.caller.finish(False) else: errors = [] warnings = [] badboxes = [] try: (errors, warnings, badboxes) = parseTeXlog.parse_tex_log(data, self.caller.tex_dir) content = [""] if errors: content.append("Errors:") content.append("") content.extend(errors) else: content.append("No errors.") if warnings: if errors: content.extend(["", "Warnings:"]) else: content[-1] = content[-1] + " Warnings:" content.append("") content.extend(warnings) else: if errors: content.append("") content.append("No warnings.") else: content[-1] = content[-1] + " No warnings." if badboxes and self.caller.display_bad_boxes: if warnings or errors: content.extend(["", "Bad Boxes:"]) else: content[-1] = content[-1] + " Bad Boxes:" content.append("") content.extend(badboxes) else: if self.caller.display_bad_boxes: if errors or warnings: content.append("") content.append("No bad boxes.") else: content[-1] = content[-1] + " No bad boxes." content.append("") content.append(log_file + ":1: Double-click here to open the full log.") show_panel = { "always": False, "no_errors": bool(errors), "no_warnings": bool(errors or warnings), "no_badboxes": bool(errors or warnings or (self.caller.display_bad_boxes and badboxes)), "never": True }.get(self.caller.hide_panel_level, bool(errors or warnings)) if show_panel: self.caller.progress_indicator.success_message = "Build completed" self.caller.show_output_panel(force=True) else: message = "Build completed" if errors: message += " with errors" if warnings: if errors: if badboxes and self.caller.display_bad_boxes: message += "," else: message += " and" else: message += " with" message += " warnings" if badboxes and self.caller.display_bad_boxes: if errors or warnings: message += " and" else: message += " with" message += " bad boxes" self.caller.progress_indicator.success_message = message except Exception as e: self.caller.show_output_panel() content = ["", ""] content.append( "LaTeXTools could not parse the TeX log file {0}".format( log_file)) content.append("(actually, we never should have gotten here)") content.append("") content.append("Python exception: {0!r}".format(e)) content.append("") content.append( "The full error description can be found on the console.") content.append("Please let us know on GitHub. Thanks!") traceback.print_exc() self.caller.output(content) self.caller.output("\n\n[Done!]\n") if _HAS_PHANTOMS: self.caller.errors = locals().get("errors", []) self.caller.warnings = locals().get("warnings", []) self.caller.badboxes = locals().get("badboxes", []) self.caller.finish(len(errors) == 0)
def run ( self ): print ("Welcome to thread " + self.getName()) self.caller.output("[Compiling " + self.caller.file_name + "]") env = dict(os.environ) if self.caller.path: env['PATH'] = self.caller.path # Handle custom env variables if self.caller.env: update_env(env, self.caller.env) # Now, iteratively call the builder iterator # cmd_iterator = self.caller.builder.commands() try: for (cmd, msg) in cmd_iterator: # If there is a message, display it if msg: self.caller.output(msg) # If there is nothing to be done, exit loop # (Avoids error with empty cmd_iterator) if cmd == "": break if isinstance(cmd, strbase) or isinstance(cmd, list): print(cmd) # Now create a Popen object try: proc = external_command( cmd, env=env, use_texpath=False, preexec_fn=os.setsid if self.caller.plat != 'windows' else None, cwd=self.caller.tex_dir ) except: self.caller.show_output_panel() self.caller.output("\n\nCOULD NOT COMPILE!\n\n") self.caller.output("Attempted command:") self.caller.output(" ".join(cmd)) self.caller.output("\nBuild engine: " + self.caller.builder.name) self.caller.proc = None traceback.print_exc() return # Abundance of caution / for possible future extensions: elif isinstance(cmd, subprocess.Popen): proc = cmd else: # don't know what the command is continue # Now actually invoke the command, making sure we allow for killing # First, save process handle into caller; then communicate (which blocks) with self.caller.proc_lock: self.caller.proc = proc out, err = proc.communicate() self.caller.builder.set_output(out.decode(self.caller.encoding,"ignore")) # Here the process terminated, but it may have been killed. If so, stop and don't read log # Since we set self.caller.proc above, if it is None, the process must have been killed. # TODO: clean up? with self.caller.proc_lock: if not self.caller.proc: print (proc.returncode) self.caller.output("\n\n[User terminated compilation process]\n") self.caller.finish(False) # We kill, so won't switch to PDF anyway return # Here we are done cleanly: with self.caller.proc_lock: self.caller.proc = None print ("Finished normally") print (proc.returncode) # At this point, out contains the output from the current command; # we pass it to the cmd_iterator and get the next command, until completion except: self.caller.show_output_panel() self.caller.output("\n\nCOULD NOT COMPILE!\n\n") self.caller.output("\nBuild engine: " + self.caller.builder.name) self.caller.proc = None traceback.print_exc() return # Clean up cmd_iterator.close() try: # Here we try to find the log file... # 1. Check the aux_directory if there is one # 2. Check the output_directory if there is one # 3. Assume the log file is in the same folder as the main file log_file_base = self.caller.tex_base + ".log" if self.caller.aux_directory is None: if self.caller.output_directory is None: log_file = os.path.join( self.caller.tex_dir, log_file_base ) else: log_file = os.path.join( self.caller.output_directory, log_file_base ) if not os.path.exists(log_file): log_file = os.path.join( self.caller.tex_dir, log_file_base ) else: log_file = os.path.join( self.caller.aux_directory, log_file_base ) if not os.path.exists(log_file): if ( self.caller.output_directory is not None and self.caller.output_directory != self.caller.aux_directory ): log_file = os.path.join( self.caller.output_directory, log_file_base ) if not os.path.exists(log_file): log_file = os.path.join( self.caller.tex_dir, log_file_base ) # CHANGED 12-10-27. OK, here's the deal. We must open in binary mode # on Windows because silly MiKTeX inserts ASCII control characters in # over/underfull warnings. In particular it inserts EOFs, which # stop reading altogether; reading in binary prevents that. However, # that's not the whole story: if a FS character is encountered, # AND if we invoke splitlines on a STRING, it sadly breaks the line # in two. This messes up line numbers in error reports. If, on the # other hand, we invoke splitlines on a byte array (? whatever read() # returns), this does not happen---we only break at \n, etc. # However, we must still decode the resulting lines using the relevant # encoding. # Note to self: need to think whether we don't want to codecs.open # this, too... Also, we may want to move part of this logic to the # builder... with open(log_file, 'rb') as f: data = f.read() except IOError: traceback.print_exc() self.caller.show_output_panel() content = ['', 'Could not read log file {0}.log'.format( self.caller.tex_base ), ''] if out is not None: content.extend(['Output from compilation:', '', out.decode('utf-8')]) if err is not None: content.extend(['Errors from compilation:', '', err.decode('utf-8')]) self.caller.output(content) # if we got here, there shouldn't be a PDF at all self.caller.finish(False) else: errors = [] warnings = [] badboxes = [] try: (errors, warnings, badboxes) = parseTeXlog.parse_tex_log( data, self.caller.tex_dir ) content = [""] if errors: content.append("Errors:") content.append("") content.extend(errors) else: content.append("No errors.") if warnings: if errors: content.extend(["", "Warnings:"]) else: content[-1] = content[-1] + " Warnings:" content.append("") content.extend(warnings) else: if errors: content.append("") content.append("No warnings.") else: content[-1] = content[-1] + " No warnings." if badboxes and self.caller.display_bad_boxes: if warnings or errors: content.extend(["", "Bad Boxes:"]) else: content[-1] = content[-1] + " Bad Boxes:" content.append("") content.extend(badboxes) else: if self.caller.display_bad_boxes: if errors or warnings: content.append("") content.append("No bad boxes.") else: content[-1] = content[-1] + " No bad boxes." show_panel = { "always": False, "no_errors": bool(errors), "no_warnings": bool(errors or warnings), "no_badboxes": bool( errors or warnings or (self.caller.display_bad_boxes and badboxes)), "never": True }.get(self.caller.hide_panel_level, bool(errors or warnings)) if show_panel: self.caller.progress_indicator.success_message = "Build completed" self.caller.show_output_panel(force=True) else: message = "Build completed" if errors: message += " with errors" if warnings: if errors: if badboxes and self.caller.display_bad_boxes: message += "," else: message += " and" else: message += " with" message += " warnings" if badboxes and self.caller.display_bad_boxes: if errors or warnings: message += " and" else: message += " with" message += " bad boxes" self.caller.progress_indicator.success_message = message except Exception as e: self.caller.show_output_panel() content = ["", ""] content.append( "LaTeXTools could not parse the TeX log file {0}".format( log_file ) ) content.append("(actually, we never should have gotten here)") content.append("") content.append("Python exception: {0!r}".format(e)) content.append("") content.append( "The full error description can be found on the console." ) content.append("Please let us know on GitHub. Thanks!") traceback.print_exc() self.caller.output(content) self.caller.output("\n\n[Done!]\n") if _HAS_PHANTOMS: self.caller.errors = locals().get("errors", []) self.caller.warnings = locals().get("warnings", []) self.caller.badboxes = locals().get("badboxes", []) self.caller.finish(len(errors) == 0)
def _run_zathura(self, pdf_file): return external_command( ['zathura', self._get_synctex_editor(), pdf_file], use_texpath=False).pid
def commands(self): # Print greeting self.display("\n\nScriptBuilder: ") # create an environment to be used for all subprocesses # adds any settings from the `env` dict to the current # environment env = dict(os.environ) env['PATH'] = self.texpath if self.env is not None and isinstance(self.env, dict): update_env(env, self.env) if self.cmd is None: sublime.error_message( "You MUST set a command in your LaTeXTools.sublime-settings " + "file before launching the script builder." ) # I'm not sure this is the best way to handle things... raise StopIteration() if isinstance(self.cmd, strbase): self.cmd = [self.cmd] for cmd in self.cmd: replaced_var = False if isinstance(cmd, strbase): cmd, replaced_var = self.substitute(cmd) else: for i, component in enumerate(cmd): cmd[i], replaced = self.substitute(component) replaced_var = replaced_var or replaced if not replaced_var: if isinstance(cmd, strbase): cmd += ' ' + self.base_name else: cmd.append(self.base_name) if not isinstance(cmd, strbase): self.display("Invoking '{0}'... ".format( u' '.join([quote(s) for s in cmd]) )) else: self.display("Invoking '{0}'... ".format(cmd)) yield ( # run with use_texpath=False as we have already configured # the environment above, including the texpath external_command( cmd, env=env, cwd=self.tex_dir, use_texpath=False, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ), "" ) self.display("done.\n") # This is for debugging purposes if self.display_log and self.out is not None: self.display("\nCommand results:\n") self.display(self.out) self.display("\n\n")
def _focus_xdotool(self, pid): external_command( ['xdotool', 'search', '--pid', pid, '--class', 'Zathura', 'windowactivate', '%2'], use_texpath=False )
def keep_focus(): external_command([sublime_command], use_texpath=False)
def commands(self): # Print greeting self.display("\n\nWineBuilder: ") # create an environment to be used for all subprocesses # adds any settings from the `env` dict to the current # environment env = dict(os.environ) env['PATH'] = self.texpath if self.env is not None and isinstance(self.env, dict): update_env(env, self.env) latex = ["latex", "-src", "-interaction=nonstopmode", "-synctex=1"] bibtex = ["bibtex"] dvi2ps = ["dvips"] # Get the platform plat = sublime.platform() # ps2pdf command, with reasonable executable (NOTE: we assume you installed 64-bit Ghostscrit) gs = "gswin64c" if plat == "windows" else "gs-952-linux-x86_64" ps2pdf = [ gs, "-dNOPAUSE", "-dBATCH", "-sDEVICE=pdfwrite", "-dPDFSETTINGS=/prepress", "-dCompatibilityLevel=1.4", "-dSubsetFonts=true", "-dEmbedAllFonts=true", '-sOutputFile="' + self.base_name + '.pdf"', "-c", "save", "pop", "-f", ] # Regex to look for missing citations # This works for plain latex; apparently natbib requires special handling # TODO: does it work with biblatex? citations_rx = re.compile( r"Warning: Citation `.+' on page \d+ undefined") # We have commands in our PATH, and are in the same dir as the master file # This is for debugging purposes def display_results(n): if self.display_log: self.display("Command results, run %d:\n" % (n, )) self.display(self.out) self.display("\n") run = 1 brun = 0 yield (latex + [self.base_name], "latex run %d; " % (run, )) display_results(run) # Check for citations # Use search, not match: match looks at the beginning of the string # We need to run latex twice after bibtex if citations_rx.search(self.out): brun = brun + 1 yield (bibtex + [self.base_name], "bibtex run %d; " % (brun, )) display_results(1) run = run + 1 yield (latex + [self.base_name], "latex run %d; " % (run, )) display_results(run) run = run + 1 yield (latex + [self.base_name], "latex run %d; " % (run, )) display_results(run) # Apparently natbib needs separate processing if "Package natbib Warning: There were undefined citations." in self.out: brun = brun + 1 yield (bibtex + [self.base_name], "bibtex run %d; " % (brun, )) display_results(2) run = run + 1 yield (latex + [self.base_name], "latex run %d; " % (run, )) display_results(run) run = run + 1 yield (latex + [self.base_name], "latex run %d; " % (run, )) display_results(run) # Check for changed labels # Do this at the end, so if there are also citations to resolve, # we may save one pdflatex run if "Rerun to get cross-references right." in self.out: run = run + 1 yield (latex + [self.base_name], "latex run %d; " % (run, )) display_results(run) yield (dvi2ps + [self.base_name], "dvips run %d; " % (run, )) display_results(run) # NOTE: here, ps2pdf is considered as an external command, because we use customized # executable instead of the built-in on cmd = external_command(ps2pdf + [self.base_name + ".ps"], env=env, cwd=self.tex_dir, use_texpath=False, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) yield (cmd, "ps2pdf run %d; " % (run, )) display_results(run) self.display("done.\n")