|
|
1.1 root 1: ;; TeX mode commands.
2: ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3: ;; Rewritten following contributions by William F. Schelter
4: ;; and Dick King (king@kestrel).
5: ;; Modified August 1986 by Stephen Gildea <mit-erl!gildea> and
6: ;; Michael Prange <mit-erl!prange> to add LaTeX support and enhance
7: ;; TeX-region.
8: ;; Added TeX-directory and reorganized somewhat gildea 21 Nov 86
9:
10: ;; This file is part of GNU Emacs.
11:
12: ;; GNU Emacs is free software; you can redistribute it and/or modify
13: ;; it under the terms of the GNU General Public License as published by
14: ;; the Free Software Foundation; either version 1, or (at your option)
15: ;; any later version.
16:
17: ;; GNU Emacs is distributed in the hope that it will be useful,
18: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20: ;; GNU General Public License for more details.
21:
22: ;; You should have received a copy of the GNU General Public License
23: ;; along with GNU Emacs; see the file COPYING. If not, write to
24: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25:
26: ;; Still to do:
27: ;; Make TAB indent correctly for TeX code. Then we can make linefeed
28: ;; do something more useful.
29: ;;
30: ;; Have spell understand TeX instead of assuming the entire world
31: ;; uses nroff.
32: ;;
33: ;; The code for finding matching $ needs to be fixed.
34:
35: (provide 'tex-mode)
36:
37: (defvar TeX-directory "/tmp/"
38: "*Directory in which to run TeX subjob. Temporary files are
39: created in this directory.")
40: (defvar TeX-dvi-print-command "lpr -d"
41: "*Command string used by \\[TeX-print] to print a .dvi file.")
42: (defvar TeX-show-queue-command "lpq"
43: "*Command string used by \\[TeX-show-print-queue] to show the print queue
44: that \\[TeX-print] put your job on.")
45: (defvar TeX-default-mode 'plain-TeX-mode
46: "*Mode to enter for a new file when it can't be determined whether
47: the file is plain TeX or LaTeX or what.")
48:
49: (defvar TeX-command nil
50: "The command to run TeX on a file. The name of the file will be appended
51: to this string, separated by a space.")
52: (defvar TeX-trailer nil
53: "String appended after the end of a region sent to TeX by \\[TeX-region].")
54: (defvar TeX-start-of-header nil
55: "String used by \\[TeX-region] to delimit the start of the file's header.")
56: (defvar TeX-end-of-header nil
57: "String used by \\[TeX-region] to delimit the end of the file's header.")
58: (defvar TeX-shell-cd-command "cd"
59: "Command to give to shell running TeX to change directory. The value of
60: TeX-directory will be appended to this, separated by a space.")
61: (defvar TeX-zap-file nil
62: "Temporary file name used for text being sent as input to TeX.
63: Should be a simple file name with no extension or directory specification.")
64:
65: (defvar TeX-mode-syntax-table nil
66: "Syntax table used while in TeX mode.")
67:
68: (defun TeX-define-common-keys (keymap)
69: "Define the keys that we want defined both in TeX-mode
70: and in the TeX-shell."
71: (define-key keymap "\C-c\C-k" 'TeX-kill-job)
72: (define-key keymap "\C-c\C-l" 'TeX-recenter-output-buffer)
73: (define-key keymap "\C-c\C-q" 'TeX-show-print-queue)
74: (define-key keymap "\C-c\C-p" 'TeX-print)
75: )
76:
77: (defvar TeX-mode-map nil "Keymap for TeX mode")
78:
79: (if TeX-mode-map
80: nil
81: (setq TeX-mode-map (make-sparse-keymap))
82: (TeX-define-common-keys TeX-mode-map)
83: (define-key TeX-mode-map "\"" 'TeX-insert-quote)
84: (define-key TeX-mode-map "\n" 'TeX-terminate-paragraph)
85: (define-key TeX-mode-map "\e}" 'up-list)
86: (define-key TeX-mode-map "\e{" 'TeX-insert-braces)
87: (define-key TeX-mode-map "\C-c\C-r" 'TeX-region)
88: (define-key TeX-mode-map "\C-c\C-b" 'TeX-buffer)
89: (define-key TeX-mode-map "\C-c\C-f" 'TeX-close-LaTeX-block)
90: )
91:
92: (defvar TeX-shell-map nil
93: "Keymap for the TeX shell. A shell-mode-map with a few additions")
94:
95: ;(fset 'TeX-mode 'tex-mode) ;in loaddefs.
96:
97: ;;; This would be a lot simpler if we just used a regexp search,
98: ;;; but then it would be too slow.
99: (defun tex-mode ()
100: "Major mode for editing files of input for TeX or LaTeX.
101: Trys to intuit whether this file is for plain TeX or LaTeX and
102: calls plain-tex-mode or latex-mode. If it cannot be determined
103: \(e.g., there are no commands in the file), the value of
104: TeX-default-mode is used."
105: (interactive)
106: (let (mode slash comment)
107: (save-excursion
108: (goto-char (point-min))
109: (while (and (setq slash (search-forward "\\" nil t))
110: (setq comment (let ((search-end (point)))
111: (save-excursion
112: (beginning-of-line)
113: (search-forward "%" search-end t))))))
114: (if (and slash (not comment))
115: (setq mode (if (looking-at "documentstyle")
116: 'latex-mode
117: 'plain-tex-mode))))
118: (if mode (funcall mode)
119: (funcall TeX-default-mode))))
120:
121: (fset 'plain-TeX-mode 'plain-tex-mode)
122: (fset 'LaTeX-mode 'latex-mode)
123:
124: (defun plain-tex-mode ()
125: "Major mode for editing files of input for plain TeX.
126: Makes $ and } display the characters they match.
127: Makes \" insert `` when it seems to be the beginning of a quotation,
128: and '' when it appears to be the end; it inserts \" only after a \\.
129:
130: Use \\[TeX-region] to run TeX on the current region, plus a \"header\"
131: copied from the top of the file (containing macro definitions, etc.),
132: running TeX under a special subshell. \\[TeX-buffer] does the whole buffer.
133: \\[TeX-print] prints the .dvi file made by either of these.
134:
135: Use \\[validate-TeX-buffer] to check buffer for paragraphs containing
136: mismatched $'s or braces.
137:
138: Special commands:
139: \\{TeX-mode-map}
140:
141: Mode variables:
142: TeX-directory
143: Directory in which to create temporary files for TeX jobs
144: run by \\[TeX-region] or \\[TeX-buffer].
145: TeX-dvi-print-command
146: Command string used by \\[TeX-print] to print a .dvi file.
147: TeX-show-queue-command
148: Command string used by \\[TeX-show-print-queue] to show the print
149: queue that \\[TeX-print] put your job on.
150:
151: Entering plain-TeX mode calls the value of text-mode-hook,
152: then the value of TeX-mode-hook, and then the value
153: of plain-TeX-mode-hook."
154: (interactive)
155: (TeX-common-initialization)
156: (setq mode-name "TeX")
157: (setq major-mode 'plain-TeX-mode)
158: (setq TeX-command "tex")
159: (setq TeX-start-of-header "%**start of header")
160: (setq TeX-end-of-header "%**end of header")
161: (setq TeX-trailer "\\bye\n")
162: (run-hooks 'text-mode-hook 'TeX-mode-hook 'plain-TeX-mode-hook))
163:
164: (defun latex-mode ()
165: "Major mode for editing files of input for LaTeX.
166: Makes $ and } display the characters they match.
167: Makes \" insert `` when it seems to be the beginning of a quotation,
168: and '' when it appears to be the end; it inserts \" only after a \\.
169:
170: Use \\[TeX-region] to run LaTeX on the current region, plus the preamble
171: copied from the top of the file (containing \\documentstyle, etc.),
172: running LaTeX under a special subshell. \\[TeX-buffer] does the whole buffer.
173: \\[TeX-print] prints the .dvi file made by either of these.
174:
175: Use \\[validate-TeX-buffer] to check buffer for paragraphs containing
176: mismatched $'s or braces.
177:
178: Special commands:
179: \\{TeX-mode-map}
180:
181: Mode variables:
182: TeX-directory
183: Directory in which to create temporary files for TeX jobs
184: run by \\[TeX-region] or \\[TeX-buffer].
185: TeX-dvi-print-command
186: Command string used by \\[TeX-print] to print a .dvi file.
187: TeX-show-queue-command
188: Command string used by \\[TeX-show-print-queue] to show the print
189: queue that \\[TeX-print] put your job on.
190:
191: Entering LaTeX mode calls the value of text-mode-hook,
192: then the value of TeX-mode-hook, and then the value
193: of LaTeX-mode-hook."
194: (interactive)
195: (TeX-common-initialization)
196: (setq mode-name "LaTeX")
197: (setq major-mode 'LaTeX-mode)
198: (setq TeX-command "latex")
199: (setq TeX-start-of-header "\\documentstyle")
200: (setq TeX-end-of-header "\\begin{document}")
201: (setq TeX-trailer "\\end{document}\n")
202: (run-hooks 'text-mode-hook 'TeX-mode-hook 'LaTeX-mode-hook))
203:
204: (defun TeX-common-initialization ()
205: (kill-all-local-variables)
206: (use-local-map TeX-mode-map)
207: (setq local-abbrev-table text-mode-abbrev-table)
208: (if (null TeX-mode-syntax-table)
209: (progn
210: (setq TeX-mode-syntax-table (make-syntax-table))
211: (set-syntax-table TeX-mode-syntax-table)
212: (modify-syntax-entry ?\\ ".")
213: (modify-syntax-entry ?\f ">")
214: (modify-syntax-entry ?\n ">")
215: (modify-syntax-entry ?$ "$$")
216: (modify-syntax-entry ?% "<")
217: (modify-syntax-entry ?\" ".")
218: (modify-syntax-entry ?& ".")
219: (modify-syntax-entry ?_ ".")
220: (modify-syntax-entry ?@ "_")
221: (modify-syntax-entry ?~ " ")
222: (modify-syntax-entry ?' "w"))
223: (set-syntax-table TeX-mode-syntax-table))
224: (make-local-variable 'paragraph-start)
225: (setq paragraph-start "^[ \t]*$\\|^[\f\\\\%]")
226: (make-local-variable 'paragraph-separate)
227: (setq paragraph-separate paragraph-start)
228: (make-local-variable 'comment-start)
229: (setq comment-start "%")
230: (make-local-variable 'comment-start-skip)
231: (setq comment-start-skip "\\(\\(^\\|[^\\]\\)\\(\\\\\\\\\\)*\\)\\(%+ *\\)")
232: (make-local-variable 'comment-indent-hook)
233: (setq comment-indent-hook 'TeX-comment-indent)
234: (make-local-variable 'TeX-command)
235: (make-local-variable 'TeX-start-of-header)
236: (make-local-variable 'TeX-end-of-header)
237: (make-local-variable 'TeX-trailer))
238:
239: (defun TeX-comment-indent ()
240: (if (looking-at "%%%")
241: (current-column)
242: (skip-chars-backward " \t")
243: (max (if (bolp) 0 (1+ (current-column)))
244: comment-column)))
245:
246: (defun TeX-insert-quote (arg)
247: "Insert ``, '' or \" according to preceding character.
248: With prefix argument, always insert \" characters."
249: (interactive "P")
250: (if arg
251: (let ((count (prefix-numeric-value arg)))
252: (if (listp arg)
253: (self-insert-command 1) ;C-u always inserts just one
254: (self-insert-command count)))
255: (insert
256: (cond
257: ((or (bobp)
258: (save-excursion
259: (forward-char -1)
260: (looking-at "[ \t\n]\\|\\s(")))
261: "``")
262: ((= (preceding-char) ?\\)
263: ?\")
264: (t "''")))))
265:
266: (defun validate-TeX-buffer ()
267: "Check current buffer for paragraphs containing mismatched $'s.
268: As each such paragraph is found, a mark is pushed at its beginning,
269: and the location is displayed for a few seconds."
270: (interactive)
271: (let ((opoint (point)))
272: (goto-char (point-max))
273: ;; Does not use save-excursion
274: ;; because we do not want to save the mark.
275: (unwind-protect
276: (while (and (not (input-pending-p)) (not (bobp)))
277: (let ((end (point)))
278: (search-backward "\n\n" nil 'move)
279: (or (TeX-validate-paragraph (point) end)
280: (progn
281: (push-mark (point))
282: (message "Mismatch found in pararaph starting here")
283: (sit-for 4)))))
284: (goto-char opoint))))
285:
286: (defun TeX-validate-paragraph (start end)
287: (condition-case ()
288: (save-excursion
289: (save-restriction
290: (narrow-to-region start end)
291: (goto-char start)
292: (forward-sexp (- end start))
293: t))
294: (error nil)))
295:
296: (defun TeX-terminate-paragraph (inhibit-validation)
297: "Insert two newlines, breaking a paragraph for TeX.
298: Check for mismatched braces/$'s in paragraph being terminated.
299: A prefix arg inhibits the checking."
300: (interactive "P")
301: (or inhibit-validation
302: (TeX-validate-paragraph
303: (save-excursion
304: (search-backward "\n\n" nil 'move)
305: (point))
306: (point))
307: (message "Paragraph being closed appears to contain a mismatch"))
308: (insert "\n\n"))
309:
310: (defun TeX-insert-braces ()
311: "Make a pair of braces and be poised to type inside of them."
312: (interactive)
313: (insert ?\{)
314: (save-excursion
315: (insert ?})))
316:
317: ;;; Like TeX-insert-braces, but for LaTeX.
318: (defun TeX-close-LaTeX-block ()
319: "Creates an \\end{...} to match \\begin{...} on the current line and
320: puts point on the blank line between them."
321: (interactive "*")
322: (let ((fail-point (point)))
323: (end-of-line)
324: (if (re-search-backward "\\\\begin{\\([^}\n]*\\)}"
325: (save-excursion (beginning-of-line) (point)) t)
326: (let ((text (buffer-substring (match-beginning 1) (match-end 1)))
327: (indentation (current-column)))
328: (end-of-line)
329: (delete-horizontal-space)
330: (insert "\n\n")
331: (indent-to indentation)
332: (insert "\\end{" text "}")
333: (forward-line -1))
334: (goto-char fail-point)
335: (ding))))
336:
337: ;;; Invoking TeX in an inferior shell.
338:
339: ;;; Why use a shell instead of running TeX directly? Because if TeX
340: ;;; gets stuck, the user can switch to the shell window and type at it.
341:
342: ;;; The utility functions:
343:
344: (defun TeX-start-shell ()
345: (require 'shell)
346: (save-excursion
347: (set-buffer (make-shell "TeX-shell" nil nil "-v"))
348: (setq TeX-shell-map (copy-keymap shell-mode-map))
349: (TeX-define-common-keys TeX-shell-map)
350: (use-local-map TeX-shell-map)
351: (if (zerop (buffer-size))
352: (sleep-for 1))))
353:
354: (defun set-buffer-directory (buffer directory)
355: "Set BUFFER's default directory to be DIRECTORY."
356: (setq directory (file-name-as-directory (expand-file-name directory)))
357: (if (not (file-directory-p directory))
358: (error "%s is not a directory" directory)
359: (save-excursion
360: (set-buffer buffer)
361: (setq default-directory directory))))
362:
363: ;;; The commands:
364:
365: ;;; It's a kludge that we have to create a special buffer just
366: ;;; to write out the TeX-trailer. It would nice if there were a
367: ;;; function like write-region that would write literal strings.
368:
369: (defun TeX-region (beg end)
370: "Run TeX on the current region. A temporary file (TeX-zap-file) is
371: written in directory TeX-directory, and TeX is run in that directory.
372: If the buffer has a header, it is written to the temporary file before
373: the region itself. The buffer's header is all lines between the
374: strings defined by TeX-start-of-header and TeX-end-of-header
375: inclusive. The header must start in the first 100 lines. The value
376: of TeX-trailer is appended to the temporary file after the region."
377: (interactive "r")
378: (if (get-buffer "*TeX-shell*")
379: (TeX-kill-job)
380: (TeX-start-shell))
381: (or TeX-zap-file (setq TeX-zap-file (make-temp-name "#tz")))
382: (let ((tex-out-file (concat TeX-zap-file ".tex"))
383: (temp-buffer (get-buffer-create " TeX-Output-Buffer"))
384: (zap-directory
385: (file-name-as-directory (expand-file-name TeX-directory))))
386: (save-excursion
387: (save-restriction
388: (widen)
389: (goto-char (point-min))
390: (forward-line 100)
391: (let ((search-end (point))
392: (hbeg (point-min)) (hend (point-min))
393: (default-directory zap-directory))
394: (goto-char (point-min))
395: ;; Initialize the temp file with either the header or nothing
396: (if (search-forward TeX-start-of-header search-end t)
397: (progn
398: (beginning-of-line)
399: (setq hbeg (point)) ;mark beginning of header
400: (if (search-forward TeX-end-of-header nil t)
401: (progn (forward-line 1)
402: (setq hend (point))) ;mark end of header
403: (setq hbeg (point-min))))) ;no header
404: (write-region (min hbeg beg) hend tex-out-file nil nil)
405: (write-region (max beg hend) end tex-out-file t nil))
406: (let ((local-tex-trailer TeX-trailer))
407: (set-buffer temp-buffer)
408: (erase-buffer)
409: ;; make sure trailer isn't hidden by a comment
410: (insert-string "\n")
411: (if local-tex-trailer (insert-string local-tex-trailer))
412: (set-buffer-directory temp-buffer zap-directory)
413: (write-region (point-min) (point-max) tex-out-file t nil))))
414: (set-buffer-directory "*TeX-shell*" zap-directory)
415: (send-string "TeX-shell" (concat TeX-shell-cd-command " "
416: zap-directory "\n"))
417: (send-string "TeX-shell" (concat TeX-command " \""
418: tex-out-file "\"\n")))
419: (TeX-recenter-output-buffer 0))
420:
421: (defun TeX-buffer ()
422: "Run TeX on current buffer. See \\[TeX-region] for more information."
423: (interactive)
424: (TeX-region (point-min) (point-max)))
425:
426: (defun TeX-kill-job ()
427: "Kill the currently running TeX job."
428: (interactive)
429: (quit-process "TeX-shell" t))
430:
431: (defun TeX-recenter-output-buffer (linenum)
432: "Redisplay buffer of TeX job output so that most recent output can be seen.
433: The last line of the buffer is displayed on
434: line LINE of the window, or centered if LINE is nil."
435: (interactive "P")
436: (let ((tex-shell (get-buffer "*TeX-shell*"))
437: (old-buffer (current-buffer)))
438: (if (null tex-shell)
439: (message "No TeX output buffer")
440: (pop-to-buffer tex-shell)
441: (bury-buffer tex-shell)
442: (goto-char (point-max))
443: (recenter (if linenum
444: (prefix-numeric-value linenum)
445: (/ (window-height) 2)))
446: (pop-to-buffer old-buffer)
447: )))
448:
449: (defun TeX-print ()
450: "Print the .dvi file made by \\[TeX-region] or \\[TeX-buffer].
451: Runs the shell command defined by TeX-dvi-print-command."
452: (interactive)
453: (send-string "TeX-shell"
454: (concat TeX-dvi-print-command " \"" TeX-zap-file ".dvi\"\n"))
455: (TeX-recenter-output-buffer nil))
456:
457: (defun TeX-show-print-queue ()
458: "Show the print queue that \\[TeX-print] put your job on.
459: Runs the shell command defined by TeX-show-queue-command."
460: (interactive)
461: (if (not (get-buffer "*TeX-shell*"))
462: (TeX-start-shell))
463: (send-string "TeX-shell" (concat TeX-show-queue-command "\n"))
464: (TeX-recenter-output-buffer nil))
465:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.