Franz Inc. GNU Emacs/Common Lisp Interface Release 1.3 This document is a specification of the Franz Inc. GNU Emacs interface to Common Lisp, which is written entirely in GNU Emacs Lisp (for GNU Emacs version 18.50). 0. Concepts and Terminology In Emacs, each buffer has a `mode.' A mode is a collection of key and variable `bindings' which are specialized to a certain task. When the cursor is in a `buffer' and you depress a key, its action is determined by the binding found in the `keymap' associated with that buffer (the buffer-local keymap). If there is no binding in the buffer-local keymap, then the binding is sought on the `global' keymap. Thus, a mode is usually implemented by creating a buffer-local keymap and adding bindings to do specific tasks. The result is that certain keys act differently in the buffer but most keys act just as they do in all the other buffers. Usually the mode of a buffer is displayed in parentheses at the bottom of the screen (in what is called the `mode line'). Two terms used interchangeably in this document are `subprocess' and `inferior process'. They both refer to the interaction between Emacs and running program, and their names come from the fact that UNIX processes are part of a hierarchical structure--each process has a parent and some processes have children. Here, Lisp is run as a child of Emacs, or a subordinate process under Emacs. Most machines available today have a `network' interface. There are several `protocols' in use today, of which `TCP/IP' (Transmission Control Protocol) is one. TCP/IP is most commonly used for communication between machines using `ethernet'--ethernet is the hardware and TCP/IP is the software. TCP/IP is available on Berkeley UNIX and some other UNIX systems, and is a powerful tool for making resources from a large number of machines easily available to all users on the network. The X window system, for example, uses TCP/IP to communicate between clients and server. In order for Emacs and Lisp to communicate, Lisp must accept messages sent to a certain address and Emacs must know that address. There are two types of addressing available: internet and UNIX domain. An internet address is a machine address and a port number. A UNIX domain address is a file name. The advantage of an internet address is that it can be accessed from any machine on the network because the address contains the machine number. The disadvantage is that only one process (a Lisp process in our case) on a given machine can listen for messages on a given internet address. Thus, if you wanted to use the Emacs to Lisp interface on a machine with many users, only one user at a time could use it. A UNIX domain address can only be used from programs running on the same machine. However the flexibility of using file names in UNIX domain addresses allows the Emacs to Lisp interface to choose unique addresses for each user running on a machine. The file name convention we use is this: when user `smith' starts up Lisp, the UNIX domain address `~smith/.excl_to_emacs' is used by Lisp. When `smith' directs Emacs to connect to Lisp, it knows it was started by smith and thus talks to address `~smith/.excl_to_emacs'. Thus multiple users on a given machine can run the Emacs to Lisp interface. The Emacs/Lisp interface in this document can use both of these methods of communication, but the preferred method uses UNIX domain sockets, because more than one person on a machine may use the Lisp/Emacs interface. 1. Introduction The purpose of this package is to enhance the Lisp environment. To this end, GNU Emacs and Lisp have been tightly coupled, and in the case of Allegro CL 3.0 the interface uses TCP/IP UNIX or internet domain sockets. This interface can be broken down into three modes: * Common Lisp, * Inferior Common Lisp, and * TCP Common Lisp. The first is for editing Lisp programs, the second for starting up a Lisp subprocess under Emacs, and the third for TCP/IP communication between Emacs and Lisp. While editing Lisp source code, there are commands that make it easy to send expressions to, and receive information from, a Lisp process. For example: a function can be sent to Lisp from a source buffer, a form in a source buffer can be macroexpanded, and source for functions defined by loading files into Lisp may be located automatically. For many of the bindings set up in the editing modes to be useful, there must be a Lisp to which Emacs can communicate. In this area the interface can be broken down into three parts: an enhanced mode for running an inferior Lisp process in an Emacs buffer, a new mode that creates an Emacs buffer onto an existing Lisp process via a TCP/IP socket, and mechanisms to query the Lisp environment for information which can be used in the Emacs environment (also using TCP/IP sockets). Running an inferior Lisp in an Emacs buffer is not new--Emacs supports this `off the shelf.' This feature allows users to interact directly with Lisp while editing Lisp source code. Although the existing inferior Lisp mode has been enhanced and a new mode added to support socket connections to Lisp, the most significant contribution of this package is in offering tighter coupling of the Lisp and Emacs environments and in providing better subprocess management tools. By taking advantage of Lisp multiprocessing, an Emacs buffer can be opened onto a Lisp not started as a subprocess of Emacs. This connection uses TCP/IP sockets (UNIX or internet domain), which in turn means that Emacs can talk to a Lisp running on any machine on the network. Sockets and multiprocessing also mean that one can establish more than one connection between Lisp and Emacs. These socket connections to Lisp are the key to the integration of the two environments. Emacs uses a `back door' connection to exchange information with a Lisp process. Users can obtain information about Lisp function argument lists and symbol documentation, macroexpand Lisp forms, and locate source definitions of Lisp symbols (which are recorded by Lisp when a symbol is defined, usually by loading a file). All these features are accessible with a few key-strokes. Aside from the Lisp interface proper, this package provides useful features for subprocess manipulation, including an input ring for handy retrieval of previously-typed input, filename completion, special handling of certain subprocess-specific keys (e.g., ^C or ^D), and continuously showing output from a subprocess in a visible buffer. 2. Editing Lisp This package modifies `auto-mode-alist' so that the major modes defined in this package are invoked when certain types of source files are edited. The list of filename extensions given by the value of `fi:common-lisp-file-types' cause `fi:common-lisp-mode' to be invoked whenever a file with one of these types is visited. The important actions done by Common Lisp mode are (in order): 1. set up local variables specific to the mode; 2. check for package information; 3. set up keymaps; and 4. call hooks. The above functions are enhancements to the standard available GNU Emacs Lisp mode. The major mode function for Common Lisp is called `fi:common-lisp-mode', and this function can be interactively called to put a buffer in Common Lisp mode. fi:common-lisp-file-types...........................................[variable] Value: (".cl" ".lisp" ".lsp") A list of the files which are automatically put in fi:common-lisp-mode. This variable should be set before this package is loaded. 2.1 Bindings The key bindings for Common Lisp mode are set up only once, the first time the mode is entered, and are taken from the variable `fi:common-lisp-mode-map'. Users wanting to change the bindings could explicitly set this variable or augment the map from within the hooks for the mode. The initial local bindings for Common Lisp mode are: fi:common-lisp-mode-map...............................................[keymap] Major mode map used when editing Common Lisp source. C-c Prefix Command RET fi:lisp-reindent-newline-indent DEL backward-delete-char-untabify TAB lisp-indent-line C-x Prefix Command ESC Prefix Command C-c C-r fi:lisp-eval-region C-c C-s fi:lisp-eval-last-sexp C-c C-b fi:lisp-eval-current-buffer ESC C-x fi:lisp-eval-defun ESC W fi:lisp-walk ESC M fi:lisp-macroexpand ESC F fi:lisp-function-documentation ESC D fi:lisp-describe ESC C fi:lisp-who-calls ESC A fi:lisp-arglist ESC TAB fi:lisp-complete-symbol ESC , fi:lisp-tags-loop-continue ESC . fi:lisp-find-tag ESC C-q indent-sexp 2.2 Variables All local variables are killed when Common Lisp mode is entered--this is a convention to insure that there are no name conflicts with user variables. To correctly deal with the Common Lisp package system, Emacs must know the package for each file, so that it may use this when sending expressions from a buffer to Lisp. There is a buffer-local variable which contains the name of the package: fi:package..........................................................[variable] Value: "user" A buffer-local variable whose value should either be nil or a string which names a package in the Lisp world (ie, in a Lisp subprocess running as an inferior of Emacs in some buffer). It is used when expressions are sent from an Emacs buffer to a Lisp process so that the symbols are read into the correct Lisp package. There are three ways to automatically set this variable (the first and third items here are standard GNU Emacs features): 1. If the first line in the file contains text surrounded by -*-, the `package' field of this line is parsed for the package name. For example, ;; -*- mode: common-lisp; package: excl -*- would put the file in package `excl'. 2. If the above attempt fails, then the buffer is searched for an `in-package' form, which is parsed for the package name. 3. Lastly, the values obtained in one of the first two locations can be over-written by manually setting fi:package in the local variables list. For example, the following at the end of the file will override any value given previously given to fi:package: ^L ;; Local Variables: ;; eval: (setq fi:package "excl") ;; End: Note that the normal method for setting a variable will not work, because `fi:package' contains a `:' and this confuses GNU Emacs, hence the use of `eval'. If Emacs cannot determine the package, then it is assumed to be "user" (the initial Common Lisp package). 2.3 Functions The following functions are either bound to keys in Common Lisp mode or are available as extended commands: fi:lisp-reindent-newline-indent.....................................[function] Invoke with: RET in Common Lisp mode. Indent the current line, insert a newline and indent to the proper column. fi:lisp-eval-region.................................................[function] Invoke with: C-c C-r in Common Lisp mode. Send the text in the region to the Lisp subprocess associated with this buffer, one expression at a time if there is more than one complete expression. If a Lisp subprocess has not been started, then one is started. With a prefix argument, the source sent to the subprocess is compiled. fi:lisp-eval-last-sexp..............................................[function] Invoke with: C-c C-s in Common Lisp mode. Send the sexp before the point to the Lisp subprocess associated with this buffer. If a Lisp subprocess has not been started, then one is started. With a prefix argument, the source sent to the subprocess is compiled. fi:lisp-eval-current-buffer.........................................[function] Invoke with: C-c C-b in Common Lisp mode. Send the entire buffer to the Lisp subprocess associated with this buffer. If a Lisp subprocess has not been started, then one is started. With a prefix argument, the source sent to the subprocess is compiled. fi:lisp-eval-defun..................................................[function] Invoke with: ESC C-x in Common Lisp mode. Send the current top-level (or nearest previous) form to the Lisp subprocess associated with this buffer. A `top-level' form is one that starts in column 1. If a Lisp subprocess has not been started, then one is started. With a prefix argument, the source sent to the subprocess is compiled. fi:remove-all-temporary-lisp-transaction-files......................[function] This function will clean up all the files created for Lisp/Emacs communication. See the variable fi:emacs-to-lisp-transaction-directory for the location of the files. The following functions are bound to keys in Common Lisp mode, and require the TCP/IP communication channel to Lisp: fi:lisp-find-tag....................................................[function] Invoke with: ESC . in Common Lisp mode. Find the Common Lisp source for a symbol, using the characters around the point as the default tag. fi:lisp-tags-loop-continue..........................................[function] Invoke with: ESC , in Common Lisp mode. Find the next occurrence of the tag last used by fi:lisp-find-tag. fi:lisp-arglist.....................................................[function] Invoke with: ESC A in Common Lisp mode. Print the arglist (using excl:arglist) for a symbol, which is read from the minibuffer. The word around the point is used as the default. fi:lisp-describe....................................................[function] Invoke with: ESC D in Common Lisp mode. Describe a symbol, which is read from the minibuffer. The word around the point is used as the default. fi:lisp-function-documentation......................................[function] Invoke with: ESC F in Common Lisp mode. Print the function documentation for a symbol, which is read from the minibuffer. The word around the point is used as the default. fi:lisp-macroexpand.................................................[function] Invoke with: ESC M in Common Lisp mode. Print the macroexpansion of the form at the point. fi:lisp-walk........................................................[function] Invoke with: ESC W in Common Lisp mode. Print the full macroexpansion the form at the point. With a prefix argument, macroexpand the code as the compiler would. fi:lisp-who-calls...................................................[function] Invoke with: ESC C in Common Lisp mode. Print all the callers of a function. The default symbol name is taken from the sexp around the point. fi:lisp-complete-symbol.............................................[function] Invoke with: ESC TAB in Common Lisp mode. Perform completion on the Common Lisp symbol preceding the point. That symbol is compared to symbols that exist in the Common Lisp, to which there is a TCP/IP connection (see fi:eval-in-lisp). If the symbol starts just after an open-parenthesis, then only symbols (in the Common Lisp) with function defintions are considered. Otherwise all symbols are considered. fi:set-associated-sublisp...........................................[function] When evaluated in a Lisp source buffer causes further `eval' commands (those which send expressions from Emacs to Lisp) to use BUFFER-NAME as the buffer which contains a Lisp subprocess. If evaluated when not in a Lisp source buffer, then the process type is read from the minibuffer ("common-lisp" or "franz-lisp"). The buffer name is interactively read and must be the name of an existing buffer. New buffers with the same mode as the current buffer will also use BUFFER-NAME for future `eval' commands. 2.3 Hooks The hooks run for Common Lisp mode are fi:lisp-mode-hook and fi:common-lisp-mode-hook. The form of the hook function is determined by `run-hooks', which is used to process the hooks. Hooks are run last during mode initialization. For example, the following hook enables auto-fill in Common Lisp mode: (setq fi:lisp-mode-hook '(lambda () (define-key (current-local-map) "\t" 'lisp-indent-line) (setq fill-column 75) (auto-fill-mode 1))) 3. Running Lisp What follows is a discussion of the bindings, variables and functions allowing the user to interact with and manipulate a Lisp run as an inferior to Emacs. A discussion on how to start up and use the interface is discussed in the next section. 3.1 Bindings The initial local bindings for Inferior Common Lisp mode are: fi:inferior-common-lisp-mode-map......................................[keymap] The inferior-common-lisp major-mode keymap. DEL backward-delete-char-untabify TAB lisp-indent-line C-x Prefix Command ESC Prefix Command C-c Prefix Command RET fi:inferior-lisp-newline C-c C-\ fi:subprocess-quit C-c C-d fi:subprocess-send-eof C-c C-c fi:subprocess-interrupt C-c C-w fi:subprocess-backward-kill-word C-c C-v fi:subprocess-show-output C-c C-u fi:subprocess-kill-input C-c C-s fi:re-search-forward-input C-c C-r fi:re-search-backward-input C-c C-p fi:pop-input C-c C-o fi:subprocess-send-flush C-c C-n fi:push-input C-c RET fi:subprocess-input-region C-c C-l fi:list-input-ring C-c C-k fi:subprocess-kill-output C-c C-a fi:subprocess-beginning-of-line C-x RET fi:inferior-lisp-input-list ESC W fi:lisp-walk ESC M fi:lisp-macroexpand ESC F fi:lisp-function-documentation ESC D fi:lisp-describe ESC C fi:lisp-who-calls ESC A fi:lisp-arglist ESC TAB fi:lisp-complete-symbol ESC , fi:lisp-tags-loop-continue ESC . fi:lisp-find-tag ESC RET fi:inferior-lisp-input-sexp ESC C-q indent-sexp and for the TCP Common Lisp mode: fi:tcp-common-lisp-mode-map...........................................[keymap] The tcp-lisp major-mode keymap. DEL backward-delete-char-untabify TAB lisp-indent-line C-x Prefix Command ESC Prefix Command C-c Prefix Command RET fi:inferior-lisp-newline C-c C-\ fi:tcp-lisp-kill-process C-c C-d fi:tcp-lisp-send-eof C-c C-c fi:tcp-lisp-interrupt-process C-c C-w fi:subprocess-backward-kill-word C-c C-v fi:subprocess-show-output C-c C-u fi:subprocess-kill-input C-c C-s fi:re-search-forward-input C-c C-r fi:re-search-backward-input C-c C-p fi:pop-input C-c C-o fi:subprocess-send-flush C-c C-n fi:push-input C-c RET fi:subprocess-input-region C-c C-l fi:list-input-ring C-c C-k fi:subprocess-kill-output C-c C-a fi:subprocess-beginning-of-line C-x RET fi:inferior-lisp-input-list ESC W fi:lisp-walk ESC M fi:lisp-macroexpand ESC F fi:lisp-function-documentation ESC D fi:lisp-describe ESC C fi:lisp-who-calls ESC A fi:lisp-arglist ESC TAB fi:lisp-complete-symbol ESC , fi:lisp-tags-loop-continue ESC . fi:lisp-find-tag ESC RET fi:inferior-lisp-input-sexp ESC C-q indent-sexp Superkeys are keys that are handled specially at the end of a buffer. At the end of a buffer it has a buffer-specific meaning, but anywhere else in the buffer it has the normal global meaning (obtained by looking the key up in the global keymap). This way, ^D can send an EOF to the Lisp process at the end of a buffer but invoke delete-char ("delete character") anywhere else. The values of `fi:inferior-common-lisp-mode-super-key-map' and `fi:tcp-common-lisp-mode-super-key-map' are used as superkey maps for Inferior Common Lisp and TCP Common Lisp modes. Superkeys are turned off by default. 3.2 Variables The name of the Common Lisp image to activate for an inferior Lisp is taken from the following variables: fi:common-lisp-image-name...........................................[variable] Value: "cl" *Default Common Lisp image to invoke from `fi:common-lisp'. If the value is a string then it names the image file or image path that `fi:common-lisp' invokes. Otherwise, the value of this variable is given to funcall, the result of which should yield a string which is the image name or path. After the image name as been determined and the process has been started, a file in the user's home directory called .emacs_, where is the image name, is fed to the newly created process. This could be used to customize a initialization file on the name of the Lisp binary. The command-line arguments passed to the activated image are taken from the following variables: fi:common-lisp-image-arguments......................................[variable] Value: nil *Default Common Lisp image arguments when invoked from `fi:common-lisp', which must be a list of strings. The prompt pattern for the inferior Lisp is taken from a variable with the name `fi:-prompt-pattern' or from the following: fi:common-lisp-prompt-pattern.......................................[variable] Value: "^\\(\\[[0-9]+c?\\] \\|\\[step\\] \\)?<[-A-Za-z]* ?[0-9]*?> " *The regular expression which matches the Common Lisp prompt, used in Inferior Common Lisp mode. Anything from beginning of line up to the end of what this pattern matches is deemed to be a prompt. fi:common-lisp-package-regexp.......................................[variable] Value: "(in-package\\>\\|:\\\\|:\\\\|:\\\\|:\\\\|:\\\\|:\\" *The regular expression matching the Common Lisp expression(s) to change packages. If nil, no automatic package tracking will be done. The following variables are used in TCP Common Lisp mode: fi:unix-domain......................................................[variable] Value: t *If non-nil, then `fi:unix-domain-socket' specifies the name of the socket file. It is recommended that this interface be used, and not internet ports, because when internet ports are used only one process on a machine may use this interface (it is a global resource). When using UNIX domain sockets, communication is done through a socket file in the user's home directory. But, if you really want to use internet ports, here are the steps to take: 1. Set this variable to nil. 2. Add the following line to /etc/services: excl 6789/tcp 3. Make sure `fi:local-host-name' is in /etc/hosts and points to the local or loopback host. 4. On the Common Lisp side, put the following in you .clinit.cl file: (setq ipc:*inet-port* 6789) ; the number from /etc/services (setq ipc:*unix-domain* nil) The problem with this, is that people can then use `telnet' to get a listener on your lisp! fi:unix-domain-socket...............................................[variable] Value: "~/.excl_to_emacs" *The name of the socket file that lisp and emacs use to communicate. This is used when fi:unix-domain is non-nil. fi:excl-service-name................................................[variable] Value: "excl" *The service name from /etc/services (`tcp' type). This is only used when fi:unix-domain is nil. fi:local-host-name..................................................[variable] Value: "localhost" *On 4.2 BSD the name of 127.1--usually localhost or loopback. This is only used when fi:unix-domain is nil. fi:source-info-not-found-hook.......................................[variable] Value: find-tag *The value of this variable is funcalled when source information is not present in Lisp for a symbol. The function is given one argument, the name for which source is desired (a string). The null string means use the word at the point as the search word. This allows the GNU Emacs tags facility to be used when the information is not present in Lisp. plus the following miscellaneous variables: fi:echo-evals-from-buffer-in-listener-p.............................[variable] Value: nil *If non-NIL, forms evalutated directly from a lisp buffer by the fi:lisp-eval-* functions will be echoed by the lisp listener. fi:emacs-to-lisp-transaction-directory..............................[variable] Value: "/tmp" *The directory in which files for Emacs/Lisp communication are stored. When using Lisp and Emacs on different machines, this directory should be accessible on both machine with the same pathname (via the wonders of NFS). fi:subprocess-enable-superkeys......................................[variable] Value: nil *If t, certain keys become `superkeys' in subprocess buffers--this should be set before starting any subprocesses. The superkeys are C-a, C-d, C-o,C-u, C-w, C-z, and C-\, which will behave as they would in the current local keymap when typed at the end of a subprocess buffer. If typed elsewhere, these keys have their normal global binding. This is a buffer-local symbol. Use setq-default to set the default value for this symbol. fi:pop-to-sublisp-buffer-after-lisp-eval............................[variable] Value: t *If non-nil, then after sending expressions to a Lisp process do pop to the buffer which contains the Lisp. fi:display-buffer-function..........................................[variable] Value: switch-to-buffer *If non-nil, then it is used as the function which is funcall'd with one argument, a buffer, to display a subprocess buffer when it is created (ie, from `fi:common-lisp'). fi:lisp-evalserver-timeout..........................................[variable] Value: 5 The time which fi:eval-in-lisp will wait before timing out and signalling an error. Without a timeout Emacs would potentially be locked out if Lisp did not `return' a result. fi:lisp-evalserver-number-reads.....................................[variable] Value: 20 The number of times the Lisp eval server tries to read from the lisp-evalserver process before giving up. Without this feature Emacs would hang if Lisp got into an infinite loop while printing. If the size of the values returned to Emacs is large, then the value of this variable should be increased. The following are miscellaneous subprocess variables: fi:default-input-ring-max...........................................[variable] Value: 50 *The default maximum length to which an input ring is allowed to grow. fi:shell-token-pattern..............................................[variable] Value: "[ ()<>&|;=]" *The regular expression used by file name completion to mark path name boundaries. fi:subprocess-continuously-show-output-in-visible-buffer............[variable] Value: t *If t, output from a subprocess to a visible buffer is continuously shown. If a subprocess buffer is visible and the window point is beyond the process output marker, output to that buffer from its associated process will be continuously visible. If the window point is before the process output marker, the window is not updated. This is a buffer-local symbol. The following three variables are used to track the shell commands which change the current working directory. For Common Lisp, the aliases in Appendix A together with these variables will allow Common Lisp to emulate the shell commands and for Emacs to track them: fi:shell-cd-regexp..................................................[variable] Value: ":?cd" *The regular expression matching the C shell `cd' command. If nil, no automatic directory changes will be made. fi:shell-popd-regexp................................................[variable] Value: ":?popd" *The regular expression matching the C shell `popd' command. If nil, no automatic directory changes will be made. fi:shell-pushd-regexp...............................................[variable] Value: ":?pushd" *The regular expression matching the C shell `pushd' command. If nil, no automatic directory changes will be made. 3.3 Functions fi:common-lisp......................................................[function] Start a Common Lisp subprocess in a buffer whose name is determined from the optional prefix argument BUFFER-NUMBER. Common Lisp buffer names start with `*common-lisp' and end with `*', with an optional `-N' in between. If BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER is >= 0, then the buffer is named `*common-lisp-*'. If BUFFER-NUMBER is < 0, then the first available buffer name is chosen. The image file and image arguments are taken from the variables `fi:common-lisp-image-name' and `fi:common-lisp-image-arguments'. See fi:explicit-common-lisp. fi:explicit-common-lisp.............................................[function] The same as fi:common-lisp, except that the image and image arguments are read from the minibuffer. fi:remote-common-lisp...............................................[function] Start a Common Lisp subprocess in a buffer whose name is determined from the optional prefix argument BUFFER-NUMBER, where the Common Lisp image is run on another machine. Common Lisp buffer names start with `*common-lisp' and end with `*', with an optional `-N' in between. If BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER is >= 0, then the buffer is named `*common-lisp-*'. If BUFFER-NUMBER is < 0, then the first available buffer name is chosen. The host on which the image is run is read from the minibuffer. The image file and image arguments are taken from the variables `fi:common-lisp-image-name' and `fi:common-lisp-image-arguments'. See fi:explicit-remote-common-lisp. fi:explicit-remote-common-lisp......................................[function] The same as fi:remote-common-lisp, except that the image and image arguments are read from the minibuffer. fi:tcp-common-lisp..................................................[function] In a buffer whose name is determined from the optional prefix argument BUFFER-NAME, connect to a Common Lisp using either a UNIX domain socket file or internet port number. Common Lisp buffer names start with `*common-lisp' and end with `*', with an optional `-N' in between. If BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER is >= 0,then the buffer is named `*common-lisp-*'. If BUFFER-NUMBER is < 0, then the first available buffer name is chosen. See `fi:unix-domain' and `fi:explicit-tcp-common-lisp'. fi:explicit-tcp-common-lisp.........................................[function] The same as fi:tcp-common-lisp, except that the host name a port number are read from the minibuffer. Use a port number of 0 for UNIX domain sockets. fi:inferior-lisp-newline............................................[function] Invoke with: RET in Inferior Common Lisp mode. Bound to RET in an inferior Lisp buffer. At the end of the buffer it inserts a newline and performs automatic indentation. Whole expressions are sent to Lisp (not each piece after each newline is typed). This allows previously typed lines to be edited before Lisp is sent the input. Typed anywhere else in the buffer, this functions causes the input previously typed (around the point) to be copied to the end of the subprocess buffer and send to Lisp. fi:inferior-lisp-input-sexp.........................................[function] Invoke with: ESC RET in Inferior Common Lisp mode. Send the sexp on which the point resides to the Lisp subprocess. With a numeric prefix argument, send that many sexps. fi:inferior-lisp-input-list.........................................[function] Invoke with: C-x RET in Inferior Common Lisp mode. Send the list before the point to the Lisp subprocess. With a numeric prefix argument, send that many lists. fi:subprocess-input-region..........................................[function] Invoke with: C-c RET in Inferior Common Lisp mode. Send the region defined by the point and mark to the Lisp subprocess. fi:subprocess-kill-input............................................[function] Invoke with: C-c C-u in Inferior Common Lisp mode. Kill all input since the last output by the subprocess. fi:subprocess-beginning-of-line.....................................[function] Invoke with: C-c C-a in Inferior Common Lisp mode. Moves point to beginning of line, just like (beginning-of-line), except that if the pattern at the beginning of the line matches the current subprocess prompt pattern, this function skips over it. fi:subprocess-backward-kill-word....................................[function] Invoke with: C-c C-w in Inferior Common Lisp mode. Kill previous word in current subprocess input line. This function takes care not to delete past most recent subprocess output. fi:subprocess-kill-output...........................................[function] Invoke with: C-c C-k in Inferior Common Lisp mode. Kill all output from the subprocess since the last input. fi:subprocess-quit..................................................[function] Invoke with: C-c C-\ in Inferior Common Lisp mode. Send a quit signal to the subprocess. fi:subprocess-send-flush............................................[function] Invoke with: C-c C-o in Inferior Common Lisp mode. Send the `flush output' character (^O) to subprocess. fi:subprocess-show-output...........................................[function] Invoke with: C-c C-v in Inferior Common Lisp mode. Display the start of this batch of shell output at top of window. Also move the point there. fi:subprocess-suspend...............................................[function] Suspend, with a SIGSTOP, the current subprocess. The following three functions are used in fi:inferior-lisp-mode to interrupt, kill or input an end-of-file to the Lisp process: fi:subprocess-interrupt.............................................[function] Invoke with: C-c C-c in Inferior Common Lisp mode. Interrupt the current subprocess. fi:subprocess-kill..................................................[function] Send a `kill' (SIGKILL) signal to the current subprocess. fi:subprocess-send-eof..............................................[function] Invoke with: C-c C-d in Inferior Common Lisp mode. Send an end of file to the subprocess. The following three functions are used in fi:tcp-common-lisp-mode to interrupt, kill and input an end-of-file to the Lisp process at the other end of the TCP/IP socket: fi:tcp-lisp-interrupt-process.......................................[function] Invoke with: C-c C-c in TCP Common Lisp mode. Interrupt the tcp-lisp process via a mp:process-interrupt spoken to the backdoor Common Lisp listener. fi:tcp-lisp-kill-process............................................[function] Invoke with: C-c C-\ in TCP Common Lisp mode. Kill a tcp-lisp process via a mp:process-kill spoken to the backdoor Common Lisp listener. fi:tcp-lisp-send-eof................................................[function] Invoke with: C-c C-d in TCP Common Lisp mode. Simulate an EOF on the tcp-lisp process via a db:debug-pop spoken to the backdoor Common Lisp listener. All input typed to a subprocess buffer is saved in a ring. The following functions retrieve input and manipulate the ring: fi:pop-input........................................................[function] Invoke with: C-c C-p in Inferior Common Lisp mode. Yank previous text from input ring. Cycle through input ring with each successive invocation. fi:push-input.......................................................[function] Invoke with: C-c C-n in Inferior Common Lisp mode. Yank next text from input ring. Cycle through input ring in reverse order with each successive invocation. fi:list-input-ring..................................................[function] Invoke with: C-c C-l in Inferior Common Lisp mode. Display contents of input ring, starting at arg. The list is displayed in reverse order if called from a program and the optional second parameter is non-nil. fi:re-search-backward-input.........................................[function] Invoke with: C-c C-r in Inferior Common Lisp mode. Search in input ring for text that contains regexp and yank. fi:re-search-forward-input..........................................[function] Invoke with: C-c C-s in Inferior Common Lisp mode. Search in input ring for text that contains regexp and yank. plus the following miscellaneous function: fi:eval-in-lisp.....................................................[function] Apply format (in Emacs) to STRING and ARGS and evaluate the result in the Common Lisp to which we are connected. If a lisp-eval-server has not been started, then this function starts it. 3.4 Hooks The hooks run at the end of Inferior Common Lisp mode initialization are: fi:lisp-mode-hook fi:subprocess-mode-hook fi:inferior-common-lisp-mode-hook and for TCP Common Lisp mode are: fi:lisp-mode-hook fi:subprocess-mode-hook fi:tcp-common-lisp-mode-hook 4. Starting the Interface The two parts of the (full) interface which require user setup are: * running Lisp as an inferior of Emacs, with a "Lisp listener daemon" listening for connections from Emacs * a set of Emacs bindings that query Lisp for information In this sections the setup of these features will be discussed. 4.1 Setup (After the installation procedure has been followed (see the file INSTALL in the main distribution directory) the interface will be in a subdirectory of the `lisp' directory. Typically the location is /usr/local/lib/emacs, which is the pathname used throughout the rest of this document.) The Lisp part of the interface consists of a Lisp process called the "Lisp listener daemon" which lies dormant until Emacs tries to communicate with it. When Emacs "connects" an interactive top level is started (called a "read-eval-print" loop) to which Emacs can send expressions for evaluation and from which Emacs receives the results of evaluation (see fi:eval-in-lisp). The preferred method to start this daemon is to put the following in your .login file: setenv EMACSLIBRARY /usr/local/lib/emacs and to put the following in your .clinit.cl file in your home directory: (defparameter *emacs-library* (let ((emacs-lib (si:getenv "EMACSLIBRARY"))) (if emacs-lib (format nil "~a/lisp/fi/" emacs-lib)))) (and *emacs-library* (find "+ipc" (system:command-line-arguments) :test #'string=) (load (merge-pathnames "clinit.cl" *emacs-library*)) (load-and-start-ipc-package)) and to put the following in your .emacs file in your home directory: (load "fi/site-init.el") (setq fi:common-lisp-image-arguments '("+ipc")) (setq fi:unix-domain-socket (format "/tmp/%s_emacs_to_acl" (user-login-name))) Now consider the following typed to Emacs: M-x fi:common-lisp RET This will cause a Common Lisp (the default image name is `cl') to be started in a buffer called `*common-lisp*', as an inferior process of Emacs. This Common Lisp will be passed a command line argument of `+ipc', which will cause Common Lisp to load and start the Lisp listener daemon. Emacs and Common Lisp will communicate through a UNIX domain socket (a file) in /tmp called `USER_emacs_to_acl', where USER is the currently-logged-in-user's name. All of the bindings and functions described above are now available. 4.2 Examples After fi:common-lisp has started a Common Lisp and all the above modifications to .emacs and .clinit.cl have been made, the following Emacs command will open a second buffer onto the same Lisp. This listener is a separate Common Lisp process (as opposed to a separate Operating System process) and the entire Common Lisp environment available in the first listener is available in this one: M-x fi:tcp-common-lisp RET To run a second Common Lisp and get a completely fresh Common Lisp: C-u 2 M-x fi:common-lisp RET The former uses one Common Lisp for multiple purposes (compiling a program in one buffer while typing forms to another), while the latter starts two separate Common Lisp processes, and thus uses twice the memory and swap space. 4.2.1 Remote Common Lisps using TCP/IP It is possible, with the functions and bindings in this interface, to run an Emacs and Common Lisp on two different machines. For example, to run Emacs on a machine called `snooze' and Common Lisp on one called `akbar', where both machines are accessible on the network, ~/.emacs on `snooze' would contain: (setq fi:unix-domain nil) (setq fi:local-host-name "akbar") ; the remote host name and ~/.clinit.cl on `akbar' would contain the forms given in section 4.1 with the call to load-and-start-ipc-package replaced with: (load-and-start-ipc-package :unix-domain nil) Then, make sure the value of ipc::*inet-port* in ipc.cl and fi:excl-service-name in tcplisp.el (all in the lisp/fi directory) match what is in /etc/services. For the interface as distributed, put the following line in /etc/services: excl 6789/tcp on both `akbar' and `snooze'. Then, on `akbar', possibly in a shell buffer remotely logged into `akbar', startup Common Lisp with the +ipc argument: akbar% cl +ipc (If you get the error "bind: Address already in use" then the port number you chose is already being used by another program. In this case, use something other than 6789 (in the default case) or the one currently being used.) Then, on `snooze' do: M-x fi:tcp-common-lisp RET which will open a connection to the Lisp on `akbar' from `snooze'. 4.2.2 Remote Common Lisps using `rsh' It is also possible to run Common Lisp on another machine using `rsh'. For example, typing the following to Emacs will start a Lisp process on host `akbar' without using the TCP/IP connection between Common Lisp and Emacs: M-x fi:remote-common-lisp RET akbar RET NOTE: fi:remote-common-lisp uses fi:common-lisp-image-name to determine which image to activate. If the image name is incorrect for the remote machine, then use fi:explicit-remote-common-lisp. Appendix A Sample .emacs ;; -[Fri Nov 18 18:53:13 1988 by layer]- ;; Sample .emacs file ;; ;; $Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/emacs-18.55/dist-1.3/fi/spec.out,v 1.1.1.1 2018/04/24 16:12:57 root Exp $ (load "fi/site-init.el") ;; use a socket file in /tmp since can't communicate via files on NFS ;; mounted file systems ;; (setq fi:unix-domain-socket (format "/tmp/%s_emacs_to_acl" (user-login-name))) ;; turn on superkeys in subprocess modes ;; (setq-default fi:subprocess-enable-superkeys t) ;; the following causes fi:common-lisp to give the inferior Common ;; Lisp, by default, a command line argument of `+ipc': ;; (setq fi:common-lisp-image-arguments '("+ipc")) ;; the following causes fi:common-lisp to invoke the image `acl', but ;; to ask for an image name when given a prefix argument: ;; (setq fi:common-lisp-image-name '(lambda () (let ((image "acl")) (if current-prefix-arg (setq image (read-file-name (format "cl image (default: %s): " image) default-directory image nil))) (setq mode-line-buffer-identification (format "%s (%s)" (buffer-name) (file-name-nondirectory image))) image))) ;; This redefines `kill-emacs' so that transaction files in /tmp are ;; removed emacs is killed: ;; (fset 'old-kill-emacs (symbol-function 'kill-emacs)) (defun kill-emacs (&optional arg) (interactive "P") (fi:remove-all-temporary-lisp-transaction-files) (old-kill-emacs arg)) Appendix B Sample .clinit.cl ;; -[Fri Nov 18 19:00:37 1988 by layer]- ;; Sample .clinit.cl file ;; ;; $Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/emacs-18.55/dist-1.3/fi/spec.out,v 1.1.1.1 2018/04/24 16:12:57 root Exp $ (format t "; Loading home clinit...~%") (defparameter *emacs-library* (let ((emacs-lib (si:getenv "EMACSLIBRARY"))) (if emacs-lib (format nil "~a/lisp/fi/" emacs-lib)))) (and *emacs-library* (find "+ipc" (system:command-line-arguments) :test #'string=) (load (merge-pathnames "clinit.cl" *emacs-library*)) (load-and-start-ipc-package :unix-domain nil)) ;; The following emulates the C shell cd, pushd, popd, pwd, and dirs, ;; and allows Emacs to track directory changes: (defvar *directory-stack* (list (namestring (setq *default-pathname-defaults* (current-directory))))) (tpl:alias ("pushd" :string) (&optional dir) (if* (string= "" dir) then (let ((old-top (pop *directory-stack*)) (new-top (pop *directory-stack*))) (push old-top *directory-stack*) (push (chdir new-top) *directory-stack*)) else (push (chdir dir) *directory-stack*)) (format t "~a~%" *directory-stack*)) (tpl:alias "popd" () (if (> (length *directory-stack*) 1) (pop *directory-stack*) (format t "nothing to pop into~%")) (chdir (car *directory-stack*)) (format t "~a~%" *directory-stack*)) (tpl:alias "dirs" () (format t "~a~%" *directory-stack*)) (tpl:alias ("cd" :string) (dir) (setf (car *directory-stack*) (apply #'chdir (if (string= "" dir) nil (list dir)))) (format t "~a~%" *directory-stack*)) (tpl:alias "pwd" () (format t "process cwd = ~a~%*default-pathname-defaults* = ~a~%" (namestring (current-directory)) (namestring (truename *default-pathname-defaults*)))) Appendix C Sample X11 interaction ;; -[Fri Nov 18 20:21:56 1988 by layer]- ;; Sample X11 bindings for .emacs file ;; ;; $Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/emacs-18.55/dist-1.3/fi/spec.out,v 1.1.1.1 2018/04/24 16:12:57 root Exp $ (require 'x-mouse) (defun x-lisp-find-tag (arg) (x-mouse-set-point arg) (cond ((eq major-mode 'fi:common-lisp-mode) (fi:lisp-find-tag)) (t (find-tag-other-window (find-tag-default))))) (defun x-lisp-eval-defun (arg) (x-mouse-set-point arg) (cond ((memq major-mode '(fi:common-lisp-mode fi:franz-lisp-mode fi:lisp-mode)) (fi:lisp-eval-defun nil)) ((eq major-mode 'fi:emacs-lisp-mode) (eval-defun)))) (defun x-lisp-arglist (arg) (x-mouse-set-point arg) (cond ((eq major-mode 'fi:common-lisp-mode) (fi:lisp-arglist)) (t (describe-function (intern (find-tag-default)))))) (define-key mouse-map x-button-left-up 'x-lisp-find-tag) (define-key mouse-map x-button-middle-up 'x-lisp-eval-defun) (define-key mouse-map x-button-right-up 'x-lisp-arglist) ;; we ignore mouse button-down events, because if we put something ;; on it the `up' event will cause the minibuffer output to disappear (define-key mouse-map x-button-left 'x-mouse-ignore) (define-key mouse-map x-button-middle 'x-mouse-ignore) (define-key mouse-map x-button-right 'x-mouse-ignore) (define-key mouse-map x-button-c-left 'x-mouse-ignore) Appendix D Franz Lisp Support D.1 Introduction Franz Lisp is handled very similar to Common Lisp, the only difference being that Franz Lisp does not support TCP/IP socket communication. In all other ways, the features, function and variable names mirror those of the corresponding Common Lisp functions and variables. D.2 Editing Franz Lisp As with Common Lisp, editing a Franz Lisp source file (.l extension) causes fi:franz-lisp-mode to be invoked. The order of setup in the mode follows that of fi:common-lisp-mode. Package system set-up also occurs in the same way as in fi:common-lisp-mode. Franz Lisp does not support the commands depending on TCP/IP. D.2.1 Bindings fi:franz-lisp-mode-map................................................[keymap] Major mode map used when editing Franz Lisp source. C-c Prefix Command RET fi:lisp-reindent-newline-indent DEL backward-delete-char-untabify TAB lisp-indent-line C-x Prefix Command ESC Prefix Command C-c C-r fi:lisp-eval-region C-c C-s fi:lisp-eval-last-sexp C-c C-b fi:lisp-eval-current-buffer ESC C-x fi:lisp-eval-defun ESC C-q indent-sexp D.2.2 Variables The buffer-local variable fi:package is set up as in fi:common-lisp-mode. D.2.3 Functions The functions in the keymaps are a subset of those in Common Lisp mode--refer to the main document for a description of those commands. D.2.4 Hooks The hooks run are fi:lisp-mode-hook and fi:franz-lisp-mode-hook, and are done last in the mode initialization. D.3 Running Franz Lisp As with Common Lisp, there are two entry points for running an inferior Franz Lisp. `M-x fi:franz-lisp' and `M-x fi:explicit-franz-lisp' create Franz Lisp processes. The default name of the Franz Lisp image is `lisp'. D.3.1 Bindings fi:inferior-franz-lisp-mode-map.......................................[keymap] The inferior-franz-lisp major-mode keymap. DEL backward-delete-char-untabify TAB lisp-indent-line C-x Prefix Command ESC Prefix Command C-c Prefix Command RET fi:inferior-lisp-newline C-c C-\ fi:subprocess-quit C-c C-d fi:subprocess-send-eof C-c C-c fi:subprocess-interrupt C-c C-w fi:subprocess-backward-kill-word C-c C-v fi:subprocess-show-output C-c C-u fi:subprocess-kill-input C-c C-s fi:re-search-forward-input C-c C-r fi:re-search-backward-input C-c C-p fi:pop-input C-c C-o fi:subprocess-send-flush C-c C-n fi:push-input C-c RET fi:subprocess-input-region C-c C-l fi:list-input-ring C-c C-k fi:subprocess-kill-output C-c C-a fi:subprocess-beginning-of-line C-x RET fi:inferior-lisp-input-list ESC RET fi:inferior-lisp-input-sexp ESC C-q indent-sexp D.3.2 Variables fi:franz-lisp-image-name............................................[variable] Value: "lisp" *Default Franz Lisp image to invoke from `fi:franz-lisp'. If the value is a string then it names the image file or image path that `fi:common-lisp' invokes. Otherwise, the value of this variable is given to funcall, the result of which should yield a string which is the image name or path. fi:franz-lisp-image-arguments.......................................[variable] Value: nil *Default Franz Lisp image arguments when invoked from `fi:franz-lisp'. fi:franz-lisp-prompt-pattern........................................[variable] Value: "^[-=]> +\\|^c{[0-9]+} +" *The regular expression which matches the Franz Lisp prompt, used in Inferior Franz Lisp mode. Anything from beginning of line up to the end of what this pattern matches is deemed to be a prompt. D.3.3 Functions fi:franz-lisp.......................................................[function] Start a Franz Lisp subprocess in a buffer whose name is determined from the optional prefix argument BUFFER-NUMBER. Franz Lisp buffer names start with `*franz-lisp' and end with `*', with an optional `-N' in between. If BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER is >= 0, then the buffer is named `*franz-lisp-*'. If BUFFER-NUMBER is < 0, then the first available buffer name is chosen. The image file and image arguments are taken from the variables `fi:franz-lisp-image-name' and `fi:franz-lisp-image-arguments'. See fi:explicit-franz-lisp. fi:explicit-franz-lisp..............................................[function] The same as fi:franz-lisp, except that the image and image arguments are read from the minibuffer. D.3.3 Hooks The following hooks are run when starting up an inferior Franz Lisp: fi:lisp-mode-hook fi:subprocess-mode-hook fi:inferior-franz-lisp-mode-hook