;;;###autoload
(defcustom tex-main-file nil
"*The main TeX source file which includes this buffer's file.
-The command `tex-buffer' runs TeX on `tex-main-file'if that is non-nil."
+The command `tex-file' runs TeX on the file specified by `tex-main-file'
+if the variable is non-nil."
:type '(choice (const :tag "None" nil)
file)
:group 'tex-file)
(defcustom tex-run-command "tex"
"*Command used to run TeX subjob.
If this string contains an asterisk (`*'), that is replaced by the file name;
-otherwise, the file name, preceded by blank, is added at the end."
+otherwise the value of tex-start-options-string and the file name are added
+at the end, with blanks as separators."
:type 'string
:group 'tex-run)
+(defcustom tex-start-options-string "\\\\nonstopmode\\\\input"
+ "*TeX options to use when running TeX.
+These precede the input file name."
+ :type 'string
+ :group 'tex-run
+ :version "20.4")
+
;;;###autoload
(defcustom latex-run-command "latex"
"*Command used to run LaTeX subjob.
(setq imenu-create-index-function 'latex-imenu-create-index)
(make-local-variable 'tex-face-alist)
(setq tex-face-alist tex-latex-face-alist)
+ (make-local-variable 'fill-nobreak-predicate)
+ (setq fill-nobreak-predicate 'latex-fill-nobreak-predicate)
(run-hooks 'text-mode-hook 'tex-mode-hook 'latex-mode-hook))
;;;###autoload
\\\\[a-z]*space[ \t]*$\\|\\\\[a-z]*skip[ \t]*$\\|\
\\\\newpage[ \t]*$\\|\\\\[a-z]*page[a-z]*[ \t]*$\\|\\\\footnote[ \t]*$\\|\
\\\\marginpar[ \t]*$\\|\\\\parbox[ \t]*$\\|\\\\caption[ \t]*$")
+ (make-local-variable 'imenu-create-index-function)
+ (setq imenu-create-index-function 'latex-imenu-create-index)
+ (make-local-variable 'tex-face-alist)
+ (setq tex-face-alist tex-latex-face-alist)
+ (make-local-variable 'fill-nobreak-predicate)
+ (setq fill-nobreak-predicate 'latex-fill-nobreak-predicate)
(run-hooks
'text-mode-hook 'tex-mode-hook 'latex-mode-hook 'slitex-mode-hook))
(while not-finished
(cond ((looking-at "[ \t]+")
(goto-char (match-end 0))
- (if (eql category 'null)
+ (if (eq category 'null)
(setq category 'space)))
((looking-at "\n")
- (cond ((eql category 'newline)
+ (cond ((eq category 'newline)
(setq category 'par)
(setq not-finished nil))
(t
(t
(setq not-finished nil))))
(skip-chars-forward " \t\n\f")
- (if (eql category 'newline)
+ (if (eq category 'newline)
'space ;TeX doesn't distinguish
category)))
(condition-case ()
(save-restriction
(narrow-to-region start end)
+ ;; First check that the open and close parens balance in numbers.
(goto-char start)
(while (< 0 (setq max-possible-sexps (1- max-possible-sexps)))
- (forward-sexp 1)))
+ (forward-sexp 1))
+ ;; Now check that like matches like.
+ (goto-char start)
+ (while (progn (skip-syntax-forward "^(")
+ (not (eobp)))
+ (let ((match (matching-paren (following-char))))
+ (save-excursion
+ (forward-sexp 1)
+ (or (= (preceding-char) match)
+ (error "Mismatched parentheses"))))
+ (forward-char 1)))
(error
(skip-syntax-forward " .>")
(setq failure-point (point)))))
(save-excursion
(insert ?})))
+;; This function is used as the value of fill-nobreak-predicate
+;; in LaTeX mode. Its job is to prevent line-breaking inside
+;; of a \verb construct.
+(defun latex-fill-nobreak-predicate ()
+ (let ((opoint (point))
+ inside)
+ (save-excursion
+ (save-restriction
+ (beginning-of-line)
+ (narrow-to-region (point) opoint)
+ (while (re-search-forward "\\\\verb\\(.\\)" nil t)
+ (unless (re-search-forward (regexp-quote (match-string 1)) nil t)
+ (setq inside t)))))
+ inside))
+
;;; Like tex-insert-braces, but for LaTeX.
(define-skeleton tex-latex-block
"Create a matching pair of lines \\begin[OPT]{NAME} and \\end{NAME} at point.
(insert "\\end" text)
(if new-line-needed (insert ?\n))))
\f
-(defun tex-compilation-parse-errors ()
- "Parse the current buffer as error messages.
-This makes a list of error descriptors, compilation-error-list.
-For each source-file, line-number pair in the buffer,
-the source file is read in, and the text location is saved in
-compilation-error-list. The function `next-error', assigned to
-\\[next-error], takes the next error off the list and visits its location.
-
-This function works on TeX compilations only. It is necessary for
-that purpose, since TeX does not put file names on the same line as
-line numbers for the errors."
- (setq compilation-error-list nil)
- (message "Parsing error messages...")
- (modify-syntax-entry ?\{ "_")
- (modify-syntax-entry ?\} "_")
- (modify-syntax-entry ?\[ "_")
- (modify-syntax-entry ?\] "_")
- (let (text-buffer
- last-filename last-linenum)
- ;; Don't reparse messages already seen at last parse.
- (goto-char compilation-parsing-end)
- ;; Don't parse the first two lines as error messages.
- ;; This matters for grep.
- (if (bobp)
- (forward-line 2))
- (while (re-search-forward "^l\.[0-9]+ " nil t)
- (let (linenum filename
- error-marker text-marker)
- ;; Extract file name and line number from error message.
- ;; Line number is 2 away from beginning of line: "l.23"
- (beginning-of-line)
- (goto-char (+ (point) 2))
- (setq linenum (read (current-buffer)))
- ;; The file is the one that was opened last and is still open.
- ;; We need to find the last open parenthesis.
- (insert ?\))
- (backward-sexp)
- (forward-char)
- (setq filename (current-word))
- ;; Locate the erring file and line.
- (if (and (equal filename last-filename)
- (= linenum last-linenum))
- nil
- (skip-chars-backward "^(")
- (backward-char)
- (forward-sexp)
- (backward-delete-char 1)
- (setq error-marker (point-marker))
- ;; text-buffer gets the buffer containing this error's file.
- (if (not (equal filename last-filename))
- (setq text-buffer
- (and (file-exists-p (setq last-filename filename))
- (find-file-noselect filename))
- last-linenum 0))
- (if text-buffer
- ;; Go to that buffer and find the erring line.
- (save-excursion
- (set-buffer text-buffer)
- (if (zerop last-linenum)
- (progn
- (goto-char 1)
- (setq last-linenum 1)))
- (forward-line (- linenum last-linenum))
- (setq last-linenum linenum)
- (setq text-marker (point-marker))
- (setq compilation-error-list
- (cons (list error-marker text-marker)
- compilation-error-list)))))
- (forward-line 1)))
- (setq compilation-parsing-end (point-max)))
- (message "Parsing error messages...done")
- (setq compilation-error-list (nreverse compilation-error-list)))
-\f
;;; Invoking TeX in an inferior shell.
;;; Why use a shell instead of running TeX directly? Because if TeX
(setq tex-shell-map (nconc (make-sparse-keymap) shell-mode-map))
(tex-define-common-keys tex-shell-map)
(use-local-map tex-shell-map)
+ (compilation-minor-mode)
(run-hooks 'tex-shell-hook)
+ (setq comint-input-filter-functions 'shell-directory-tracker)
(while (zerop (buffer-size))
(sleep-for 1)))))
Do this in background if optional BACKGROUND is t. If COMMAND has no *,
FILE will be appended, preceded by a blank, to COMMAND. If FILE is nil, no
substitution will be made in COMMAND. COMMAND can be any expression that
-evaluates to a command string."
+evaluates to a command string.
+
+Return the process in which TeX is running."
(save-excursion
(let* ((cmd (eval command))
(proc (or (get-process "tex-shell") (error "No TeX subprocess")))
(goto-char (process-mark proc))
(insert string)
(comint-send-input)
- (setq tex-send-command-modified-tick (buffer-modified-tick buf)))))
+ (setq tex-send-command-modified-tick (buffer-modified-tick buf))
+ proc)))
(defun tex-delete-last-temp-files (&optional not-all)
"Delete any junk files from last temp file.
(let* ((dir (file-name-directory tex-last-temp-file))
(list (and (file-directory-p dir)
(file-name-all-completions
- (file-name-nondirectory tex-last-temp-file) dir))))
+ (file-name-sans-extension
+ (file-name-nondirectory tex-last-temp-file))
+ dir))))
(while list
(if not-all
(and
(add-hook 'kill-emacs-hook 'tex-delete-last-temp-files)
+(defvar tex-start-tex-marker nil
+ "Marker pointing after last TeX-running command in the TeX shell buffer.")
+
+(defun tex-start-tex (command file)
+ "Start a TeX run, using COMMAND on FILE."
+ (let* ((star (string-match "\\*" command))
+ (compile-command
+ (if star
+ (concat (substring command 0 star)
+ (comint-quote-filename file)
+ (substring command (1+ star)))
+ (concat command " "
+ (comint-quote-filename tex-start-options-string) " "
+ (comint-quote-filename file)))))
+ (with-current-buffer (process-buffer (tex-send-command compile-command))
+ (save-excursion
+ (forward-line -1)
+ (setq tex-start-tex-marker (point-marker)))
+ (make-local-variable 'compilation-parse-errors-function)
+ (setq compilation-parse-errors-function 'tex-compilation-parse-errors))))
+\f
+(defun tex-compilation-parse-errors (limit-search find-at-least)
+ "Parse the current buffer as error messages.
+This makes a list of error descriptors, `compilation-error-list'.
+For each source-file, line-number pair in the buffer,
+the source file is read in, and the text location is saved in
+`compilation-error-list'. The function `next-error', assigned to
+\\[next-error], takes the next error off the list and visits its location.
+
+If LIMIT-SEARCH is non-nil, don't bother parsing past that location.
+If FIND-AT-LEAST is non-nil, don't bother parsing after finding that
+
+This function works on TeX compilations only. It is necessary for
+that purpose, since TeX does not put file names on the same line as
+line numbers for the errors."
+ (require 'thingatpt)
+ (setq compilation-error-list nil)
+ (message "Parsing error messages...")
+ (let ((old-lc-syntax (char-syntax ?\{))
+ (old-rc-syntax (char-syntax ?\}))
+ (old-lb-syntax (char-syntax ?\[))
+ (old-rb-syntax (char-syntax ?\]))
+ (num-found 0) last-filename last-linenum last-position)
+ (unwind-protect
+ (progn
+ (modify-syntax-entry ?\{ "_")
+ (modify-syntax-entry ?\} "_")
+ (modify-syntax-entry ?\[ "_")
+ (modify-syntax-entry ?\] "_")
+ ;; Don't reparse messages already seen at last parse.
+ (goto-char (max (or compilation-parsing-end 0)
+ tex-start-tex-marker))
+ ;; Don't parse the first two lines as error messages.
+ ;; This matters for grep.
+ (if (bobp) (forward-line 2))
+ (while (re-search-forward
+ "^l\\.\\([0-9]+\\) \\(\\.\\.\\.\\)?\\(.*\\)$"
+ (and (or (null find-at-least)
+ (>= num-found find-at-least)) limit-search) t)
+ ;; Extract file name and line number from error message.
+ ;; Line number is 2 away from beginning of line: "l.23"
+ ;; The file is the one that was opened last and is still open.
+ ;; We need to find the last open parenthesis.
+ (let* ((linenum (string-to-int (match-string 1)))
+ (error-text (regexp-quote (match-string 3)))
+ (filename
+ (save-excursion
+ (backward-up-list 1)
+ (skip-syntax-forward "(_")
+ (while (not (file-readable-p
+ (thing-at-point 'filename)))
+ (skip-syntax-backward "(_")
+ (backward-up-list 1)
+ (skip-syntax-forward "(_"))
+ (thing-at-point 'filename)))
+ (error-marker
+ (save-excursion
+ (re-search-backward "^! " nil t)
+ (point-marker)))
+ (new-file (or (null last-filename)
+ (not (string-equal last-filename filename))))
+ (error-location
+ (save-excursion
+ (if (equal filename tex-last-temp-file)
+ (set-buffer tex-last-buffer-texed)
+ (set-buffer (find-file-noselect filename)))
+ (if new-file
+ (goto-line linenum)
+ (goto-char last-position)
+ (forward-line (- linenum last-linenum)))
+ ;first try a forward search
+ ;for the error text, then a
+ ;backward search limited by
+ ;the last error
+ (let ((starting-point (point)))
+ (or (re-search-forward error-text nil t)
+ (re-search-backward
+ error-text
+ (marker-position last-position) t)
+ (goto-char starting-point)))
+ (point-marker))))
+ (setq last-filename filename)
+ (if (or new-file
+ (not (= last-position error-location)))
+ (progn
+ (setq num-found (1+ num-found))
+ (setq last-position error-location)
+ (setq last-linenum linenum)
+ (setq compilation-error-list
+ (nconc compilation-error-list
+ (list (cons error-marker
+ error-location)))))))))
+ (modify-syntax-entry ?\{ (char-to-string old-lc-syntax))
+ (modify-syntax-entry ?\} (char-to-string old-rc-syntax))
+ (modify-syntax-entry ?\[ (char-to-string old-lb-syntax))
+ (modify-syntax-entry ?\] (char-to-string old-rb-syntax))))
+ (setq compilation-parsing-end (point))
+ (message "Parsing error messages...done"))
+\f
;;; The commands:
(defun tex-region (beg end)
;; Record the file name to be deleted afterward.
(setq tex-last-temp-file tex-out-file)
(tex-send-command tex-shell-cd-command zap-directory)
- (tex-send-command tex-command tex-out-file)
+ (tex-start-tex tex-command tex-out-file)
(tex-display-shell)
(setq tex-print-file tex-out-file)
(setq tex-last-buffer-texed (current-buffer))))
(tex-kill-job)
(tex-start-shell))
(tex-send-command tex-shell-cd-command file-dir)
- (tex-send-command tex-command source-file)
+ (tex-start-tex tex-command source-file)
(tex-display-shell)
(setq tex-last-buffer-texed (current-buffer))
(setq tex-print-file source-file)))
(setq print-file-name-dvi test-name))
(if (not (file-exists-p print-file-name-dvi))
(error "No appropriate `.dvi' file could be found")
+ (if (tex-shell-running)
+ (tex-kill-job)
+ (tex-start-shell))
(tex-send-command
(if alt tex-alt-dvi-print-command tex-dvi-print-command)
print-file-name-dvi t))))
(provide 'tex-mode)
;;; tex-mode.el ends here
-