Hi list,

I've implemented TeX-update, as suggested in the wishlist.  My work
follows the same logic of http://www.emacswiki.org/emacs/TN#toc8 and
is in part based on it: a function runs the compilation command and
calls a sentinel which, when the command finishes, calls back the
function and so on until a stopping condition is reached.

Some comments about possible copyrights concerns:

- `TeX-command-default' is extracted from `TeX-command-query', there
is nothing new in it;

- the sentinel function `TeX-command-sequence-sentinel' is similar to
`TeX-texify-sentinel' of EmacsWiki, but I don't know how a basic
sentinel could be written otherwise.  Moreover, how to test whether
there have been errors in the last compilation is reported literally
in the docstring of `TeX-error-report-switches';

- `TeX-command-sequence' has only the last three lines in common with
`TeX-texify' of EmacsWiki, which are the setting of a sentinel, how
could it be done otherwise?  For the rest these functions are
different: `TeX-command-sequence' is much more flexible (see the
docstring and the possible values of the first argument) and stopping
after a command has been run N times in a row does work, in
`TeX-texify' it doesn't.

In addition, in the second patch I've added "dvips" and "ps2pdf" rules
to `TeX-command-list', and there is a new option
`TeX-PDF-via-dvips-ps2pdf' so that one can produce a PDF using latex +
dvips + ps2pdf.  Using `TeX-update' all this boils down to a single
C-c C-u  :-)

I've been using `TeX-update' and dvips + ps2pdf for a week, without
problems.  Comments and suggestions welcome.

Bye,
Mosè
From 4ea34d2d4510c84d722ed8c0c4b82345e1cb88f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <m...@gnu.org>
Date: Mon, 17 Aug 2015 00:28:03 +0200
Subject: [PATCH 1/2] Implement TeX-update.

---
 tex-buf.el | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 tex.el     |  12 ++---
 2 files changed, 154 insertions(+), 29 deletions(-)

diff --git a/tex-buf.el b/tex-buf.el
index b5ed365..668a5b5 100644
--- a/tex-buf.el
+++ b/tex-buf.el
@@ -1,6 +1,6 @@
 ;;; tex-buf.el --- External commands for AUCTeX.
 
-;; Copyright (C) 1991-1999, 2001-2014 Free Software Foundation, Inc.
+;; Copyright (C) 1991-1999, 2001-2015 Free Software Foundation, Inc.
 
 ;; Maintainer: auctex-devel@gnu.org
 ;; Keywords: tex, wp
@@ -460,6 +460,114 @@ ORIGINALS which are modified but not saved yet."
           (setq found t)))
     found))
 
