Xref: utzoo comp.emacs:5286 gnu.emacs:436 Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!bbn!rochester!pt.cs.cmu.edu!centro.soar.cs.cmu.edu!shivers From: shivers@centro.soar.cs.cmu.edu (Olin Shivers) Newsgroups: comp.emacs,gnu.emacs Subject: New process modes for shell, Lisp, Scheme, T, TeX (part 3 of 3) Message-ID: <4237@pt.cs.cmu.edu> Date: 9 Feb 89 21:38:15 GMT Organization: Carnegie-Mellon University, CS/RI Lines: 1580 This message contains: 1. The standard anouncement header 2. A shar file for cmuscheme.el, cmutex.el, tea.el, and tea2.el. (The entire package must be split -- otherwise notesfiles sites will not be able to handle it.) ------------------------------------------------------------------------------- I have written new gnu-emacs packages that provide shell, inferior lisp, inferior scheme, and inferior T modes. These packages have the following advantages over the standard released gnu packages: - Input history is kept in all modes, traversed with M-p and M-n, just like on LispM's and various fancy shells. - Filename completion and query is available in all modes. - Keybindings are cross-compatible among all modes. - Keybindings are compatible with Zwei and Hemlock. - Directory tracking is more robust in shell mode, and is *only* active in shell mode. (Try entering "cd /" to an inferior lisp in the old package: Lisp barfs, but the inferior lisp mode goes ahead and changes the buffer's directory.) - Non-echoed text entry (for entering passwords) is available in all modes. - Shell and inferior Lisp modes are backwards compatible with the standard gnu modes. - One source for the inferior Lisp mode works in both emacs releases 18.4x and 18.5x. This has been the cause of confusing bugs for users who unwittingly tried to use an 18.4x version inferior Lisp mode in an 18.5x version emacs, and vice-versa. - A full set of eval/compile-region/defun commands for the inferior Lisp, Scheme, and T modes. - New modes are easily created for new types of processes. =============================================================================== THE BAD NEWS: It would be nice if the shell & inferior lisp package, cmushell.el, was completely plug-compatible with the old package in shell.el -- if you could just name the new version shell.el, and have it transparently replace the old one. But you can't. Several other packages (tex-mode, background, dbx, gdb, kermit, monkey, prolog, telnet) are also clients of shell mode. These packages assume detailed knowledge of shell mode internals in ways that are incompatible with the new mode (mostly because of the new mode's greater functionality). So, unless we are willing to port all of these packages, we can't have the new shell package be a complete replacement for shell.el -- that is, we can't name the file shell.el, and its main entry point (shell), because dbx.el will break when it loads it in and tries to use it. There are two ways to fix this. One: rewrite these other modes to use the new package. This is a win, but can't be assumed. The other, backwards compatible route, is to make this package non-conflict with shell.el, so both files can be loaded in at the same time. This is what I have done. So the mode names and major functions have different names, e.g: shell.el cmushell.el -------- ---------- M-x shell M-x cmushell -- Fire up a shell M-x run-lisp M-x cmulisp -- Fire up a lisp shell-mode-map cmushell-mode-map -- Keybindings for [cmu]shell mode All the names have been carefully chosen so that shell.el and cmushell.el won't tromp on each other -- that way dbx.el and friends can happily load in shell.el without breaking the cmushell.el package, and vice versa. With the exception of M-x cmushell and M-x cmulisp, however, most of the name changes are invisible to the user. Further, most of the customising variables that are common in functionality have the same name: inferior-lisp-program, explicit-shell-file-name, et al. Hook variables are different, so you can customise shell-mode and cmushell-mode differently, for instance. By the way, it is rather easy to port the shell.el-dependent packages to use the new stuff. There are fairly complete comments in the relevant source files showing how to do this. Note that this backwards-compatibility hassle *only* affects shell and inferior lisp mode; the other process-in-a-buffer modes (Scheme, T, etc.) do not have this problem. =============================================================================== GENERALIA: The implementation strategy was to factor common process functionality into a general command interpreter mode -- comint mode -- and then to build all the specific modes on top. This provides uniform, integrated functionality and interface across all the derived modes. Comint mode provides the input history, filename completion and query, non-echoed text entry, input editing, and process signalling (e.g., ^z, ^c, ...) commands. *Any* mode built on comint mode gets all this stuff automatically. Additionally, comint mode has general hooks for customising it to specific command interpreters, such as Lisp, Scheme, csh, ML, etc.. This release includes the following files: - comint.el comint mode - cmushell.el cmushell and cmulisp modes, built on comint mode. - cmuscheme.el inferior Scheme mode, built on comint mode. - tea.el inferior T mode, built on comint mode. - tea2.el Variant of tea.el - cmutex.el tex-mode.el with rewritten process interaction code. Some bugs also fixed. These packages have been in daily use by a user community of about 10-20 at CMU since August; most bugs have been shaken out. cmutex.el is less tested. Please notify me of bugs. The files are *extensively* commented; this should serve as sufficient documentation. Each file includes suggestions for your .emacs file in comments at the top. On-line documentation (C-h C-m, C-h C-f, C-h C-v) is available for modes, commands, and variables. This source is available on an FSF-style basis: use it any way you like as long as you don't charge money for it or change the basis of its availability; I assume no liability for its use. =============================================================================== INPUT HISTORY: There are actually two different ways to retrieve old commands for resubmission to a process. The standard way is to use the input history mechanism. An internal list is kept in each process buffer of the last n inputs (default: 30). The commands M-p and M-n move through this list. This is similar in functionality to the input history mechanisms provided by the LispM, Hemlock, and various fancy shells (tcsh, cmucsh, ksh,...). There is also a command, bound to C-c r, which searches backwards through the input history looking for a substring match. RMS doesn't like this mechanism. He has suggested an input history mechanism that operates by searching backwards (and forwards) through the buffer for occurrences of the prompt. The user can then resubmit the input by hitting return. I do not like this mechanism. If the prompt changes dynamically, you can miss a command. False positives are also annoying. The screen jumps around a lot as you scroll through your history. If you run a subprogram that has a null prompt (like dc), prompt search will miss all its inputs. Etc. However, you may try either of these mechanisms, and go with the style you prefer. The RMS-style prompt-search stuff is available on M-N and M-P (meta-shift-n and meta-shift-P); C-c R is bound to a command that searches for specific commands (analogous to C-c r). If you use this stuff, you will probably want to sharpen up the regular expression used to match the prompt in each mode to match your particular prompt -- the default, general regexp used in shell mode generates too many annoying false positives. (It's local variable comint-prompt-regexp -- you should set it in a hook). =============================================================================== Source code follows. Please report bugs to me: shivers@cs.cmu.edu. -Olin ------ # # type sh /afs/cs.cmu.edu/user/shivers/lib/emacs/post3.shar to unpack this archive. # echo extracting cmuscheme.el... cat >cmuscheme.el <<'!E!O!F!' ;;; cmuscheme.el -- Scheme process in a buffer. Adapted from tea.el. ;;; Copyright Olin Shivers (1988) ;;; Please imagine a long, tedious, legalistic 5-page gnu-style copyright ;;; notice appearing here to the effect that you may use this code any ;;; way you like, as long as you don't charge money for it, remove this ;;; notice, or hold me liable for its results. ;;; ;;; This is a customisation of comint-mode (see comint.el) ;;; ;;; Written by Olin Shivers (olin.shivers@cs.cmu.edu). With bits and pieces ;;; lifted from scheme.el, shell.el, clisp.el, newclisp.el, cobol.el, et al.. ;;; 8/88 ;;; ;;; Please send me bug reports, bug fixes, and extensions, so that I can ;;; merge them into the master source. ;; YOUR .EMACS FILE ;;============================================================================= ;; Some suggestions for your .emacs file. ;; ;; ; If cmuscheme lives in some non-standard directory, you must tell emacs ;; ; where to get it. This may or may not be necessary. ;; (setq load-path (cons (expand-file-name "~jones/lib/emacs") load-path)) ;; ;; ; Autoload run-scheme from file cmuscheme.el ;; (autoload 'run-scheme "cmuscheme" ;; "Run an inferior Scheme process." ;; t) ;; ;; ; Files ending in ".scm" are Scheme source, ;; ; so put their buffers in scheme-mode. ;; (setq auto-mode-alist ;; (cons '("\\.scm$" . scheme-mode) ;; auto-mode-alist)) ;; ;; ; Define C-c C-t to run my favorite command in inferior scheme mode: ;; (setq cmuscheme-load-hook ;; '((lambda () (define-key inferior-scheme-mode-map "\C-c\C-t" ;; 'favorite-cmd)))) ;;; ;;; Unfortunately, scheme.el defines run-scheme to autoload from xscheme.el. ;;; This will womp your declaration to autoload run-scheme from cmuscheme.el ;;; if you haven't loaded cmuscheme in before scheme. Two fixes: ;;; - load cmuscheme.el in your .emacs: (load-library 'cmuscheme) ;;; - change autoload declaration in scheme.el to point to cmuscheme.el: ;;; (autoload 'run-scheme "cmuscheme" "Run an inferior Scheme" t) ;;; *or* just delete the autoload declaration from scheme.el altogether, ;;; which will allow the autoload in your .emacs to have its say. (provide 'cmuscheme) (require 'scheme) (require 'comint) ;;; INFERIOR SCHEME MODE STUFF ;;;============================================================================ (defvar inferior-scheme-mode-hook nil "*Hook for customising inferior-scheme mode.") (defvar inferior-scheme-mode-map nil) (cond ((not inferior-scheme-mode-map) (setq inferior-scheme-mode-map (full-copy-sparse-keymap comint-mode-map)) (define-key scheme-mode-map "\M-\C-x" ;gnu convention 'scheme-send-definition) (define-key inferior-scheme-mode-map "\C-cl" 'scheme-load-file) (define-key inferior-scheme-mode-map "\C-ck" 'scheme-compile-file) (scheme-mode-commands inferior-scheme-mode-map))) ;; Install the process communication commands in the scheme-mode keymap. (define-key scheme-mode-map "\M-\C-x" 'scheme-send-definition);gnu convention (define-key scheme-mode-map "\C-ce" 'scheme-send-definition) (define-key scheme-mode-map "\C-c\C-e" 'scheme-send-definition-and-go) (define-key scheme-mode-map "\C-cr" 'scheme-send-region) (define-key scheme-mode-map "\C-c\C-r" 'scheme-send-region-and-go) (define-key scheme-mode-map "\C-cc" 'scheme-compile-definition) (define-key scheme-mode-map "\C-c\C-c" 'scheme-compile-definition-and-go) (define-key scheme-mode-map "\C-cz" 'switch-to-scheme) (define-key scheme-mode-map "\C-cl" 'scheme-load-file) (define-key scheme-mode-map "\C-ck" 'scheme-compile-file) ;k for "kompile" (defun inferior-scheme-mode () "Major mode for interacting with an inferior Scheme process. The following commands are available: \\{inferior-scheme-mode-map} A Scheme process can be fired up with M-x run-scheme. Customisation: Entry to this mode runs the hooks on comint-mode-hook and inferior-scheme-mode-hook (in that order). You can send text to the inferior Scheme process from other buffers containing Scheme source. switch-to-scheme switches the current buffer to the Scheme process buffer. scheme-send-definition sends the current definition to the Scheme process. scheme-compile-definition compiles the current definition. scheme-send-region sends the current region to the Scheme process. scheme-compile-region compiles the current region. scheme-send-definition-and-go, scheme-compile-definition-and-go, scheme-send-region-and-go, and scheme-compile-region-and-go switch to the Scheme process buffer after sending their text. Commands: Return after the end of the process' output sends the text from the end of process to point. Return before the end of the process' output copies the sexp ending at point to the end of the process' output, and sends it. Delete converts tabs to spaces as it moves back. Tab indents for Scheme; with argument, shifts rest of expression rigidly with the current line. C-M-q does Tab on each line starting within following expression. Paragraphs are separated only by blank lines. Semicolons start comments. If you accidentally suspend your process, use \\[comint-continue-subjob] to continue it." (interactive) (comint-mode) ;; Customise in inferior-scheme-mode-hook (setq comint-prompt-regexp "^[^>]*>+ *") ; OK for cscheme, oaklisp, T,... (scheme-mode-variables) (setq major-mode 'inferior-scheme-mode) (setq mode-name "Inferior Scheme") (setq mode-line-process '(": %s")) (use-local-map inferior-scheme-mode-map) (setq comint-input-filter (function scheme-input-filter)) (setq comint-input-sentinel (function ignore)) (setq comint-get-old-input (function scheme-get-old-input)) (run-hooks 'inferior-scheme-mode-hook)) (defun scheme-input-filter (str) "Don't save anything matching inferior-scheme-filter-regexp" (not (string-match inferior-scheme-filter-regexp str))) (defvar inferior-scheme-filter-regexp "\\`\\s *\\S ?\\S ?\\s *\\'" "*Input matching this regexp are not saved on the history list. Defaults to a regexp ignoring all inputs of 0, 1, or 2 letters.") (defun scheme-get-old-input () "Snarf the sexp ending at point" (save-excursion (let ((end (point))) (backward-sexp) (buffer-substring (point) end)))) (defun scheme-args-to-list (string) (let ((where (string-match "[ \t]" string))) (cond ((null where) (list string)) ((not (= where 0)) (cons (substring string 0 where) (scheme-args-to-list (substring string (+ 1 where) (length string))))) (t (let ((pos (string-match "[^ \t]" string))) (if (null pos) nil (scheme-args-to-list (substring string pos (length string))))))))) (defvar scheme-program-name "scheme" "*Program invoked by the scheme and run-scheme commands") (defun scheme (arg) "Like run-scheme, except prompts for a command line." (interactive "sExtra arguments to Scheme: ") (switch-to-buffer (apply 'make-comint (append (list "scheme" scheme-program-name nil) (scheme-args-to-list arg) '("-emacs")))) (inferior-scheme-mode)) (defun run-scheme (arg) "Run an inferior Scheme process, input and output via buffer *scheme*. With argument, it asks for a command line. Take the program name from the variable scheme-program-name. Runs the hooks from inferior-scheme-mode-hook \(after the comint-mode-hook is run). \(Type \\[describe-mode] in the process buffer for a list of commands.)" (interactive "P") (if arg (call-interactively 'scheme) (scheme ""))) (defun scheme-send-region (start end) "Send the current region to the inferior Scheme process." (interactive "r") (send-region "scheme" start end) (send-string "scheme" "\n")) (defun scheme-send-definition () "Send the current definition to the inferior Scheme process." (interactive) (save-excursion (end-of-defun) (let ((end (point))) (beginning-of-defun) (scheme-send-region (point) end)))) (defvar scheme-compile-exp-command "(compile '%s)" "*Template for issuing commands to compile arbitrary Scheme expressions.") (defun scheme-compile-region (start end) "Compile the current region in the inferior Scheme process \(A BEGIN is wrapped around the region: (BEGIN ))" (interactive "r") (send-string "scheme" (format scheme-compile-exp-command (format "(begin %s)" (buffer-substring start end)))) (send-string "scheme" "\n")) (defun scheme-compile-definition () "Compile the current definition in the inferior Scheme process." (interactive) (save-excursion (end-of-defun) (let ((end (point))) (beginning-of-defun) (scheme-compile-region (point) end)))) (defun switch-to-scheme (eob-p) "Switch to the *scheme* buffer. With argument, positions cursor at end of buffer." (interactive "P") (pop-to-buffer "*scheme*") (cond (eob-p (push-mark) (goto-char (point-max))))) (defun scheme-send-region-and-go (start end) "Send the current region to the inferior Scheme process, and switch to the process buffer." (interactive "r") (scheme-send-region start end) (switch-to-scheme t)) (defun scheme-send-definition-and-go () "Send the current definition to the inferior Scheme, and switch to the process buffer." (interactive) (scheme-send-definition) (switch-to-scheme t)) (defun scheme-compile-definition-and-go () "Compile the current definition in the inferior Scheme, and switch to the process buffer." (interactive) (scheme-compile-definition) (switch-to-scheme t)) (defun scheme-compile-region-and-go (start end) "Compile the current region in the inferior Scheme, and switch to the process buffer." (interactive "r") (scheme-compile-region start end) (switch-to-scheme t)) (defvar scheme-source-modes '(scheme-mode) "*Used to determine if a buffer contains Scheme source code. If it's loaded into a buffer that is in one of these major modes, it's considered a scheme source file by scheme-load-file and scheme-compile-file. Used by these commands to determine defaults.") (defvar scheme-prev-l/c-dir/file nil "Caches the (directory . file) pair used in the last scheme-load-file or scheme-compile-file command. Used for determining the default in the next one.") (defun scheme-load-file (file-name) "Load a Scheme file into the inferior Scheme process." (interactive (comint-get-source "Load Scheme file: " scheme-prev-l/c-dir/file scheme-source-modes t)) ; T because LOAD ; needs an exact name (comint-check-source file-name) ; Check to see if buffer needs saved. (setq scheme-prev-l/c-dir/file (cons (file-name-directory file-name) (file-name-nondirectory file-name))) (send-string "scheme" (concat "(load \"" file-name "\"\)\n")) (switch-to-scheme t)) (defun scheme-compile-file (file-name) "Compile a Scheme file in the inferior Scheme process." (interactive (comint-get-source "Compile Scheme file: " scheme-prev-l/c-dir/file scheme-source-modes nil)) ; NIL because COMPILE doesn't ; need an exact name. (comint-check-source file-name) ; Check to see if buffer needs saved. (setq scheme-prev-l/c-dir/file (cons (file-name-directory file-name) (file-name-nondirectory file-name))) (send-string "scheme" (concat "(compile-file \"" file-name "\"\)\n")) (switch-to-scheme t)) ;;; Do the user's customisation... (defvar cmuscheme-load-hook nil "This hook is run when cmuscheme is loaded in. This is a good place to put keybindings.") (run-hooks 'cmuscheme-load-hook) !E!O!F! # # type sh /afs/cs.cmu.edu/user/shivers/lib/emacs/post3.shar to unpack this archive. # echo extracting cmutex.el... cat >cmutex.el <<'!E!O!F!' ;; TeX mode commands. ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc. ;; ; Some suggestions for your .emacs file: ; ====================================== ; ;; Arrange for TeX-region to put it's temp file in the local directory, so ; ;; that you can invoke it on text that contains \input or \include. ; (setq TeX-directory "." ; use the local directory ; TeX-zap-file "#zap") ; and call the temp file #zap.tex ; ;; Arrange for tex m ode to autoload from cmutex.el, instead of the standard ; ;; package, tex-mode.el. ; (autoload 'tex-mode "cmutex" "Major mode for editing files of TeX or LaTeX." ; t) ; ;; If cmutex.el or comint.el reside in a non-standard directory, you ; ;; must tell emacs where to look for them. This may not be necessary. ; (setq load-path (cons (expand-file-name "/afs/user/shivers/lib/emacs") ; load-path)) ;; See notes below to if you intend to use the TeX-region command. ;; ;; Rewritten following contributions by William F. Schelter ;; and Dick King (king@kestrel). ;; Modified August 1986 by Stephen Gildea and ;; Michael Prange to add LaTeX support and enhance ;; TeX-region. ;; Added TeX-directory and reorganized somewhat gildea 21 Nov 86 ;; ;; Process stuff rewritten substantially. TeX processes are now run at ;; toplevel in a comint buffer. They are killed with the KILL signal, ;; so they die without core dumping. Comint mode provides better ;; process interaction than old shell mode. ;; - suggest you arrange for TeX-directory to be "." so that ;; \include and \input's work. See notes below. ;; - fixed TeX-region so it doesn't include the line before the header. ;; I did not fix it so that if you TeX-region the entire buffer, ;; the trailer won't get included twice (once from the buffer, and once ;; courtesy of TeX-region). TeX works in the presence of this bug, so ;; what the hell. ;; - changed TeX-buffer so it directly TeX's the file when appropriate. ;; Also added TeX-last-processed-file so that TeX-print knows who to print. ;; This is pretty winning. ;; - TeX-dvi-print-command is now a format string, with a %s where the filename ;; goes. Now you can have print commands like: "dvi-ps %s | lpr". ;; Olin Shivers (shivers@cs.cmu.edu) 2/89 ;; ;; This file is part of GNU Emacs. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY. No author or distributor ;; accepts responsibility to anyone for the consequences of using it ;; or for whether it serves any particular purpose or works at all, ;; unless he says so in writing. Refer to the GNU Emacs General Public ;; License for full details. ;; Everyone is granted permission to copy, modify and redistribute ;; GNU Emacs, but only under the conditions described in the ;; GNU Emacs General Public License. A copy of this license is ;; supposed to have been given to you along with GNU Emacs so you ;; can know your rights and responsibilities. It should be in a ;; file named COPYING. Among other things, the copyright notice ;; and this notice must be preserved on all copies. ;; Still to do: ;; Make TAB indent correctly for TeX code. Then we can make linefeed ;; do something more useful. ;; ;; Have spell understand TeX instead of assuming the entire world ;; uses nroff. ;; ;; The code for finding matching $ needs to be fixed. ;; NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE ;; NOTE ;; NOTE If you use the TeX-region command (C-c C-r) you may have problems with ;; NOTE the default setup. TeX-region creates a file in /tmp with a name like ;; NOTE /tmp/#tza0042.tex, and puts the region to be processed by TeX there. ;; NOTE IF YOUR FILE CONTAINS \input OR \include FORMS, TEX-REGION WILL BREAK. ;; NOTE If you, for example, have \input{decls} in your header, then when ;; NOTE TeX runs, it will look for decls.tex in /tmp, instead of looking ;; NOTE in the original directory your source file lives in. There isn't ;; NOTE any real clean way to fix this. A reasonable solution, if you intend ;; NOTE to use TeX-region on source that contains \input's and \include's ;; NOTE is to arrange for TeX-region to create the temp file in the local ;; NOTE directory. You can do this by putting the following form in your ;; NOTE .emacs file: ;; NOTE (setq TeX-directory "." ; use the local directory ;; NOTE TeX-zap-file "#zap") ; and call the temp file #zap.tex ;; NOTE ;; NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE (provide 'tex-mode) (defvar TeX-directory "/tmp/" "*Directory in which to run TeX subjob. Temporary files are created in this directory.") (defvar TeX-dvi-print-command "dvi-ps %s | lpr" "*Command string used by \\[TeX-print] to print a .dvi file.") (defvar TeX-last-processed-file nil "The last file that was TeX'ed by \\[TeX-region] or \\[TeX-buffer]. Used by \\[TeX-print].") (defvar TeX-show-queue-command "lpq" "*Command string used by \\[TeX-show-print-queue] to show the print queue that \\[TeX-print] put your job on.") (defvar TeX-default-mode 'plain-TeX-mode "*Mode to enter for a new file when it can't be determined whether the file is plain TeX or LaTeX or what.") (defvar TeX-command nil "The command to run TeX on a file. The name of the file will be appended to this string, separated by a space.") (defvar TeX-trailer nil "String appended after the end of a region sent to TeX by \\[TeX-region].") (defvar TeX-start-of-header nil "String used by \\[TeX-region] to delimit the start of the file's header.") (defvar TeX-end-of-header nil "String used by \\[TeX-region] to delimit the end of the file's header.") (defvar TeX-zap-file nil "Temporary file name used for text being sent as input to TeX. Should be a simple file name with no extension or directory specification.") (defvar TeX-mode-syntax-table nil "Syntax table used while in TeX mode.") (defun TeX-define-common-keys (keymap) "Define the keys that we want defined both in TeX-mode and in the TeX-shell." (define-key keymap "\C-c\C-k" 'TeX-kill-job) (define-key keymap "\C-c\C-l" 'TeX-recenter-output-buffer) (define-key keymap "\C-c\C-q" 'TeX-show-print-queue) (define-key keymap "\C-c\C-p" 'TeX-print) ) (defvar TeX-mode-map nil "Keymap for TeX mode") (if TeX-mode-map nil (setq TeX-mode-map (make-sparse-keymap)) (TeX-define-common-keys TeX-mode-map) (define-key TeX-mode-map "\"" 'TeX-insert-quote) (define-key TeX-mode-map "\n" 'TeX-terminate-paragraph) (define-key TeX-mode-map "\e}" 'up-list) (define-key TeX-mode-map "\e{" 'TeX-insert-braces) (define-key TeX-mode-map "\C-c\C-r" 'TeX-region) (define-key TeX-mode-map "\C-c\C-b" 'TeX-buffer) (define-key TeX-mode-map "\C-c\C-f" 'TeX-close-LaTeX-block) ) (defvar TeX-shell-map nil "Keymap for the TeX shell. A shell-mode-map with a few additions") ;(fset 'TeX-mode 'tex-mode) ;in loaddefs. ;;; This would be a lot simpler if we just used a regexp search, ;;; but then it would be too slow. (defun tex-mode () "Major mode for editing files of input for TeX or LaTeX. Trys to intuit whether this file is for plain TeX or LaTeX and calls plain-tex-mode or latex-mode. If it cannot be determined \(e.g., there are no commands in the file), the value of TeX-default-mode is used." (interactive) (let (mode slash comment) (save-excursion (goto-char (point-min)) (while (and (setq slash (search-forward "\\" nil t)) (setq comment (let ((search-end (point))) (save-excursion (beginning-of-line) (search-forward "%" search-end t)))))) (if (and slash (not comment)) (setq mode (if (looking-at "documentstyle") 'latex-mode 'plain-tex-mode)))) (if mode (funcall mode) (funcall TeX-default-mode)))) (fset 'plain-TeX-mode 'plain-tex-mode) (fset 'LaTeX-mode 'latex-mode) (defun plain-tex-mode () "Major mode for editing files of input for plain TeX. Makes $ and } display the characters they match. Makes \" insert `` when it seems to be the beginning of a quotation, and '' when it appears to be the end; it inserts \" only after a \\. Use \\[TeX-region] to run TeX on the current region, plus a \"header\" copied from the top of the file (containing macro definitions, etc.), running TeX in a separate window. \\[TeX-buffer] does the whole buffer. \\[TeX-print] prints the .dvi file made by either of these. Use \\[validate-TeX-buffer] to check buffer for paragraphs containing mismatched $'s or braces. Special commands: \\{TeX-mode-map} Mode variables: TeX-directory Directory in which to create temporary files for TeX jobs run by \\[TeX-region] or \\[TeX-buffer]. TeX-dvi-print-command Command string used by \\[TeX-print] to print a .dvi file. TeX-show-queue-command Command string used by \\[TeX-show-print-queue] to show the print queue that \\[TeX-print] put your job on. Entering plain-TeX mode calls the value of text-mode-hook, then the value of TeX-mode-hook, and then the value of plain-TeX-mode-hook." (interactive) (TeX-common-initialization) (setq mode-name "TeX") (setq major-mode 'plain-TeX-mode) (setq TeX-command "tex") (setq TeX-start-of-header "%**start of header") (setq TeX-end-of-header "%**end of header") (setq TeX-trailer "\\bye\n") (run-hooks 'text-mode-hook 'TeX-mode-hook 'plain-TeX-mode-hook)) (defun latex-mode () "Major mode for editing files of input for LaTeX. Makes $ and } display the characters they match. Makes \" insert `` when it seems to be the beginning of a quotation, and '' when it appears to be the end; it inserts \" only after a \\. Use \\[TeX-region] to run LaTeX on the current region, plus the preamble copied from the top of the file (containing \\documentstyle, etc.), running LaTeX under a special subshell. \\[TeX-buffer] does the whole buffer. \\[TeX-print] prints the .dvi file made by either of these. Use \\[validate-TeX-buffer] to check buffer for paragraphs containing mismatched $'s or braces. Special commands: \\{TeX-mode-map} Mode variables: TeX-directory Directory in which to create temporary files for TeX jobs run by \\[TeX-region] or \\[TeX-buffer]. TeX-dvi-print-command Command string used by \\[TeX-print] to print a .dvi file. TeX-show-queue-command Command string used by \\[TeX-show-print-queue] to show the print queue that \\[TeX-print] put your job on. Entering LaTeX mode calls the value of text-mode-hook, then the value of TeX-mode-hook, and then the value of LaTeX-mode-hook." (interactive) (TeX-common-initialization) (setq mode-name "LaTeX") (setq major-mode 'LaTeX-mode) (setq TeX-command "latex") (setq TeX-start-of-header "\\documentstyle") (setq TeX-end-of-header "\\begin{document}") (setq TeX-trailer "\\end{document}\n") (run-hooks 'text-mode-hook 'TeX-mode-hook 'LaTeX-mode-hook)) (defun TeX-common-initialization () (kill-all-local-variables) (use-local-map TeX-mode-map) (setq local-abbrev-table text-mode-abbrev-table) (if (null TeX-mode-syntax-table) (progn (setq TeX-mode-syntax-table (make-syntax-table)) (set-syntax-table TeX-mode-syntax-table) (modify-syntax-entry ?\\ ".") (modify-syntax-entry ?\f ">") (modify-syntax-entry ?\n ">") (modify-syntax-entry ?$ "$$") (modify-syntax-entry ?% "<") (modify-syntax-entry ?\" ".") (modify-syntax-entry ?& ".") (modify-syntax-entry ?_ ".") (modify-syntax-entry ?@ "_") (modify-syntax-entry ?~ " ") (modify-syntax-entry ?' "w")) (set-syntax-table TeX-mode-syntax-table)) (make-local-variable 'paragraph-start) (setq paragraph-start "^[ \t]*$\\|^[\f\\\\]") (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) (make-local-variable 'comment-start) (setq comment-start "%") (make-local-variable 'comment-start-skip) (setq comment-start-skip "[^\\]\\(\\(\\\\\\\\\\)*\\)%+ *") (make-local-variable 'comment-indent-hook) (setq comment-indent-hook 'TeX-comment-indent) (make-local-variable 'TeX-command) (make-local-variable 'TeX-start-of-header) (make-local-variable 'TeX-end-of-header) (make-local-variable 'TeX-trailer)) (defun TeX-comment-indent () (if (looking-at "%%%") (current-column) (skip-chars-backward " \t") (max (if (bolp) 0 (1+ (current-column))) comment-column))) (defun TeX-insert-quote (arg) "Insert ``, '' or \" according to preceding character. With prefix argument, always insert \" characters." (interactive "P") (if arg (let ((count (prefix-numeric-value arg))) (if (listp arg) (self-insert-command 1) ;C-u always inserts just one (self-insert-command count))) (insert (cond ((or (bobp) (save-excursion (forward-char -1) (looking-at "[ \t\n]\\|\\s("))) "``") ((= (preceding-char) ?\\) ?\") (t "''"))))) (defun validate-TeX-buffer () "Check current buffer for paragraphs containing mismatched $'s. As each such paragraph is found, a mark is pushed at its beginning, and the location is displayed for a few seconds." (interactive) (let ((opoint (point))) (goto-char (point-max)) ;; Does not use save-excursion ;; because we do not want to save the mark. (unwind-protect (while (and (not (input-pending-p)) (not (bobp))) (let ((end (point))) (search-backward "\n\n" nil 'move) (or (TeX-validate-paragraph (point) end) (progn (push-mark (point)) (message "Mismatch found in pararaph starting here") (sit-for 4))))) (goto-char opoint)))) (defun TeX-validate-paragraph (start end) (condition-case () (save-excursion (save-restriction (narrow-to-region start end) (goto-char start) (forward-sexp (- end start)) t)) (error nil))) (defun TeX-terminate-paragraph (inhibit-validation) "Insert two newlines, breaking a paragraph for TeX. Check for mismatched braces/$'s in paragraph being terminated. A prefix arg inhibits the checking." (interactive "P") (or inhibit-validation (TeX-validate-paragraph (save-excursion (search-backward "\n\n" nil 'move) (point)) (point)) (message "Paragraph being closed appears to contain a mismatch")) (insert "\n\n")) (defun TeX-insert-braces () "Make a pair of braces and be poised to type inside of them." (interactive) (insert ?\{) (save-excursion (insert ?}))) ;;; Like TeX-insert-braces, but for LaTeX. (defun TeX-close-LaTeX-block () "Creates an \\end{...} to match \\begin{...} on the current line and puts point on the blank line between them." (interactive "*") (let ((fail-point (point))) (end-of-line) (if (re-search-backward "\\\\begin{\\([^}\n]*\\)}" (save-excursion (beginning-of-line) (point)) t) (let ((text (buffer-substring (match-beginning 1) (match-end 1))) (indentation (current-column))) (end-of-line) (delete-horizontal-space) (insert "\n\n") (indent-to indentation) (insert "\\end{" text "}") (forward-line -1)) (goto-char fail-point) (ding)))) ;;; Invoking TeX in an inferior shell. ;;; The utility functions: (defun TeX-make-process-buffer () (require 'comint) (save-excursion (set-buffer (get-buffer-create "*TeX-shell*")) (comint-mode) (setq TeX-shell-map (full-copy-sparse-keymap comint-mode-map)) (TeX-define-common-keys TeX-shell-map) (use-local-map TeX-shell-map))) (defun set-buffer-directory (buffer directory) "Set BUFFER's default directory to be DIRECTORY." (setq directory (file-name-as-directory (expand-file-name directory))) (if (not (file-directory-p directory)) (error "%s is not a directory" directory) (save-excursion (set-buffer buffer) (setq default-directory directory)))) ;;; The commands: ;;; It's a kludge that we have to create a special buffer just ;;; to write out the TeX-trailer. It would nice if there were a ;;; function like write-region that would write literal strings. ;;; Changed a (forward-line -1) that was causing an extra ;;; line to be included in the header to a (beginning-of-line). Olin 1/89 (defun TeX-region (beg end) "Run TeX on the current region. A temporary file (TeX-zap-file) is written in directory TeX-directory, and TeX is run in that directory. If the buffer has a header, it is written to the temporary file before the region itself. The buffer's header is all lines between the strings defined by TeX-start-of-header and TeX-end-of-header inclusive. The header must start in the first 100 lines. The value of TeX-trailer is appended to the temporary file after the region." (interactive "r") (or TeX-zap-file (setq TeX-zap-file (make-temp-name "#tz"))) (let* ((temp-buffer (get-buffer-create " TeX-Output-Buffer")) (zap-directory (file-name-as-directory (expand-file-name TeX-directory))) (tex-out-file (concat TeX-zap-file ".tex")) ; Looks nicer (full-tex-out-file (expand-file-name tex-out-file zap-directory))) (save-excursion (save-restriction (widen) (goto-char (point-min)) (forward-line 100) (let ((search-end (point)) (hbeg (point-min)) (hend (point-min))) (goto-char (point-min)) ;; Initialize the temp file with either the header or nothing (if (search-forward TeX-start-of-header search-end t) (progn (beginning-of-line) (setq hbeg (point)) ;mark beginning of header (if (search-forward TeX-end-of-header nil t) (progn (forward-line 1) (setq hend (point))) ;mark end of header (setq hbeg (point-min))))) ;no header (write-region (min hbeg beg) hend full-tex-out-file nil nil) (write-region (max beg hend) end full-tex-out-file t nil)) (let ((local-tex-trailer TeX-trailer)) (set-buffer temp-buffer) (erase-buffer) ;; make sure trailer isn't hidden by a comment (insert-string "\n") (if local-tex-trailer (insert-string local-tex-trailer)) (write-region (point-min) (point-max) full-tex-out-file t nil)))) (TeX-process-file zap-directory tex-out-file))) ;;; Altered so that TeX is run directly on the file, if the buffer ;;; is visiting a file and unmodified. Olin 1/89 (defun TeX-buffer () "Run TeX on current buffer. If buffer is a file buffer, and modified, first offers to save buffer. Afterwards, if buffer is a file buffer and unmodified, runs TeX directly on file. Otherwise, calls TeX-region on whole buffer." (interactive) (let ((fname (buffer-file-name))) ;; Offer to save buffer if a modified file buffer. (if (and fname (buffer-modified-p) (y-or-n-p (format "Save buffer %s first? " (buffer-name)))) (save-buffer)) (if (and fname (not (buffer-modified-p))) ;; If unmodified file buffer, then tex it directly. (TeX-process-file (file-name-directory fname) (file-name-nondirectory fname)) ; looks nicer ;; otherwise, just Tex-region the whole buffer. (TeX-region (point-min) (point-max))))) ;; New auxiliary function. (defun TeX-process-file (dir fname) "Fires up a TeX process, working directory DIR, on file FNAME." (if (get-buffer "*TeX-shell*") (let ((old-proc (get-buffer-process "*TeX-shell*"))) (if (and old-proc (memq (process-status old-proc) '(run stop))) (message "Killing old TeX process %s..." (process-name old-proc)))) (TeX-make-process-buffer)) (set-buffer-directory "*TeX-shell*" dir) (TeX-recenter-output-buffer 0) (save-excursion (let ((command TeX-command)) ; TeX-command is buffer local. (set-buffer "*TeX-shell*") (goto-char (point-max)) (insert (format "\n--- Running process: %s %s\n--- working directory %s\n" command fname dir)))) (comint-exec "*TeX-shell*" "TeX-shell" TeX-command nil (list fname)) (setq TeX-last-processed-file (expand-file-name fname dir))) (defun TeX-kill-job () "Kill the currently running TeX job." (interactive) (kill-process "TeX-shell" t)) ; no mercy. no coredump. (defun TeX-recenter-output-buffer (linenum) "Redisplay buffer of TeX job output so that most recent output can be seen. The last line of the buffer is displayed on line LINE of the window, or centered if LINE is nil." (interactive "P") (let ((tex-shell (get-buffer "*TeX-shell*")) (old-buffer (current-buffer))) (if (null tex-shell) (message "No TeX output buffer") (pop-to-buffer tex-shell) (bury-buffer tex-shell) ; WHAT IS THE POINT OF THIS LINE??? Olin (goto-char (point-max)) (recenter (if linenum (prefix-numeric-value linenum) (/ (window-height) 2))) (pop-to-buffer old-buffer) ))) (defun TeX-print () "Print the .dvi file made by \\[TeX-region] or \\[TeX-buffer]. Runs the shell command defined by TeX-dvi-print-command." (interactive) (if (stringp TeX-last-processed-file) (let ((dir (file-name-directory TeX-last-processed-file)) (fname (file-name-nondirectory TeX-last-processed-file))) (if (string-match "\\(^.*\\.\\)[^.]*$" fname) ; Strip off extension (let* ((noext (substring fname 0 (match-end 1))) ; foo.tex ==> foo. (cmd (format TeX-dvi-print-command (concat "\"" dir noext "dvi\"")))) (message cmd) (shell-command cmd)) (error "Can't figure out name of dvi file"))) (error "No last file processed."))) (defun TeX-show-print-queue () "Show the print queue that \\[TeX-print] put your job on. Runs the shell command defined by TeX-show-queue-command." (interactive) (shell-command TeX-show-queue-command)) !E!O!F! # # type sh /afs/cs.cmu.edu/user/shivers/lib/emacs/post3.shar to unpack this archive. # echo extracting tea.el... cat >tea.el <<'!E!O!F!' ;;; tea.el -- Teach emacs about T. ;;; Copyright Olin Shivers (1988) ;;; Please imagine a long, tedious, legalistic 5-page gnu-style copyright ;;; notice appearing here to the effect that you may use this code any ;;; way you like, as long as you don't charge money for it, remove this ;;; notice, or hold me liable for its results. ;;; ;;; 1. Major mode for editing T source: t-mode ;;; This is just a variant of scheme-mode, tweaked for T. ;;; 2. Major mode for running T in a buffer: run-tea ;;; This is a customisation of comint-mode. ;;; ;;; Written by Olin Shivers (olin.shivers@cs.cmu.edu). With bits and pieces ;;; lifted from scheme.el, shell.el, clisp.el, newclisp.el, cobol.el, et al.. ;;; 8/88 ;;; Please send me bug reports, bug fixes, and extensions, so that I can ;;; merge them into the master source. ;;; ;; YOUR .EMACS FILE ;;============================================================================= ;; Some suggestions for your .emacs file. ;; ;; ; If tea.el lives in some non-standard directory, you must tell emacs ;; ; where to get it. This may or may not be necessary. ;; (setq load-path (cons (expand-file-name "~jones/lib/emacs") load-path)) ;; ;; ; Autoload run-tea and t-mode from file tea.el ;; (autoload 'run-tea "tea" ;; "Run an inferior T process." ;; t) ;; ;; (autoload 't-mode "tea" ;; "Major mode for editing T source. Just Scheme mode, tuned a bit." ;; t) ;; ;; ; Files ending in ".t" are T source, so put their buffers in t-mode. ;; (setq auto-mode-alist ;; (cons '("\\.t$" . t-mode) ;; auto-mode-alist)) ;; ;; ; Define C-c C-t to run my favorite command in inferior T mode: ;; (setq tea-load-hook ;; '((lambda () (define-key inferior-t-mode-map "\C-c\C-t" ;; 'favorite-cmd)))) ;; ETAGS ;;============================================================================= ;; A suggestion for modifying the etags program so that it knows about T. ;; You should modify the few lines that allow etags to conclude that ;; files that end with ".t" are lisp or scheme source code. ;; Find a line that looks like ;; /* .scm or .sm or .scheme implies scheme source code */ ;; and add a ;; !strcmp (cp + 1, "t") || ;; suffix check to the following clauses that check filename suffixes. ;; This is already done for some versions of etags. Have a look, or try it ;; & see. (setq scheme-mit-dialect nil) ; Give me a break. (require 'scheme) (require 'cmushell) ;;; T mode stuff ;;;============================================================================ ;;; Note: T mode alters the scheme-mode syntax table and indentation ;;; hooks slightly. If you were using scheme-mode and t-mode simultaneously ;;; this might be a problem, except that the alterations are fairly ;;; innocuous. ;; This adds [] and {} as matching delimiters. So emacs will treat #[Char 0] ;; or #{Procedure 1 ADD} as an s-exp with a quote sign in front. (modify-syntax-entry ?[ "(]" scheme-mode-syntax-table) (modify-syntax-entry ?] ")[" scheme-mode-syntax-table) (modify-syntax-entry ?{ "(}" scheme-mode-syntax-table) (modify-syntax-entry ?} "){" scheme-mode-syntax-table) ;; Modify scheme-indent-hook for T. (put 'labels 'scheme-indent-hook 1) (put 'block 'scheme-indent-hook 0) (put 'block0 'scheme-indent-hook 0) (put 'object 'scheme-indent-hook 1) (put 'lset 'scheme-indent-hook 1) (put 'xcase 'scheme-indent-hook 1) (put 'select 'scheme-indent-hook 1) (put 'xselect 'scheme-indent-hook 1) (put 'iterate 'scheme-indent-hook 2) (put 'cond 'scheme-indent-hook 0) (put 'xcond 'scheme-indent-hook 0) (put 'catch 'scheme-indent-hook 1) (put 'bind 'scheme-indent-hook 1) (put 'define-operation 'scheme-indent-hook 1) (put 'operation 'scheme-indent-hook 1) (put 'object 'scheme-indent-hook 1) (put 'join 'scheme-indent-hook 0) (put 'destructure 'scheme-indent-hook 1) (put 'destructure* 'scheme-indent-hook 1) (put 'define-integrable 'scheme-indent-hook 1) (put 'define-constant 'scheme-indent-hook 1) (put 'define-syntax 'scheme-indent-hook 1) (put 'let-syntax 'scheme-indent-hook 1) (put 'define-local-syntax 'scheme-indent-hook 1) (put 'macro-expander 'scheme-indent-hook 1) (put 'with-open-streams 'scheme-indent-hook 1) (put 'with-open-ports 'scheme-indent-hook 1) (put 'with-input-from-string 'scheme-indent-hook 1) (put 'with-output-to-string 'scheme-indent-hook 1) (put 'with-output-width-string 'scheme-indent-hook 1) (put 'receive 'scheme-indent-hook 1) (put 'receive-values 'scheme-indent-hook 1) (defvar t-mode-hook nil "*Hook for customising T mode") (defvar t-mode-map (full-copy-sparse-keymap scheme-mode-map)) (defun t-mode () "Major mode for editing T code. This is Scheme mode, slightly tuned for T. Editing commands are similar to those of Lisp mode. In addition, if an inferior T process is running, some additional commands will be defined, for evaluating expressions and controlling the interpreter, and the state of the process will be displayed in the modeline of all T buffers. The names of commands that interact with the T process start with \"tea-\". For more information see the documentation for inferior-t-mode. Commands: Delete converts tabs to spaces as it moves back. Blank lines separate paragraphs. Semicolons start comments. \\{t-mode-map} Customisation: Entry to this mode runs the hooks on t-mode-hook" (interactive) (kill-all-local-variables) (use-local-map t-mode-map) (scheme-mode-variables) (setq major-mode 't-mode) (setq mode-name "T") (run-hooks 't-mode-hook)) ;;; INFERIOR T MODE STUFF ;;;============================================================================ (defvar inferior-t-mode-map nil) (cond ((not inferior-t-mode-map) (setq inferior-t-mode-map (full-copy-sparse-keymap comint-mode-map)) (scheme-mode-commands inferior-t-mode-map) (define-key inferior-t-mode-map "\C-cl" 'tea-load-file) (define-key inferior-t-mode-map "\C-ck" 'tea-compile-file) ;"kompile" )) ;; Install the process communication commands in the scheme-mode keymap. (define-key t-mode-map "\M-\C-x" 'tea-send-definition) ; gnu convention (define-key t-mode-map "\C-ce" 'tea-send-definition) (define-key t-mode-map "\C-c\C-e" 'tea-send-definition-and-go) (define-key t-mode-map "\C-cr" 'tea-send-region) (define-key t-mode-map "\C-c\C-r" 'tea-send-region-and-go) (define-key t-mode-map "\C-cc" 'tea-compile-definition) (define-key t-mode-map "\C-c\C-c" 'tea-compile-definition-and-go) (define-key t-mode-map "\C-cz" 'switch-to-tea) (define-key t-mode-map "\C-cl" 'tea-load-file) (define-key t-mode-map "\C-ck" 'tea-compile-file) (defvar inferior-t-mode-hook nil "*Hook for customising inferior-T mode") (defun inferior-t-mode () "Major mode for interacting with an inferior T process. The following commands are available: \\{inferior-t-mode-map} A T process can be fired up with M-x run-tea. Customisation: Entry to this mode runs the hooks on comint-mode-hook and inferior-t-mode-hook (in that order). You can send text to the inferior T process from other buffers containing T source. switch-to-tea switches the current buffer to the T process buffer. tea-send-definition sends the current definition to the T process. tea-compile-definition compiles the current definition. tea-send-region sends the current region to the T process. tea-compile-region compiles the current region. tea-send-definition-and-go, tea-compile-definition-and-go, tea-send-region-and-go, and tea-compile-region-and-go switch to the T process buffer after sending their text. Commands: Return after the end of the process' output sends the text from the end of process to point. Return before the end of the process' output copies the sexp ending at point to the end of the process' output, and sends it. Delete converts tabs to spaces as it moves back. Tab indents for T; with argument, shifts rest of expression rigidly with the current line. C-M-q does Tab on each line starting within following expression. Paragraphs are separated only by blank lines. Semicolons start comments. If you accidentally suspend your process, use \\[comint-continue-subjob] to continue it." (interactive) (comint-mode) (setq comint-prompt-regexp "^>+ *") ; Customise in inferior-t-mode-hook (scheme-mode-variables) (setq major-mode 'inferior-t-mode) (setq mode-name "Inferior T") (setq mode-line-process '(": %s")) (use-local-map inferior-t-mode-map) (setq comint-input-filter 'tea-input-filter) (setq comint-input-sentinel 'ignore) (setq comint-get-old-input 'tea-get-old-input) (run-hooks 'inferior-t-mode-hook)) (defun tea-input-filter (str) "Don't save anything matching tea-filter-regexp" (not (string-match tea-filter-regexp str))) (defvar tea-filter-regexp "\\`\\s *\\S ?\\S ?\\s *\\'" "*Input matching this regexp are not saved on the history list. Defaults to a regexp ignoring all inputs of 0, 1, or 2 letters.") (defun tea-get-old-input () "Snarf the sexp ending at point" (save-excursion (let ((end (point))) (backward-sexp) (buffer-substring (point) end)))) (defun tea-args-to-list (string) (let ((where (string-match "[ \t]" string))) (cond ((null where) (list string)) ((not (= where 0)) (cons (substring string 0 where) (tea-args-to-list (substring string (+ 1 where) (length string))))) (t (let ((pos (string-match "[^ \t]" string))) (if (null pos) nil (tea-args-to-list (substring string pos (length string))))))))) (defvar tea-program-name "t" "*Program invoked by the tea and run-tea commands") (defun tea (arg) "Like run-tea, except prompts for a command line." (interactive "sExtra arguments to tea: ") (switch-to-buffer (apply 'make-comint (append (list "tea" tea-program-name nil) (tea-args-to-list arg) '("-emacs")))) (inferior-t-mode)) (defun run-tea (arg) "Run an inferior T process, input and output via buffer *tea*. With argument, it asks for a command line. Take the program name from the variable tea-program-name. Runs the hooks from inferior-t-mode-hook (after the comint-mode-hook is run). \(Type \\[describe-mode] in the process buffer for a list of commands.)" (interactive "P") (if arg (call-interactively 'tea) (tea ""))) (defun tea-send-region (start end) "Send the current region to the inferior T process" (interactive "r") (send-region "tea" start end) (send-string "tea" "\n")) (defun tea-send-definition () "Send the current definition to the inferior T process." (interactive) (save-excursion (end-of-defun) (let ((end (point))) (beginning-of-defun) (tea-send-region (point) end)))) (defun tea-compile-region (start end) "Compile the current region in the inferior T process. \(A BLOCK is wrapped around the region: (BLOCK )" (interactive "r") (send-string "tea" "(orbit '(block ") (send-region "tea" start end) (send-string "tea" "))\n")) (defun tea-compile-definition () "Compile the current definition in the inferior T process." (interactive) (save-excursion (end-of-defun) (let ((end (point))) (beginning-of-defun) (tea-compile-region (point) end)))) (defun switch-to-tea (eob-p) "Switch to the *tea* buffer. With argument, positions cursor at end of buffer." (interactive "P") (pop-to-buffer "*tea*") (cond (eob-p (push-mark) (goto-char (point-max))))) (defun tea-send-region-and-go (start end) "Send the current region to the inferior T process, and switch to the process buffer." (interactive "r") (tea-send-region start end) (switch-to-tea t)) (defun tea-send-definition-and-go () "Send the current definition to the inferior T process, and switch to the process buffer." (interactive) (tea-send-definition) (switch-to-tea t)) (defun tea-compile-region-and-go (start end) "Compile the current region in the inferior T process, and switch to process buffer." (interactive "r") (tea-compile-region start end) (switch-to-tea t)) (defun tea-compile-definition-and-go () "Compile the current definition in the inferior T process, and switch to process buffer." (interactive) (tea-compile-definition) (switch-to-tea t)) (defvar tea-source-modes '(t-mode) "*Used to determine if a buffer contains T source code. If it's loaded into a buffer that is in one of these major modes, it's considered a T source file by tea-load-file and tea-compile-file. Used by these commands to determine defaults.") (defvar tea-prev-l/c-dir/file nil "Caches the (directory . file) pair used in the last tea-load-file or tea-compile-file command. Used for determining the default in the next one.") (defun tea-load-file (file-name) "Load a T file into the inferior T process." (interactive (comint-get-source "Load T file: " tea-prev-l/c-dir/file tea-source-modes t)) ; T because LOAD needs ; an exact name. (comint-check-source file-name) ; Check to see if buffer needs saved. (setq tea-prev-l/c-dir/file (cons (file-name-directory file-name) (file-name-nondirectory file-name))) (send-string "tea" (concat "(load \"" file-name "\"\)\n")) (switch-to-tea t)) (defun tea-compile-file (file-name) "Compile a T file in the inferior T process." (interactive (comint-get-source "Compile T file: " tea-prev-l/c-dir/file tea-source-modes nil)) ; NIL because COMPILE doesn't ; need an exact name. (comint-check-source file-name) ; Check to see if buffer needs saved. (setq tea-prev-l/c-dir/file (cons (file-name-directory file-name) (file-name-nondirectory file-name))) (send-string "tea" (concat "(compile-file \"" file-name "\"\)\n")) (switch-to-tea t)) ;;; Do the user's customisation... (defvar tea-load-hook nil "This hook is run when tea is loaded in. This is a good place to put keybindings.") (run-hooks 'tea-load-hook) !E!O!F! # # type sh /afs/cs.cmu.edu/user/shivers/lib/emacs/post3.shar to unpack this archive. # echo extracting tea2.el... cat >tea2.el <<'!E!O!F!' ;;; -*-Emacs-Lisp-*- Tea mode ;;; Copyright Olin Shivers (1988) ;;; Please imagine a long, tedious, legalistic 5-page gnu-style copyright ;;; notice appearing here to the effect that you may use this code any ;;; way you like, as long as you don't charge money for it, remove this ;;; notice, or hold me liable for its results. ;;; Written by Olin Shivers (shivers@cs.cmu.edu) 10/88. ;;; Please send me bug reports, bug fixes, and extensions, so that I can ;;; merge them into the master source. ;;; This file tunes scheme and inferior-scheme modes for T. ;;; This is a fairly simple operation, and consists of: ;;; 1. Adding T-MODE to the list of modes that are recognised by ;;; scheme-load-file and scheme-compile-file as marking source files. ;;; 2. Changing the scheme-compile-exp-command string to ;;; "(orbit '%s)" ;;; 3. Tweaking the scheme syntax table just a bit. ;;; 5. Specifying indentation information for a few T specific special forms, ;;; and turning off the scheme-mit-dialect flag. ;;; 3. Having commands TEA and RUN-TEA that are just like SCHEME and ;;; RUN-SCHEME except that (a) that the name of the program to run isn't ;;; taken from the variable SCHEME-PROGRAM-NAME, it's taken from ;;; TEA-PROGRAM-NAME, and (b) the mode hook isn't INFERIOR-SCHEME-MODE-HOOK ;;; but INFERIOR-T-MODE-HOOK. ;;; 4. Having a mode T-MODE, that is exactly equal to SCHEME-MODE, except ;;; that the hooks from T-MODE-HOOK are run instead of SCHEME-MODE-HOOK. ;;; This is the minimal-delta approach to a T mode: we just mutate Scheme ;;; mode. Note, for example, that there is no "inferior-t mode." ;;; This means you can run exactly *one* scheme and/or T ;;; process at a time; you *can't* run a scheme process *and* a T process. ;;; I don't think this is a problem. ;;; This stuff uses the scheme-in-a-buffer stuff defined in cmuscheme.el and ;;; comint.el; the commands provided are extensively documented in the ;;; source text for these files. ;; YOUR .EMACS FILE ;;============================================================================= ;; Some suggestions for your .emacs file. ;; ;; ; If tea.el lives in some non-standard directory, you must tell emacs ;; ; where to get it. This may or may not be necessary. ;; (setq load-path (cons (expand-file-name "~jones/lib/emacs") load-path)) ;; ;; ; Autoload run-tea and t-mode from file tea.el ;; (autoload 'run-tea "tea" ;; "Run an inferior T process." ;; t) ;; ;; (autoload 't-mode "tea" ;; "Major mode for editing T source. Just Scheme mode, tuned a bit." ;; t) ;; ;; ; Files ending in ".t" are T source, so put their buffers in t-mode. ;; (setq auto-mode-alist ;; (cons '("\\.t$" . t-mode) ;; auto-mode-alist)) ;; ;; ; Define C-c C-t to run my favorite command in inferior Scheme mode: ;; (setq tea-load-hook ;; '((lambda () (define-key inferior-scheme-mode-map "\C-c\C-t" ;; 'favorite-cmd)))) ;; ETAGS ;;============================================================================= ;; A suggestion for modifying the etags program so that it knows about T. ;; You should modify the few lines that allow etags to conclude that ;; files that end with ".t" are lisp or scheme source code. ;; Find a line that looks like ;; /* .scm or .sm or .scheme implies scheme source code */ ;; and add a ;; !strcmp (cp + 1, "t") || ;; suffix check to the following clauses that check filename suffixes. ;; This is already done for some versions of etags. Have a look, or try it ;; & see. (require 'cmuscheme) ; For inferior-scheme mode (provide 'tea) ; File buffers in t-mode contain scheme source (if (not (memq 't-mode scheme-source-modes)) (setq scheme-source-modes (cons 't-mode scheme-source-modes))) (setq scheme-compile-exp-command "(orbit '%s)") ;; This adds [] and {} as matching delimiters. So emacs will treat #[Char 0] ;; or #{Procedure 1 ADD} as an s-exp with a quote sign in front. (modify-syntax-entry ?[ "(]" scheme-mode-syntax-table) (modify-syntax-entry ?] ")[" scheme-mode-syntax-table) (modify-syntax-entry ?{ "(}" scheme-mode-syntax-table) (modify-syntax-entry ?} "){" scheme-mode-syntax-table) ;; Modify indenting for T. (setq scheme-mit-dialect nil) ; Give me a break. (put 'labels 'scheme-indent-hook 1) (put 'block 'scheme-indent-hook 0) (put 'block0 'scheme-indent-hook 0) (put 'object 'scheme-indent-hook 1) (put 'lset 'scheme-indent-hook 1) (put 'xcase 'scheme-indent-hook 1) (put 'select 'scheme-indent-hook 1) (put 'xselect 'scheme-indent-hook 1) (put 'iterate 'scheme-indent-hook 2) (put 'cond 'scheme-indent-hook 0) (put 'xcond 'scheme-indent-hook 0) (put 'catch 'scheme-indent-hook 1) (put 'bind 'scheme-indent-hook 1) (put 'define-operation 'scheme-indent-hook 1) (put 'operation 'scheme-indent-hook 1) (put 'object 'scheme-indent-hook 1) (put 'join 'scheme-indent-hook 0) (put 'destructure 'scheme-indent-hook 1) (put 'destructure* 'scheme-indent-hook 1) (put 'define-integrable 'scheme-indent-hook 1) (put 'define-constant 'scheme-indent-hook 1) (put 'define-syntax 'scheme-indent-hook 1) (put 'let-syntax 'scheme-indent-hook 1) (put 'define-local-syntax 'scheme-indent-hook 1) (put 'macro-expander 'scheme-indent-hook 1) (put 'with-open-streams 'scheme-indent-hook 1) (put 'with-open-ports 'scheme-indent-hook 1) (put 'with-input-from-string 'scheme-indent-hook 1) (put 'with-output-to-string 'scheme-indent-hook 1) (put 'with-output-width-string 'scheme-indent-hook 1) (put 'receive 'scheme-indent-hook 1) (put 'receive-values 'scheme-indent-hook 1) (defvar tea-program-name "t" "*Name of the T program to run when RUN-TEA is called.") (defun run-tea (arg) "Run an inferior T process, input and output via buffer *scheme*. With argument, it asks for a command line. Take the program name from the variable tea-program-name. Runs the hooks from inferior-t-hook (after comint-mode-hook is run). \(Type \\[describe-mode] in the process buffer for a list of commands.)" (interactive "P") (if arg (call-interactively 'tea) (tea ""))) (defun tea (arg) "Like run-tea, except prompts for a command line." (interactive "sExtra arguments to tea: ") (let ((scheme-program-name tea-program-name) ; Lexical scope loses! (inferior-scheme-mode-hook (function (lambda (); Dynamic binding rules! (run-hooks 'inferior-t-mode-hook))))) (scheme arg))) (defvar inferior-t-mode-hook nil "*Hook for customising inferior-scheme mode when invoked via run-tea or tea") (defun t-mode () "Major mode for editing T code. Basically, it's just scheme mode, except for the entry hook. Commands: Delete converts tabs to spaces as it moves back. Blank lines separate paragraphs. Semicolons start comments. \\{scheme-mode-map} Entry to this mode runs the hooks on t-mode-hook. If you accidentally suspend your process, use \\[comint-continue-subjob] to continue it." (interactive) (kill-all-local-variables) (use-local-map scheme-mode-map) (setq major-mode 't-mode) (setq mode-name "T") (scheme-mode-variables) (run-hooks t-mode-hook)) (defvar t-mode-hook nil "*Hook for customising T mode.") ;;; Do the user's customisation... (defvar tea-load-hook nil "This hook is run when tea is loaded in. This is a good place to put keybindings.") (run-hooks 'tea-load-hook) !E!O!F! --