diff options
| author | Stefan Monnier | 2003-05-15 01:29:53 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2003-05-15 01:29:53 +0000 |
| commit | 75035a8056a15f5d52ff52744844ef79446e3746 (patch) | |
| tree | 6cd22c56a07f03648fa6205a19902dd055b13363 /lisp/textmodes | |
| parent | 588c9a7153d7164bb7d8673a775c424943a944d5 (diff) | |
| download | emacs-75035a8056a15f5d52ff52744844ef79446e3746.tar.gz emacs-75035a8056a15f5d52ff52744844ef79446e3746.zip | |
(tex-compile-history, tex-input-files-re)
(tex-use-reftex, tex-compile-commands): New vars.
(tex-summarize-command, tex-uptodate-p, tex-executable-exists-p)
(tex-command-executable, tex-command-active-p, tex-compile-default)
New functions.
(tex-compile): New command.
(tex-mode-map): Bind it to C-c C-c.
Diffstat (limited to 'lisp/textmodes')
| -rw-r--r-- | lisp/textmodes/tex-mode.el | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el index 34bd13e146a..c0e606e744c 100644 --- a/lisp/textmodes/tex-mode.el +++ b/lisp/textmodes/tex-mode.el | |||
| @@ -693,6 +693,7 @@ An alternative value is \" . \", if you use a font with a narrow period." | |||
| 693 | (define-key map "\C-c\C-r" 'tex-region) | 693 | (define-key map "\C-c\C-r" 'tex-region) |
| 694 | (define-key map "\C-c\C-b" 'tex-buffer) | 694 | (define-key map "\C-c\C-b" 'tex-buffer) |
| 695 | (define-key map "\C-c\C-f" 'tex-file) | 695 | (define-key map "\C-c\C-f" 'tex-file) |
| 696 | (define-key map "\C-c\C-c" 'tex-compile) | ||
| 696 | (define-key map "\C-c\C-i" 'tex-bibtex-file) | 697 | (define-key map "\C-c\C-i" 'tex-bibtex-file) |
| 697 | (define-key map "\C-c\C-o" 'latex-insert-block) | 698 | (define-key map "\C-c\C-o" 'latex-insert-block) |
| 698 | (define-key map "\C-c\C-e" 'latex-close-block) | 699 | (define-key map "\C-c\C-e" 'latex-close-block) |
| @@ -1524,6 +1525,53 @@ If NOT-ALL is non-nil, save the `.dvi' file." | |||
| 1524 | 1525 | ||
| 1525 | (add-hook 'kill-emacs-hook 'tex-delete-last-temp-files) | 1526 | (add-hook 'kill-emacs-hook 'tex-delete-last-temp-files) |
| 1526 | 1527 | ||
| 1528 | ;; | ||
| 1529 | ;; Machinery to guess the command that the user wants to execute. | ||
| 1530 | ;; | ||
| 1531 | |||
| 1532 | (defvar tex-compile-history nil) | ||
| 1533 | |||
| 1534 | (defvar tex-input-files-re | ||
| 1535 | (eval-when-compile | ||
| 1536 | (concat "\\." (regexp-opt '("tex" "texi" "texinfo" | ||
| 1537 | "bbl" "ind" "sty" "cls") t) | ||
| 1538 | ;; Include files with no dots (for directories). | ||
| 1539 | "\\'\\|\\`[^.]+\\'"))) | ||
| 1540 | |||
| 1541 | (defcustom tex-use-reftex t | ||
| 1542 | "If non-nil, use RefTeX's list of files to determine what command to use." | ||
| 1543 | :type 'boolean) | ||
| 1544 | |||
| 1545 | (defvar tex-compile-commands | ||
| 1546 | '(((concat "pdf" tex-command | ||
| 1547 | " " (shell-quote-argument tex-start-commands) " %f") | ||
| 1548 | t "%r.pdf") | ||
| 1549 | ((concat tex-command | ||
| 1550 | " " (shell-quote-argument tex-start-commands) " %f") | ||
| 1551 | t "%r.dvi") | ||
| 1552 | ("xdvi %r &" "%r.dvi") | ||
| 1553 | ("advi %r &" "%r.dvi") | ||
| 1554 | ("bibtex %r" "%r.aux" "%r.bbl") | ||
| 1555 | ("makeindex %r" "%r.idx" "%r.ind") | ||
| 1556 | ("texindex %r.??") | ||
| 1557 | ("dvipdfm %r" "%r.dvi" "%r.pdf") | ||
| 1558 | ("dvipdf %r" "%r.dvi" "%r.pdf") | ||
| 1559 | ("dvips %r" "%r.dvi" "%r.ps") | ||
| 1560 | ("gv %r.ps &" "%r.ps") | ||
| 1561 | ("gv %r.pdf &" "%r.pdf") | ||
| 1562 | ("xpdf %r.pdf &" "%r.pdf") | ||
| 1563 | ("lpr %r.ps" "%r.ps")) | ||
| 1564 | "List of commands for `tex-compile'. | ||
| 1565 | Each element should be of the form (FORMAT IN OUT) where | ||
| 1566 | FORMAT is an expression that evaluates to a string that can contain | ||
| 1567 | - `%r' the main file name without extension. | ||
| 1568 | - `%f' the main file name. | ||
| 1569 | IN can be either a string (with the same % escapes in it) indicating | ||
| 1570 | the name of the input file, or t to indicate that the input is all | ||
| 1571 | the TeX files of the document, or nil if we don't know. | ||
| 1572 | OUT describes the output file and is either a %-escaped string | ||
| 1573 | or nil to indicate that there is no output file.") | ||
| 1574 | |||
| 1527 | (defun tex-guess-main-file (&optional all) | 1575 | (defun tex-guess-main-file (&optional all) |
| 1528 | "Find a likely `tex-main-file'. | 1576 | "Find a likely `tex-main-file'. |
| 1529 | Looks for hints in other buffers in the same directory or in | 1577 | Looks for hints in other buffers in the same directory or in |
| @@ -1574,6 +1622,165 @@ ALL other buffers." | |||
| 1574 | buffer-file-name))))))) | 1622 | buffer-file-name))))))) |
| 1575 | (if (file-exists-p file) file (concat file ".tex")))) | 1623 | (if (file-exists-p file) file (concat file ".tex")))) |
| 1576 | 1624 | ||
| 1625 | (defun tex-summarize-command (cmd) | ||
| 1626 | (if (not (stringp cmd)) "" | ||
| 1627 | (mapconcat 'identity | ||
| 1628 | (mapcar (lambda (s) (car (split-string s))) | ||
| 1629 | (split-string cmd "\\s-*\\(?:;\\|&&\\)\\s-*")) | ||
| 1630 | "&"))) | ||
| 1631 | |||
| 1632 | (defun tex-uptodate-p (file) | ||
| 1633 | "Return non-nil if FILE is not uptodate w.r.t the document source files. | ||
| 1634 | FILE is typically the output DVI or PDF file." | ||
| 1635 | ;; We should check all the files included !!! | ||
| 1636 | (and | ||
| 1637 | ;; Clearly, the target must exist. | ||
| 1638 | (file-exists-p file) | ||
| 1639 | ;; And the last run must not have asked for a rerun. | ||
| 1640 | ;; FIXME: this should check that the last run was done on the same file. | ||
| 1641 | (let ((buf (condition-case nil (tex-shell-buf) (error nil)))) | ||
| 1642 | (when buf | ||
| 1643 | (with-current-buffer buf | ||
| 1644 | (save-excursion | ||
| 1645 | (goto-char (point-max)) | ||
| 1646 | (and (re-search-backward | ||
| 1647 | "(see the transcript file for additional information)" nil t) | ||
| 1648 | (> (save-excursion | ||
| 1649 | (or (re-search-backward "\\[[0-9]+\\]" nil t) | ||
| 1650 | (point-min))) | ||
| 1651 | (save-excursion | ||
| 1652 | (or (re-search-backward "Rerun" nil t) | ||
| 1653 | (point-min))))))))) | ||
| 1654 | ;; And the input files must not have been changed in the meantime. | ||
| 1655 | (let ((files (if (and tex-use-reftex | ||
| 1656 | (fboundp 'reftex-scanning-info-available-p) | ||
| 1657 | (reftex-scanning-info-available-p)) | ||
| 1658 | (reftex-all-document-files) | ||
| 1659 | (list (file-name-directory (expand-file-name file))))) | ||
| 1660 | (ignored-dirs-re | ||
| 1661 | (concat | ||
| 1662 | (regexp-opt | ||
| 1663 | (delq nil (mapcar (lambda (s) (if (eq (aref s (1- (length s))) ?/) | ||
| 1664 | (substring s 0 (1- (length s))))) | ||
| 1665 | completion-ignored-extensions)) | ||
| 1666 | t) "\\'")) | ||
| 1667 | (uptodate t)) | ||
| 1668 | (while (and files uptodate) | ||
| 1669 | (let ((f (pop files))) | ||
| 1670 | (if (file-directory-p f) | ||
| 1671 | (unless (string-match ignored-dirs-re f) | ||
| 1672 | (setq files (nconc | ||
| 1673 | (directory-files f t tex-input-files-re) | ||
| 1674 | files))) | ||
| 1675 | (when (file-newer-than-file-p f file) | ||
| 1676 | (setq uptodate nil))))) | ||
| 1677 | uptodate))) | ||
| 1678 | |||
| 1679 | |||
| 1680 | (autoload 'format-spec "format-spec") | ||
| 1681 | |||
| 1682 | (defvar tex-executable-cache nil) | ||
| 1683 | (defun tex-executable-exists-p (name) | ||
| 1684 | "Like `executable-find' but with a cache." | ||
| 1685 | (let ((cache (assoc name tex-executable-cache))) | ||
| 1686 | (if cache (cdr cache) | ||
| 1687 | (let ((executable (executable-find name))) | ||
| 1688 | (push (cons name executable) tex-executable-cache) | ||
| 1689 | executable)))) | ||
| 1690 | |||
| 1691 | (defun tex-command-executable (cmd) | ||
| 1692 | (let ((s (if (stringp cmd) cmd (eval (car cmd))))) | ||
| 1693 | (substring s 0 (string-match "[ \t]\\|\\'" s)))) | ||
| 1694 | |||
| 1695 | (defun tex-command-active-p (cmd fspec) | ||
| 1696 | "Return non-nil if the CMD spec might need to be run." | ||
| 1697 | (let ((in (nth 1 cmd)) | ||
| 1698 | (out (nth 2 cmd))) | ||
| 1699 | (if (stringp in) | ||
| 1700 | (let ((file (format-spec in fspec))) | ||
| 1701 | (when (file-exists-p file) | ||
| 1702 | (or (not out) | ||
| 1703 | (file-newer-than-file-p | ||
| 1704 | file (format-spec out fspec))))) | ||
| 1705 | (when (and (eq in t) (stringp out)) | ||
| 1706 | (not (tex-uptodate-p (format-spec out fspec))))))) | ||
| 1707 | |||
| 1708 | (defun tex-compile-default (dir fspec) | ||
| 1709 | "Guess a default command in DIR given the format-spec FSPEC." | ||
| 1710 | ;; TODO: Learn to do latex+dvips! | ||
| 1711 | (let ((cmds nil) | ||
| 1712 | (unchanged-in nil)) | ||
| 1713 | ;; Only consider active commands. | ||
| 1714 | (dolist (cmd tex-compile-commands) | ||
| 1715 | (when (tex-executable-exists-p (tex-command-executable cmd)) | ||
| 1716 | (if (tex-command-active-p cmd fspec) | ||
| 1717 | (push cmd cmds) | ||
| 1718 | (push (nth 1 cmd) unchanged-in)))) | ||
| 1719 | ;; Remove those commands whose input was considered stable for | ||
| 1720 | ;; some other command (typically if (t . "%.pdf") is inactive | ||
| 1721 | ;; then we're using pdflatex and the fact that the dvi file | ||
| 1722 | ;; is inexistent doesn't matter). | ||
| 1723 | (let ((tmp nil)) | ||
| 1724 | (dolist (cmd cmds) | ||
| 1725 | (unless (member (nth 1 cmd) unchanged-in) | ||
| 1726 | (push cmd tmp))) | ||
| 1727 | (if tmp (setq cmds tmp))) | ||
| 1728 | ;; remove commands whose input is not uptodate either. | ||
| 1729 | (let ((outs (delq nil (mapcar (lambda (x) (nth 2 x)) cmds)))) | ||
| 1730 | (dolist (cmd (prog1 cmds (setq cmds nil))) | ||
| 1731 | (unless (member (nth 1 cmd) outs) | ||
| 1732 | (push cmd cmds)))) | ||
| 1733 | ;; Select which file we're going to operate on (the latest). | ||
| 1734 | (let ((latest (nth 1 (car cmds)))) | ||
| 1735 | (dolist (cmd (prog1 (cdr cmds) (setq cmds (list (car cmds))))) | ||
| 1736 | (if (equal latest (nth 1 cmd)) | ||
| 1737 | (push cmd cmds) | ||
| 1738 | (unless (eq latest t) ;Can't beat that! | ||
| 1739 | (if (or (not (stringp latest)) | ||
| 1740 | (eq (nth 1 cmd) t) | ||
| 1741 | (and (stringp (nth 1 cmd)) | ||
| 1742 | (file-newer-than-file-p | ||
| 1743 | (format-spec (nth 1 cmd) fspec) | ||
| 1744 | (format-spec latest fspec)))) | ||
| 1745 | (setq latest (nth 1 cmd) cmds (list cmd))))))) | ||
| 1746 | ;; Expand the command spec into the actual text. | ||
| 1747 | (dolist (cmd (prog1 cmds (setq cmds nil))) | ||
| 1748 | (push (cons (eval (car cmd)) (cdr cmd)) cmds)) | ||
| 1749 | ;; Select the favorite command from the history. | ||
| 1750 | (let ((hist tex-compile-history) | ||
| 1751 | re) | ||
| 1752 | (while hist | ||
| 1753 | (setq re (concat "\\`" | ||
| 1754 | (regexp-quote (tex-command-executable (pop hist))) | ||
| 1755 | "\\([ \t]\\|\\'\\)")) | ||
| 1756 | (dolist (cmd cmds) | ||
| 1757 | (if (string-match re (car cmd)) | ||
| 1758 | (setq hist nil cmds (list cmd)))))) | ||
| 1759 | ;; Substitute and return. | ||
| 1760 | (format-spec (caar cmds) fspec))) | ||
| 1761 | |||
| 1762 | (defun tex-compile (dir cmd) | ||
| 1763 | "Run a command CMD on current TeX buffer's file in DIR." | ||
| 1764 | ;; FIXME: Use time-stamps on files to decide the next op. | ||
| 1765 | (interactive | ||
| 1766 | (let* ((file (tex-main-file)) | ||
| 1767 | (root (file-name-sans-extension file)) | ||
| 1768 | (dir (file-name-directory (expand-file-name file))) | ||
| 1769 | (fspec (list (cons ?r (comint-quote-filename root)) | ||
| 1770 | (cons ?f (comint-quote-filename file)))) | ||
| 1771 | (default (tex-compile-default dir fspec))) | ||
| 1772 | (list dir | ||
| 1773 | (completing-read | ||
| 1774 | (format "Command [%s]: " (tex-summarize-command default)) | ||
| 1775 | (mapcar (lambda (x) | ||
| 1776 | (list (format-spec (eval (car x)) fspec))) | ||
| 1777 | tex-compile-commands) | ||
| 1778 | nil nil nil 'tex-compile-history default)))) | ||
| 1779 | (save-some-buffers (not compilation-ask-about-save) nil) | ||
| 1780 | (if (tex-shell-running) | ||
| 1781 | (tex-kill-job) | ||
| 1782 | (tex-start-shell)) | ||
| 1783 | (tex-send-tex-command cmd dir)) | ||
| 1577 | 1784 | ||
| 1578 | (defun tex-start-tex (command file &optional dir) | 1785 | (defun tex-start-tex (command file &optional dir) |
| 1579 | "Start a TeX run, using COMMAND on FILE." | 1786 | "Start a TeX run, using COMMAND on FILE." |