+(defcustom TeX-command-sequence-max-runs-same-command 4
+  "Maximum number of runs of the same command."
+  :type 'integer
+  :group 'TeX-command)
+
+(defcustom TeX-command-sequence-max-runs 12
+  "Maximum number of total runs."
+  :type 'integer
+  :group 'TeX-command)
+
+(defvar TeX-command-sequence-count-same-command 1
+  "Counter for the runs of the same command in `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-count 1
+  "Counter for the total runs of `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-last-command nil
+  "Last command run in `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-sentinel nil
+  "Sentinel for `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-command nil
+  "Command argument for `TeX-command-sequence'.
+
+It is set in `TeX-command-sequence' and used in
+`TeX-command-sequence-sentinel' to call again
+`TeX-command-sequence' with the appropriate command argument.")
+
+(defun TeX-command-sequence (command &optional reset)
+  "Run a sequence of TeX commands defined by COMMAND.
+
+The COMMAND argument may be
+
+  * nil: no command will be run in this case
+
+  * a string with a command from `TeX-command-list'
+
+  * a non-nil list of strings, which are commands from
+    `TeX-command-list'; the car of the list is used as command to
+    be executed in the first run of `TeX-command-sequence', the
+    cdr of the list will be passed to the function in the next
+    run, etc.
+
+  * a function name, returning a string which is command from
+    `TeX-command-list'; it will be funcall'd (without arguments!)
+    and used again in the next run of `TeX-command-sequence'.
+
+  * with any other value the function `TeX-command-default' is
+    used to determine the command to run, until a stopping
+    condition is met.
+
+This function runs at most
+`TeX-command-sequence-max-runs-same-command' times the same
+command in a row, and `TeX-command-sequence-max-runs' times in
+total in any case.  It ends when `TeX-command-Show' is the
+command to be run.
+
+A non-nil value for the optional argument RESET means this is the
+first run of the function and some variables need to be reset."
+  (if (null command)
+      (message "No command to run.")
+    (let (cmd process)
+      (cond
+       ((stringp command)
+	(setq cmd command
+	      TeX-command-sequence-command nil))
+       ((listp command)
+	(setq cmd (pop command)
+	      TeX-command-sequence-command command))
+       ((functionp command)
+	(setq cmd (funcall command)
+	      TeX-command-sequence-command command))
+       (t
+	(setq cmd (TeX-command-default (TeX-master-file))
+	      TeX-command-sequence-command t)))
+      (TeX-command cmd 'TeX-master-file 0)
+      (when reset
+	(setq TeX-command-sequence-count-same-command 1
+	      TeX-command-sequence-count 1
+	      TeX-command-sequence-last-command nil))
+      (cond
+       ;; Stop when the same command has been run
+       ;; `TeX-command-sequence-max-runs-same-command' times in a row.
+       ((>= TeX-command-sequence-count-same-command
+	    TeX-command-sequence-max-runs-same-command)
+	(message "Stopping after running %S %d times in a row."
+		 TeX-command-sequence-last-command
+		 TeX-command-sequence-count-same-command))
+       ;; Stop when there have been `TeX-command-sequence-max-runs' total
+       ;; compilations.
+       ((>= TeX-command-sequence-count TeX-command-sequence-max-runs)
+	(message "Stopping after %d compilations." TeX-command-sequence-count))
+       ;; The command just run is `TeX-command-Show'.
+       ((equal command TeX-command-Show))
+       ;; In any other case continue: increase counters (when needed), update
+       ;; `TeX-command-sequence-last-command' and run the sentinel.
+       (t
+	(if (equal cmd TeX-command-sequence-last-command)
+	    (setq TeX-command-sequence-count-same-command
+		  (1+ TeX-command-sequence-count-same-command))
+	  (setq TeX-command-sequence-count-same-command 1))
+	(setq TeX-command-sequence-count (1+ TeX-command-sequence-count)
+	      TeX-command-sequence-last-command cmd)
+	(and (setq process (get-buffer-process (current-buffer)))
+	     (setq TeX-command-sequence-sentinel (process-sentinel process))
+	     (set-process-sentinel process 'TeX-command-sequence-sentinel)))))))
+
 (defcustom TeX-save-query t
   "*If non-nil, ask user for permission to save files before starting TeX."
   :group 'TeX-command
@@ -467,29 +575,32 @@ ORIGINALS which are modified but not saved yet."
 
 (defvar TeX-command-history nil)
 
+(defun TeX-command-default (name)
+  "Guess the next command to be run on NAME."
+  (cond ((if (string-equal name TeX-region)
+	     (TeX-check-files (concat name "." (TeX-output-extension))
+			      (list name)
+			      TeX-file-extensions)
+	   (TeX-save-document (TeX-master-file)))
+	 TeX-command-default)
+	((and (memq major-mode '(doctex-mode latex-mode))
+	      ;; Want to know if bib file is newer than .bbl
+	      ;; We don't care whether the bib files are open in emacs
+	      (TeX-check-files (concat name ".bbl")
+			       (mapcar 'car
+				       (LaTeX-bibliography-list))
+			       (append BibTeX-file-extensions
+				       TeX-Biber-file-extensions)))
+	 ;; We should check for bst files here as well.
+	 (if LaTeX-using-Biber TeX-command-Biber TeX-command-BibTeX))
+	((TeX-process-get-variable name
+				   'TeX-command-next
+				   TeX-command-Show))
+	(TeX-command-Show)))
+
 (defun TeX-command-query (name)
   "Query the user for what TeX command to use."
-  (let* ((default
-	   (cond ((if (string-equal name TeX-region)
-		      (TeX-check-files (concat name "." (TeX-output-extension))
-				       (list name)
-				       TeX-file-extensions)
-		    (TeX-save-document (TeX-master-file)))
-		  TeX-command-default)
-		 ((and (memq major-mode '(doctex-mode latex-mode))
-		       ;; Want to know if bib file is newer than .bbl
-		       ;; We don't care whether the bib files are open in emacs
-		       (TeX-check-files (concat name ".bbl")
-					(mapcar 'car
-						(LaTeX-bibliography-list))
-					(append BibTeX-file-extensions
-						TeX-Biber-file-extensions)))
-		  ;; We should check for bst files here as well.
-		  (if LaTeX-using-Biber TeX-command-Biber TeX-command-BibTeX))
-		 ((TeX-process-get-variable name
-					    'TeX-command-next
-					    TeX-command-Show))
-		 (TeX-command-Show)))
+  (let* ((default (TeX-command-default name))
          (completion-ignore-case t)
          (answer (or TeX-command-force
                      (completing-read
@@ -1173,6 +1284,22 @@ Rerun to get mark in right position\\." nil t)
                      "Run LaTeX again to get citations right."))
     (setq TeX-command-next TeX-command-default))))
 
+(defun TeX-command-sequence-sentinel (process string)
+  "Call the appropriate sentinel for the current process.
+
+If there are no errors, call back `TeX-command-sequence' using
+`TeX-command-sequence-command' as command argument, unless this
+variable is nil."
+  (with-current-buffer (process-buffer process)
+    (funcall TeX-command-sequence-sentinel process string)
+    (if (string-match "\\(finished\\|exited\\)" string)
+	(with-current-buffer TeX-command-buffer
+	  (unless
+	      (or
+	       (plist-get TeX-error-report-switches (intern (TeX-master-file)))
+	       (null TeX-command-sequence-command))
+	    (TeX-command-sequence TeX-command-sequence-command))))))
+
 ;;; Process Control
 
 
diff --git a/tex.el b/tex.el
index 07fa371..ee2dccf 100644
--- a/tex.el
+++ b/tex.el
@@ -1276,13 +1276,6 @@ restarting Emacs."
 	     (repeat :tag "List of executables" (string :tag "Name"))
 	     (const :tag "No executable" nil)))))
 
-;; XXX: Regarding a possibility to (manually) run an update command,
-;; one could support this through `TeX-view' by letting it temporarily
-;; set a variable which is checked with a predicate in the viewer
-;; selection.  If the check is positive, the update command is run
-;; instead of the normal viewer command.  Direct support through the
-;; View command would require a predicate which knows when an update
-;; has to be done.
 (defcustom TeX-view-program-selection
   (cond
    ((eq system-type 'windows-nt)
@@ -2050,6 +2043,10 @@ output files."
 	    (delete-file (concat master-dir file))))
       (message "No files to be deleted"))))
 
+(defun TeX-update ()
+  "Compile the current document until an error occurs or it is finished."
+  (interactive)
+  (TeX-command-sequence t t))
 
 ;;; Master File
 
@@ -4657,6 +4654,7 @@ Brace insertion is only done if point is in a math construct and
     (define-key map "\C-c\C-r" 'TeX-command-region)
     (define-key map "\C-c\C-b" 'TeX-command-buffer)
     (define-key map "\C-c\C-c" 'TeX-command-master)
+    (define-key map "\C-c\C-u" 'TeX-update)
     (define-key map "\C-c\C-k" 'TeX-kill-job)
     (define-key map "\C-c\C-l" 'TeX-recenter-output-buffer)
     (define-key map "\C-c^" 'TeX-home-buffer)
-- 
2.5.0

From 927de03cd3ccba6cefd19f89e233666a8e98b3e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <m...@gnu.org>
Date: Mon, 17 Aug 2015 00:33:01 +0200
Subject: [PATCH 2/2] Generate PDF via dvips + ps2pdf.

---
 tex-buf.el | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 tex.el     | 27 +++++++++++++++++--
 2 files changed, 101 insertions(+), 14 deletions(-)

diff --git a/tex-buf.el b/tex-buf.el
index 668a5b5..8164831 100644
--- a/tex-buf.el
+++ b/tex-buf.el
@@ -322,7 +322,7 @@ This works only with TeX commands and if the
 	  (TeX-parse-TeX (- arg) nil)
 	;; XXX: moving backward in the errors hasn't yet been implemented for
 	;; other parsing functions.
-	(error "Jumping to previous error not supported.")))))
+	(error "Jumping to previous error not supported")))))
 
 ;;; Command Query
 
@@ -427,8 +427,8 @@ without further expansion."
 (defun TeX-check-files (derived originals extensions)
   "Check if DERIVED is newer than any of the ORIGINALS.
 Try each original with each member of EXTENSIONS, in all directories
-in `TeX-check-path'. Returns true if any of the ORIGINALS with any of the
-EXTENSIONS are newer than DERIVED. Will prompt to save the buffer of any
+in `TeX-check-path'.  Returns true if any of the ORIGINALS with any of the
+EXTENSIONS are newer than DERIVED.  Will prompt to save the buffer of any
 ORIGINALS which are modified but not saved yet."
   (let (existingoriginals
         found
@@ -595,7 +595,9 @@ first run of the function and some variables need to be reset."
 	 (if LaTeX-using-Biber TeX-command-Biber TeX-command-BibTeX))
 	((TeX-process-get-variable name
 				   'TeX-command-next
-				   TeX-command-Show))
+				   (if (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode)
+				       "Dvips"
+				     TeX-command-Show)))
 	(TeX-command-Show)))
 
 (defun TeX-command-query (name)
@@ -778,7 +780,8 @@ Return the new process."
 (defun TeX-run-set-command (name command)
   "Remember TeX command to use to NAME and set corresponding output extension."
   (setq TeX-command-default name
-	TeX-output-extension (if TeX-PDF-mode "pdf" "dvi"))
+	TeX-output-extension
+	(if (and (null TeX-PDF-via-dvips-ps2pdf) TeX-PDF-mode) "pdf" "dvi"))
   (let ((case-fold-search t)
 	(lst TeX-command-output-list))
     (while lst
@@ -862,6 +865,22 @@ run of `TeX-run-TeX', use
         process
       (TeX-synchronous-sentinel name file process))))
 
+(defun TeX-run-Dvips (name command file)
+  "Create a process for NAME using COMMAND to convert FILE with Dvips."
+  (let ((process (TeX-run-command name command file)))
+    (setq TeX-sentinel-function 'TeX-Dvips-sentinel)
+    (if TeX-process-asynchronous
+        process
+      (TeX-synchronous-sentinel name file process))))
+
+(defun TeX-run-ps2pdf (name command file)
+  "Create a process for NAME using COMMAND to convert FILE with ps2pdf."
+  (let ((process (TeX-run-command name command file)))
+    (setq TeX-sentinel-function 'TeX-ps2pdf-sentinel)
+    (if TeX-process-asynchronous
+        process
+      (TeX-synchronous-sentinel name file process))))
+
 (defun TeX-run-compile (name command file)
   "Ignore first and third argument, start compile with second argument."
   (let ((default-directory (TeX-master-directory)))
@@ -1075,7 +1094,10 @@ errors or warnings to show."
 	(TeX-parse-all-errors))
     (if (and TeX-error-overview-open-after-TeX-run TeX-error-list)
 	(TeX-error-overview))
-    (setq TeX-command-next TeX-command-Show)))
+    (if (with-current-buffer TeX-command-buffer
+	  (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode))
+	(setq TeX-command-next "Dvips")
+      (setq TeX-command-next TeX-command-Show))))
 
 (defun TeX-current-pages ()
   "Return string indicating the number of pages formatted."
@@ -1116,7 +1138,10 @@ Return nil ifs no errors were found."
 					    'TeX-current-master))
 			 t))
 	t)
-    (setq TeX-command-next TeX-command-Show)
+    (if (with-current-buffer TeX-command-buffer
+	  (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode))
+	(setq TeX-command-next "Dvips")
+      (setq TeX-command-next TeX-command-Show))
     nil))
 
 (defun TeX-LaTeX-sentinel-has-warnings ()
@@ -1198,12 +1223,18 @@ Rerun to get outlines right" nil t)
 	((re-search-forward "^LaTeX Warning: Reference" nil t)
 	 (message "%s%s%s" name ": there were unresolved references, "
 		  (TeX-current-pages))
-	 (setq TeX-command-next TeX-command-Show))
+	 (if (with-current-buffer TeX-command-buffer
+	       (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode))
+	     (setq TeX-command-next "Dvips")
+	   (setq TeX-command-next TeX-command-Show)))
 	((re-search-forward "^\\(?:LaTeX Warning: Citation\\|\
 Package natbib Warning:.*undefined citations\\)" nil t)
 	 (message "%s%s%s" name ": there were unresolved citations, "
 		  (TeX-current-pages))
-	 (setq TeX-command-next TeX-command-Show))
+	 (if (with-current-buffer TeX-command-buffer
+	       (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode))
+	     (setq TeX-command-next "Dvips")
+	   (setq TeX-command-next TeX-command-Show)))
 	((re-search-forward "Package longtable Warning: Table widths have \
 changed\\. Rerun LaTeX\\." nil t)
 	 (message
@@ -1229,7 +1260,10 @@ Rerun to get mark in right position\\." nil t)
 				    ")"))))
 	   (message "%s" (concat name ": successfully formatted "
 				 (TeX-current-pages) add-info)))
