diff --git a/tex-buf.el b/tex-buf.el index e006ea6..7282e5a 100644 --- a/tex-buf.el +++ b/tex-buf.el @@ -353,6 +353,13 @@ asked if it is positive, and suppressed if it is not." (read-from-minibuffer (concat name " command: ") command nil nil))) + ;; Kill the frame and buffer associated to the error overview before running + ;; the command. + (if (frame-live-p TeX-error-overview-frame) + (delete-frame TeX-error-overview-frame)) + (if (get-buffer TeX-error-overview-buffer-name) + (kill-buffer TeX-error-overview-buffer-name)) + ;; Now start the process (setq file (funcall file)) (TeX-process-set-variable file 'TeX-command-next TeX-command-Show) @@ -924,12 +931,18 @@ NAME is the name of the process.") "Cleanup TeX output buffer after running TeX. Parse the output buffer to collect errors and warnings if the -variable `TeX-parse-all-errors' is non-nil." +variable `TeX-parse-all-errors' is non-nil. + +Open the error overview if +`TeX-error-overview-open-after-TeX-run' is non-nil and there are +errors or warnings to show." (if (TeX-TeX-sentinel-check process name) () (message (concat name ": formatted " (TeX-current-pages))) (if TeX-parse-all-errors (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))) (defun TeX-current-pages () @@ -993,9 +1006,15 @@ Warnings can be indicated by LaTeX or packages." "Cleanup TeX output buffer after running LaTeX. Parse the output buffer to collect errors and warnings if the -variable `TeX-parse-all-errors' is non-nil." +variable `TeX-parse-all-errors' is non-nil. + +Open the error overview if +`TeX-error-overview-open-after-TeX-run' is non-nil and there are +errors or warnings to show." (if TeX-parse-all-errors (TeX-parse-all-errors)) + (if (and TeX-error-overview-open-after-TeX-run TeX-error-list) + (TeX-error-overview)) (cond ((TeX-TeX-sentinel-check process name)) ((and (save-excursion (re-search-forward @@ -1539,7 +1558,7 @@ already in an Emacs buffer) and the cursor is placed at the error." (beep) (TeX-pop-to-buffer old-buffer)) (t - (TeX-error-list-find-display-help item)))) + (apply 'TeX-find-display-help item)))) (goto-char TeX-error-point) (TeX-parse-error old-buffer))))) @@ -1688,19 +1707,62 @@ Return non-nil if an error or warning is found." t))) error-found)) -(defun TeX-error-list-find-display-help (item) - "Find the error and display the help associated to it. -ITEM is an element of `TeX-error-list' with all relevant -information about the error or warning." - (let ((type (car item))) - (apply (intern (concat "TeX-" - (cond - ((equal type 'error) - "error") - ((or (equal type 'warning) (equal type 'bad-box)) - "warning")) - "--find-display-help")) - (cdr item)))) +(defun TeX-find-display-help (type file line error offset context + string line-end bad-box) + "Find the error and display the help." + (unless file + (cond + ;; XXX: error messages have to be different? + ((equal type 'error) + (error "Error occurred after last TeX file closed")) + (t + (error "Could not determine file for warning")))) + + ;; Go back to TeX-buffer + (let ((runbuf (current-buffer)) + (master (with-current-buffer TeX-command-buffer + (expand-file-name (TeX-master-file)))) + (command-buffer TeX-command-buffer) + error-file-buffer start) + (run-hooks 'TeX-translate-location-hook) + (setq error-file-buffer (find-file file)) + ;; Set the value of `TeX-command-buffer' in the next file with an + ;; error to be displayed to the value it has in the current buffer. + (with-current-buffer error-file-buffer + (set (make-local-variable 'TeX-command-buffer) command-buffer)) + + ;; Find the location of the error or warning. + (when line + (goto-char (point-min)) + (forward-line (+ offset line -1)) + (cond + ;; Error. + ((equal type 'error) + (if (not (string= string " ")) + (search-forward string nil t))) + ;; Warning or bad box. + (t + (beginning-of-line 0) + (setq start (point)) + (goto-char (point-min)) + (forward-line (+ offset line-end -1)) + (end-of-line) + (when string + (search-backward string start t) + (search-forward string nil t))))) + + ;; Display the help. + (cond ((eq TeX-display-help 'expert) + (TeX-pop-to-buffer runbuf nil t) + (goto-char TeX-error-point) + (TeX-pop-to-buffer error-file-buffer nil t)) + (TeX-display-help + (TeX-help-error + error + (if (equal type 'warning) (concat "\n" context) context) + runbuf type)) + (t + (message (concat "! " error)))))) (defun TeX-error (&optional store) "Display an error. @@ -1754,44 +1816,11 @@ information in `TeX-error-list' instead of displaying the error." (setq TeX-error-point (point)) (if store ;; Store the error information. - (add-to-list 'TeX-error-list - (list 'error file line error offset context string) t) + (add-to-list 'TeX-error-list (list 'error file line error offset + context string nil nil) t) ;; Find the error point and display the help. - (TeX-error--find-display-help - file line error offset context string)))) - -(defun TeX-error--find-display-help (file line error offset context - string) - "Find the error and display the help." - ;; Find the error. - (if (null file) - (error "Error occurred after last TeX file closed")) - (let ((runbuf (current-buffer)) - (master (with-current-buffer - TeX-command-buffer - (expand-file-name (TeX-master-file)))) - (command-buffer TeX-command-buffer) - error-file-buffer) - (run-hooks 'TeX-translate-location-hook) - (setq error-file-buffer (find-file file)) - ;; Set the value of `TeX-command-buffer' in the next file with an - ;; error to be displayed to the value it has in the current buffer. - (with-current-buffer error-file-buffer - (set (make-local-variable 'TeX-command-buffer) command-buffer)) - (goto-char (point-min)) - (forward-line (+ offset line -1)) - (if (not (string= string " ")) - (search-forward string nil t)) - - ;; Explain the error. - (cond ((eq TeX-display-help 'expert) - (TeX-pop-to-buffer runbuf nil t) - (goto-char TeX-error-point) - (TeX-pop-to-buffer error-file-buffer nil t)) - (TeX-display-help - (TeX-help-error error context runbuf 'error)) - (t - (message (concat "! " error)))))) + (TeX-find-display-help + 'error file line error offset context string nil nil)))) (defun TeX-warning (warning &optional store) "Display a warning for WARNING. @@ -1800,7 +1829,7 @@ If optional argument STORE is non-nil, store the warning information in `TeX-error-list' instead of displaying the warning." - (let* (;; bad-box is nil if this is a "LaTeX Warning" + (let* ( ;; bad-box is nil if this is a "LaTeX Warning" (bad-box (string-match "\\\\[vh]box.*[0-9]*--[0-9]*" warning)) ;; line-string: match 1 is beginning line, match 2 is end line (line-string (if bad-box " \\([0-9]*\\)--\\([0-9]*\\)" @@ -1850,57 +1879,15 @@ warning." (list (if bad-box 'bad-box 'warning) file line warning offset context string line-end bad-box) t) ;; Find the warning point and display the help. - (TeX-warning--find-display-help - file line warning offset context string line-end bad-box)))) - -(defun TeX-warning--find-display-help (file line error offset context - string line-end bad-box) - "Find the warning and display the help." - (unless file - (error "Could not determine file for warning")) - - ;; Go back to TeX-buffer - (let ((runbuf (current-buffer)) - (master (with-current-buffer - TeX-command-buffer - (expand-file-name (TeX-master-file)))) - (command-buffer TeX-command-buffer) - error-file-buffer) - (run-hooks 'TeX-translate-location-hook) - (setq error-file-buffer (find-file file)) - ;; Set the value of `TeX-command-buffer' in the next file with an - ;; error to be displayed to the value it has in the current buffer. - (with-current-buffer error-file-buffer - (set (make-local-variable 'TeX-command-buffer) command-buffer)) - ;; Find line and string - (when line - (goto-char (point-min)) - (forward-line (+ offset line -1)) - (beginning-of-line 0) - (let ((start (point))) - (goto-char (point-min)) - (forward-line (+ offset line-end -1)) - (end-of-line) - (when string - (search-backward string start t) - (search-forward string nil t)))) - ;; Display help - (cond ((eq TeX-display-help 'expert) - (TeX-pop-to-buffer runbuf nil t) - (goto-char TeX-error-point) - (TeX-pop-to-buffer error-file-buffer nil t)) - (TeX-display-help - (TeX-help-error error (if bad-box context (concat "\n" context)) - runbuf (if bad-box 'bad-box 'warning))) - (t - (message (concat "! " error)))))) + (TeX-find-display-help (if bad-box 'bad-box 'warning) file line warning + offset context string line-end bad-box)))) ;;; - Help (defgroup TeX-error-description-faces nil "Faces used in error descriptions." :prefix "TeX-error-description-" - :group 'AUCTeX) + :group 'TeX-output) (defface TeX-error-description-error ;; This is the same as `error' face in latest GNU Emacs versions. @@ -2422,6 +2409,211 @@ error." (regexp :tag "Match") (string :format "Description:\n%v")))) +;;; Error Overview + +(defvar TeX-error-overview-active-buffer nil + "The active buffer for the current error overview.") + +(defvar TeX-error-overview-orig-frame nil + "Frame from which the error overview has been launched.") + +(defvar TeX-error-overview-frame nil + "The frame of the error overview.") + +(defun TeX-error-overview-goto-source (&optional button) + "Go to the error point in the source. +If optional argument BUTTON is non-nil, go to source associated +to the selected error." + (interactive) + (let ((index (if button (button-get button 'id) (tabulated-list-get-id))) + item) + (if index + (progn + ;; Switch to source frame. + (select-frame TeX-error-overview-orig-frame) + ;; Get the error details. + (with-current-buffer TeX-error-overview-active-buffer + (setq item (nth index TeX-error-list) + TeX-error-last-visited index)) + (with-current-buffer TeX-command-buffer + ;; For consistency with `TeX-parse-TeX', use the major mode of + ;; `TeX-command-buffer' when visiting the error point. + (let ((default-major-mode major-mode)) + ;; Find the error and display the help. + (apply 'TeX-find-display-help item))) + ;; Return to the error overview frame. + (select-frame TeX-error-overview-frame)) + (message "No more errors.") + (beep)))) + +(defun TeX-error-overview-make-entries () + "Generate the list of errors to be printed using `tabulated-list-entries'." + (with-current-buffer TeX-error-overview-active-buffer + (let ((id 0) + line type entries) + (mapc + (lambda (entry) + (setq type (nth 0 entry) + line (nth 2 entry)) + (add-to-list + 'entries + (list + ;; ID + id + (vector + ;; File + (nth 1 entry) + ;; Line + (if (numberp line) + (number-to-string line) + "") + ;; Type + (cond + ((equal type 'error) + (propertize "Error" 'font-lock-face 'TeX-error-description-error)) + ((equal type 'warning) + (propertize "Warning" 'font-lock-face + 'TeX-error-description-warning)) + ((equal type 'bad-box) + (propertize "Bad box" 'font-lock-face + 'TeX-error-description-warning)) + (t + "")) + ;; Message + (list (nth 3 entry) + 'face 'link + 'follow-link t + 'id id + 'action 'TeX-error-overview-goto-source) + )) t) + (setq id (1+ id))) TeX-error-list) + entries))) + +(defun TeX-error-overview-next-error (&optional arg) + "Move to the next line and find the associated error. + +A prefix ARG specifies how many error messages to move; negative +means move back to previous error messages." + (interactive "p") + (if (= (forward-line arg) 0) + (TeX-error-overview-goto-source) + ;; If there are lines left to move we are at the beginning or at the end of + ;; the buffer and there are no more errors. + (message "No more errors.") + (beep))) + +(defun TeX-error-overview-previous-error (&optional arg) + "Move to the previous line and find the associated error. + +Prefix arg N says how many error messages to move backward (or +forward, if negative)." + (interactive "p") + (TeX-error-overview-next-error (- arg))) + +(defun TeX-error-overview-quit () + "Delete the error overview frame." + (interactive) + (delete-frame TeX-error-overview-frame) + (setq TeX-error-overview-orig-frame nil)) + +(defvar TeX-error-overview-mode-map + (let ((map (make-sparse-keymap)) + (menu-map (make-sparse-keymap))) + (define-key map "n" 'TeX-error-overview-next-error) + (define-key map "p" 'TeX-error-overview-previous-error) + (define-key map "q" 'TeX-error-overview-quit) + (define-key map "\C-m" 'TeX-error-overview-goto-source) + map) + "Local keymap for `TeX-error-overview-mode' buffers.") + +(defvar TeX-error-overview-list-entries nil + "List of errors to be used in the error overview.") + +(define-derived-mode TeX-error-overview-mode tabulated-list-mode + "TeX errors" + "Major mode for listing TeX errors." + (setq tabulated-list-format [("File" 25 nil) + ("Line" 4 nil :right-align t) + ("Type" 7 nil) + ("Message" 0 nil)] + tabulated-list-padding 1 + tabulated-list-entries TeX-error-overview-list-entries) + (tabulated-list-init-header) + (tabulated-list-print)) + +(defconst TeX-error-overview-buffer-name "*TeX errors*" + "Name of the buffer in which to show error list.") + +(defcustom TeX-error-overview-frame-parameters + '((name . "TeX errors") + (title . "TeX errors") + (height . 10) + (width . 80) + (top . (- 0)) + (left . (- 0)) + (unsplittable . t) + (minibuffer . nil) + (vertical-scroll-bars . t) + (tool-bar-lines . 0)) + "Parameters of the error overview frame." + :group 'TeX-output + :type 'alist + :options '((name string) (title string) (height integer) (width integer) + (top integer) (left integer) (unsplittable boolean) + (minibuffer boolean) (vertical-scroll-bars boolean) + (tool-bar-lines integer))) + +(defcustom TeX-error-overview-open-after-TeX-run nil + "Whether to open automatically the error overview after running TeX." + :group 'TeX-output + :type 'boolean) + +(defun TeX-error-overview () + "Show an overview of the errors occurred in the last TeX run." + (interactive) + ;; Check requirements before start. + (if (fboundp 'tabulated-list-mode) + (if (display-multi-frame-p) + (if (setq TeX-error-overview-active-buffer (TeX-active-buffer)) + (if (with-current-buffer TeX-error-overview-active-buffer + TeX-error-list) + (progn + (setq TeX-error-overview-list-entries + (TeX-error-overview-make-entries) + TeX-error-overview-orig-frame + (window-frame (selected-window))) + ;; Create the error overview buffer. This is + ;; automatically killed before running TeX commands, so if + ;; exists it is up-to-date and doesn't need to be + ;; re-created. + (unless (get-buffer TeX-error-overview-buffer-name) + (with-current-buffer (get-buffer-create + TeX-error-overview-buffer-name) + (TeX-error-overview-mode))) + (save-window-excursion + ;; Move point to the line associated to the last visited + ;; error. + (with-current-buffer TeX-error-overview-buffer-name + (goto-char (point-min)) + (forward-line (with-current-buffer + TeX-error-overview-active-buffer + TeX-error-last-visited)) + ;; Create a new frame. + (if (frame-live-p TeX-error-overview-frame) + ;; Do not create a duplicate frame if there is + ;; already one, just rise it. + (raise-frame TeX-error-overview-frame) + (setq TeX-error-overview-frame + (make-frame + TeX-error-overview-frame-parameters)) + (set-window-buffer (selected-window) + TeX-error-overview-buffer-name) + (set-window-dedicated-p (selected-window) t))))) + (error "No errror or warning to show")) + (error "No process for this document")) + (error "Error overview requires multi frame support")) + (error "Error overview is available only in Emacs 24 or later"))) + ;;; Output mode (if (fboundp 'special-mode)