;;; ielm.el --- interaction mode for Emacs Lisp
+
;; Copyright (C) 1994 Free Software Foundation, Inc.
;; Author: David Smith <maa036@lancaster.ac.uk>
+;; Maintainer: FSF
;; Created: 25 Feb 1994
;; Keywords: lisp
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
;;; Commentary:
;;
;; (autoload 'ielm "ielm" "Start an inferior Emacs Lisp session" t)
;;
-;; For completion to work, the comint.el from FSF Emacs 19.23 is
+;; For completion to work, the comint.el from Emacs 19.23 is
;; required. If you do not have it, or if you are running Lemacs,
;; also add the following code to your .emacs:
;;
;; (setq ielm-mode-hook
;; '(lambda nil
;; (define-key ielm-map "\t"
-;; '(lambda nil (interactive) (or (ielm-tab)
+;; '(lambda nil (interactive) (or (ielm-tab)
;; (lisp-complete-symbol))))))
;; To start: M-x ielm. Type C-h m in the *ielm* buffer for more info.
-;; The latest version is available by WWW from
+;; The latest version is available by WWW from
;; http://mathssun5.lancs.ac.uk:2080/~maa036/elisp/dir.html
;; or by anonymous FTP from
;; /anonymous@wingra.stat.wisc.edu:pub/src/emacs-lisp/ielm.el.gz
;;; User variables
-(defvar ielm-noisy t
- "*If non-nil, IELM will beep on error.")
+(defgroup ielm nil
+ "Interaction mode for Emacs Lisp."
+ :group 'lisp)
+
-(defvar ielm-prompt "ELISP> "
- "Prompt used in IELM.")
+(defcustom ielm-noisy t
+ "*If non-nil, IELM will beep on error."
+ :type 'boolean
+ :group 'ielm)
-(defvar ielm-dynamic-return t
+(defcustom ielm-prompt "ELISP> "
+ "Prompt used in IELM."
+ :type 'string
+ :group 'ielm
+ :get #'(lambda (symbol) (substring-no-properties (symbol-value symbol)))
+ :set #'(lambda (symbol value) (set symbol (propertize value 'read-only t 'rear-nonsticky t))))
+
+(defcustom ielm-dynamic-return t
"*Controls whether \\<ielm-map>\\[ielm-return] has intelligent behaviour in IELM.
If non-nil, \\[ielm-return] evaluates input for complete sexps, or inserts a newline
-and indents for incomplete sexps. If nil, always inserts newlines.")
+and indents for incomplete sexps. If nil, always inserts newlines."
+ :type 'boolean
+ :group 'ielm)
-(defvar ielm-dynamic-multiline-inputs t
+(defcustom ielm-dynamic-multiline-inputs t
"*Force multiline inputs to start from column zero?
If non-nil, after entering the first line of an incomplete sexp, a newline
will be inserted after the prompt, moving the input to the next line.
This gives more frame width for large indented sexps, and allows functions
-such as `edebug-defun' to work with such inputs.")
+such as `edebug-defun' to work with such inputs."
+ :type 'boolean
+ :group 'ielm)
+
+(defcustom ielm-mode-hook nil
+ "*Hooks to be run when IELM (`inferior-emacs-lisp-mode') is started."
+ :type 'hook
+ :group 'ielm)
+
+(defvar * nil
+ "Most recent value evaluated in IELM.")
+
+(defvar ** nil
+ "Second-most-recent value evaluated in IELM.")
+
+(defvar *** nil
+ "Third-most-recent value evaluated in IELM.")
-(defvar ielm-mode-hook nil
- "*Hooks to be run when IELM (`inferior-emacs-lisp-mode') is started.")
+(defvar ielm-match-data nil
+ "Match data saved at the end of last command.")
;;; System variables
"Buffer in which IELM sexps will be evaluated.
This variable is buffer-local.")
-(defvar ielm-header
- (concat
- "*** Welcome to IELM version "
- (substring "$Revision: 1.25 $" 11 -2)
- " *** Type (describe-mode) for help.\n"
- "IELM has ABSOLUTELY NO WARRANTY; type (describe-no-warranty) for details.\n")
+(defvar ielm-header
+ "*** Welcome to IELM *** Type (describe-mode) for help.\n"
"Message to display when IELM is started.")
(defvar ielm-map nil)
(define-key ielm-map "\C-j" 'ielm-send-input)
(define-key ielm-map "\e\C-x" 'eval-defun) ; for consistency with
(define-key ielm-map "\e\t" 'lisp-complete-symbol) ; lisp-interaction-mode
- ;; These bindings are from shared-lisp-mode-map -- can you inherit
+ ;; These bindings are from `lisp-mode-shared-map' -- can you inherit
;; from more than one keymap??
- (define-key ielm-map "\e\C-q" 'indent-sexp)
- (define-key ielm-map "\eq" 'lisp-fill-paragraph)
+ (define-key ielm-map "\e\C-q" 'indent-sexp)
(define-key ielm-map "\177" 'backward-delete-char-untabify)
;; Some convenience bindings for setting the working buffer
(define-key ielm-map "\C-c\C-b" 'ielm-change-working-buffer)
(define-key ielm-map "\C-c\C-f" 'ielm-display-working-buffer)
(define-key ielm-map "\C-c\C-v" 'ielm-print-working-buffer))
+(defvar ielm-font-lock-keywords
+ (list
+ (cons (concat "^" (regexp-quote ielm-prompt)) 'font-lock-keyword-face)
+ '("\\(^\\*\\*\\*[^*]+\\*\\*\\*\\)\\(.*$\\)"
+ (1 font-lock-comment-face)
+ (2 font-lock-constant-face)))
+ "Additional expressions to highlight in ielm buffers.")
+
;;; Completion stuff
(defun ielm-tab nil
(progn
(ielm-indent-line)
t)))
-
+
(defun ielm-complete-symbol nil
"Complete the lisp symbol before point."
;; A wrapper for lisp-complete symbol that returns non-nil if
;; completion has occurred
(let* ((btick (buffer-modified-tick))
- (cbuffer (get-buffer " *Completions*"))
+ (cbuffer (get-buffer "*Completions*"))
(ctick (and cbuffer (buffer-modified-tick cbuffer))))
(lisp-complete-symbol)
;; completion has occurred if:
- (or
+ (or
;; the buffer has been modified
- (not (= btick (buffer-modified-tick)))
- ;; a completions buffer has been modifed or created
+ (not (= btick (buffer-modified-tick)))
+ ;; a completions buffer has been modified or created
(if cbuffer
(not (= ctick (buffer-modified-tick cbuffer)))
- (get-buffer " *Completions*")))))
+ (get-buffer "*Completions*")))))
(defun ielm-complete-filename nil
"Dynamically complete filename before point, if in a string."
(if (nth 3 (parse-partial-sexp comint-last-input-start (point)))
(comint-dynamic-complete-filename)))
-
+
(defun ielm-indent-line nil
"Indent the current line as Lisp code if it is not a prompt line."
- (if (save-excursion
- (beginning-of-line)
- (looking-at comint-prompt-regexp)) nil
+ (when (save-excursion (comint-bol) (bolp))
(lisp-indent-line)))
;;; Working buffer manipulation
and indents. If however `ielm-dynamic-return' is nil, this always
simply inserts a newline."
(interactive)
- (if ielm-dynamic-return
- (let ((state
+ (if ielm-dynamic-return
+ (let ((state
(save-excursion
(end-of-line)
(parse-partial-sexp (ielm-pm)
(newline-and-indent)))
(newline)))
+(defvar ielm-input)
+
(defun ielm-input-sender (proc input)
- ;; Just sets the variable ielm-input, which is in the scope of
+ ;; Just sets the variable ielm-input, which is in the scope of
;; `ielm-send-input's call.
(setq ielm-input input))
(if (ielm-is-whitespace (substring ielm-string ielm-pos))
;; need this awful let convolution to work around
;; an Emacs bug involving local vbls and let binding
- (let ((:save :)
- (::save ::)
- (:::save :::))
+ (let ((*save *)
+ (**save **)
+ (***save ***))
+ (set-match-data ielm-match-data)
(save-excursion
(set-buffer ielm-working-buffer)
(condition-case err
- (let ((: :save)
- (:: ::save)
- (::: :::save)
+ (let ((* *save)
+ (** **save)
+ (*** ***save)
(ielm-obuf (current-buffer)))
(setq ielm-result (eval ielm-form))
(setq ielm-wbuf (current-buffer))
(error (setq ielm-result (ielm-format-error err))
(setq ielm-error-type "Eval error"))
(quit (setq ielm-result "Quit during evaluation")
- (setq ielm-error-type "Eval error")))))
+ (setq ielm-error-type "Eval error"))))
+ (setq ielm-match-data (match-data)))
(setq ielm-error-type "IELM error")
(setq ielm-result "More than one sexp in input"))))
(if ielm-noisy (ding))
(setq ielm-output (concat ielm-output "*** " ielm-error-type " *** "))
(setq ielm-output (concat ielm-output ielm-result)))
- ;; There was no error, so shift the ::: values
- (setq ::: ::)
- (setq :: :)
- (setq : ielm-result))
+ ;; There was no error, so shift the *** values
+ (setq *** **)
+ (setq ** *)
+ (setq * ielm-result))
(setq ielm-output (concat ielm-output "\n"))))
(setq ielm-output (concat ielm-output ielm-prompt))
(comint-output-filter (ielm-process) ielm-output)))
;;; Major mode
+(put 'inferior-emacs-lisp-mode 'mode-class 'special)
+
(defun inferior-emacs-lisp-mode nil
"Major mode for interactively evaluating Emacs Lisp expressions.
Uses the interface provided by `comint-mode' (which see).
Inputs longer than one line are moved to the line following the
prompt (but see variable `ielm-dynamic-multiline-inputs').
-* \\[comint-dynamic-complete] completes Lisp symbols (or filenames, within strings),
+* \\[comint-dynamic-complete] completes Lisp symbols (or filenames, within strings),
or indents the line if there is nothing to complete.
-During evaluations, the values of the variables `:', `::', and `:::'
+During evaluations, the values of the variables `*', `**', and `***'
are the results of the previous, second previous and third previous
evaluations respectively.
(setq paragraph-start comint-prompt-regexp)
(setq comint-input-sender 'ielm-input-sender)
(setq comint-process-echoes nil)
- (setq comint-dynamic-complete-functions
+ (setq comint-dynamic-complete-functions
'(ielm-tab comint-replace-by-expanded-history ielm-complete-filename ielm-complete-symbol))
(setq comint-get-old-input 'ielm-get-old-input)
+ (make-local-variable 'comint-completion-addsuffix)
+ (setq comint-completion-addsuffix
+ (cons (char-to-string directory-sep-char) ""))
(setq major-mode 'inferior-emacs-lisp-mode)
(setq mode-name "IELM")
(make-local-variable 'ielm-working-buffer)
(setq ielm-working-buffer (current-buffer))
(setq indent-line-function 'ielm-indent-line)
+ (make-local-variable 'fill-paragraph-function)
+ (setq fill-paragraph-function 'lisp-fill-paragraph)
;; Value holders
- (setq : nil)
- (make-local-variable ':)
- (setq :: nil)
- (make-local-variable '::)
- (setq ::: nil)
- (make-local-variable ':::)
+ (setq * nil)
+ (make-local-variable '*)
+ (setq ** nil)
+ (make-local-variable '**)
+ (setq *** nil)
+ (make-local-variable '***)
+ (set (make-local-variable 'ielm-match-data) nil)
+
+ ;; font-lock support
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults
+ '(ielm-font-lock-keywords nil nil ((?: . "w") (?- . "w") (?* . "w"))))
;; A dummy process to keep comint happy. It will never get any input
(if (comint-check-proc (current-buffer)) nil
- (start-process "ielm" (current-buffer) "cat")
+ ;; Was cat, but on non-Unix platforms that might not exist, so
+ ;; use hexl instead, which is part of the Emacs distribution.
+ (start-process "ielm" (current-buffer) "hexl")
(process-kill-without-query (ielm-process))
(goto-char (point-max))
;; Add a silly header
;;; User command
+;;;###autoload (add-hook 'same-window-buffer-names "*ielm*")
+
;;;###autoload
(defun ielm nil
"Interactively evaluate Emacs Lisp expressions.
-Switches to the buffer *ielm*, or creates it if it does not exist."
+Switches to the buffer `*ielm*', or creates it if it does not exist."
(interactive)
- (if (comint-check-proc "*ielm*") nil
- (progn
+ (if (comint-check-proc "*ielm*")
+ nil
+ (save-excursion
(set-buffer (get-buffer-create "*ielm*"))
(inferior-emacs-lisp-mode)))
- (switch-to-buffer "*ielm*"))
+ (pop-to-buffer "*ielm*"))
+
+(provide 'ielm)
;;; ielm.el ends here