-	 (setq TeX-command-next TeX-command-Show))
+	 (if (with-current-buffer TeX-command-buffer
+	       (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode))
+	     (setq TeX-command-next "Dvips")
+	   (setq TeX-command-next TeX-command-Show)))
 	(t
 	 (message "%s%s%s" name ": problems after " (TeX-current-pages))
 	 (setq TeX-command-next TeX-command-default)))
@@ -1284,6 +1318,36 @@ Rerun to get mark in right position\\." nil t)
                      "Run LaTeX again to get citations right."))
     (setq TeX-command-next TeX-command-default))))
 
+(defun TeX-Dvips-sentinel (_process _name)
+  "Cleanup TeX output buffer after running Dvips."
+  (goto-char (point-max))
+  (cond
+   ((search-backward "TeX Output exited abnormally" nil t)
+    (message "Dvips failed.  Type `%s' to display output."
+	     (substitute-command-keys
+              "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+   (t
+    (if (with-current-buffer TeX-command-buffer
+	  (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode))
+	(setq TeX-output-extension "ps"
+	      TeX-command-next "Ps2pdf"))
+    (message "Dvips finished successfully. "))))
+
+(defun TeX-ps2pdf-sentinel (_process _name)
+  "Cleanup TeX output buffer after running ps2pdf."
+  (goto-char (point-max))
+  (cond
+   ((search-backward "TeX Output exited abnormally" nil t)
+    (message "ps2pdf failed.  Type `%s' to display output."
+	     (substitute-command-keys
+              "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+   (t
+    (if (with-current-buffer TeX-command-buffer
+	  (and TeX-PDF-via-dvips-ps2pdf TeX-PDF-mode))
+	(setq TeX-command-next TeX-command-Show
+	      TeX-output-extension "pdf"))
+    (message "ps2pdf finished successfully. "))))
+
 (defun TeX-command-sequence-sentinel (process string)
   "Call the appropriate sentinel for the current process.
 
@@ -1770,7 +1834,7 @@ If optional argument REPARSE is non-nil, reparse the output log."
 ;; be ignored, because `TeX-next-error' can call any of these functions.
 (defun TeX-parse-command (arg reparse)
   "We can't parse anything but TeX."
-  (error "I cannot parse %s output, sorry."
+  (error "I cannot parse %s output, sorry"
 	 (if (TeX-active-process)
 	     (process-name (TeX-active-process))
 	   "this")))
@@ -3004,7 +3068,7 @@ forward, if negative)."
           (TeX-command name (if (string-match "_region_" file)
                                 'TeX-region-file
                               'TeX-master-file))))
-    (error "Unable to find what command to run.")))
+    (error "Unable to find what command to run")))
 
 (provide 'tex-buf)
 
diff --git a/tex.el b/tex.el
index ee2dccf..b4a1812 100644
--- a/tex.el
+++ b/tex.el
@@ -152,6 +152,10 @@ If nil, none is specified."
      :visible TeX-queue-command)
     ("File" "%(o?)dvips %d -o %f " TeX-run-command t t
      :help "Generate PostScript file")
+    ("Dvips" "%(o?)dvips %d -o %f " TeX-run-Dvips nil t
+     :help "Convert DVI file to PostScript")
+    ("Ps2pdf" "ps2pdf %f" TeX-run-ps2pdf nil t
+     :help "Convert PostScript file to PDF")
     ("Index" "makeindex %s" TeX-run-command nil t :help "Create index file")
     ("Xindy" "texindy %s" TeX-run-command nil t
      :help "Run xindy to create index file")
@@ -445,8 +449,9 @@ string."
 	    (TeX-style-check LaTeX-command-style)))
     ("%(PDF)" (lambda ()
 		(if (and (eq TeX-engine 'default)
-			 (or TeX-PDF-mode
-			     TeX-DVI-via-PDFTeX))
+			 (if TeX-PDF-mode
+			     (not TeX-PDF-via-dvips-ps2pdf)
+			   TeX-DVI-via-PDFTeX))
 		    "pdf"
 		  "")))
     ("%(PDFout)" (lambda ()
@@ -1923,6 +1928,20 @@ already established, don't do anything."
   :group 'TeX-command
   :type 'boolean)
 
+(defcustom TeX-PDF-via-dvips-ps2pdf nil
+  "Whether to produce PDF output through the (La)TeX - dvips - ps2pdf sequence."
+  :group 'TeX-command
+  :type 'boolean)
+(make-variable-buffer-local 'TeX-PDF-via-dvips-ps2pdf)
+(put 'TeX-PDF-via-dvips-ps2pdf 'safe-local-variable 'booleanp)
+
+(defun TeX-toggle-PDF-via-dvips-ps2pdf ()
+  "Toggle `TeX-PDF-via-dvips-ps2pdf'."
+  (interactive)
+  (setq TeX-PDF-via-dvips-ps2pdf (not TeX-PDF-via-dvips-ps2pdf))
+  (message (concat "TeX-PDF-via-dvips-ps2pdf: "
+		   (if TeX-PDF-via-dvips-ps2pdf "on" "off"))))
+
 (define-minor-mode TeX-interactive-mode
   "Minor mode for interactive runs of TeX."
   nil nil nil
@@ -4740,6 +4759,10 @@ Brace insertion is only done if point is in a math construct and
 	 :style toggle :selected TeX-PDF-mode
 	 :active (not (eq TeX-engine 'omega))
 	 :help "Use PDFTeX to generate PDF instead of DVI"]
+       [ "PDF via dvips + ps2pdf" TeX-toggle-PDF-via-dvips-ps2pdf
+	 :style toggle :selected TeX-PDF-via-dvips-ps2pdf
+	 :visible TeX-PDF-mode
+	 :help "Compile with (La)TeX and convert to PDF with dvips + ps2pdf"]
        [ "Run Interactively" TeX-interactive-mode
 	 :style toggle :selected TeX-interactive-mode :keys "C-c C-t C-i"
 	 :help "Stop on errors in a TeX run"]
-- 
2.5.0

_______________________________________________
auctex-devel mailing list
auctex-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/auctex-devel

Reply via email to