1 |
;;; ielm.el --- interaction mode for Emacs Lisp |
;;; ielm.el --- interaction mode for Emacs Lisp |
2 |
|
|
3 |
;; Copyright (C) 1994 Free Software Foundation, Inc. |
;; Copyright (C) 1994, 2002, 2003 Free Software Foundation, Inc. |
4 |
|
|
5 |
;; Author: David Smith <maa036@lancaster.ac.uk> |
;; Author: David Smith <maa036@lancaster.ac.uk> |
6 |
;; Maintainer: FSF |
;; Maintainer: FSF |
110 |
(defvar ielm-match-data nil |
(defvar ielm-match-data nil |
111 |
"Match data saved at the end of last command.") |
"Match data saved at the end of last command.") |
112 |
|
|
113 |
|
(defvar *1 nil |
114 |
|
"During IELM evaluation, most recent value evaluated in IELM. |
115 |
|
Normally identical to `*'. However, if the working buffer is an IELM |
116 |
|
buffer, distinct from the process buffer, then `*' gives the value in |
117 |
|
the working buffer, `*1' the value in the process buffer. |
118 |
|
The intended value is only accessible during IELM evaluation.") |
119 |
|
|
120 |
|
(defvar *2 nil |
121 |
|
"During IELM evaluation, second-most-recent value evaluated in IELM. |
122 |
|
Normally identical to `**'. However, if the working buffer is an IELM |
123 |
|
buffer, distinct from the process buffer, then `**' gives the value in |
124 |
|
the working buffer, `*2' the value in the process buffer. |
125 |
|
The intended value is only accessible during IELM evaluation.") |
126 |
|
|
127 |
|
(defvar *3 nil |
128 |
|
"During IELM evaluation, third-most-recent value evaluated in IELM. |
129 |
|
Normally identical to `***'. However, if the working buffer is an IELM |
130 |
|
buffer, distinct from the process buffer, then `***' gives the value in |
131 |
|
the working buffer, `*3' the value in the process buffer. |
132 |
|
The intended value is only accessible during IELM evaluation.") |
133 |
|
|
134 |
;;; System variables |
;;; System variables |
135 |
|
|
136 |
(defvar ielm-working-buffer nil |
(defvar ielm-working-buffer nil |
281 |
"Return non-nil if STRING is all whitespace." |
"Return non-nil if STRING is all whitespace." |
282 |
(or (string= string "") (string-match "\\`[ \t\n]+\\'" string))) |
(or (string= string "") (string-match "\\`[ \t\n]+\\'" string))) |
283 |
|
|
|
(defun ielm-format-errors (errlist) |
|
|
(let ((result "")) |
|
|
(while errlist |
|
|
(setq result (concat result (prin1-to-string (car errlist)) ", ")) |
|
|
(setq errlist (cdr errlist))) |
|
|
(substring result 0 -2))) |
|
|
|
|
|
|
|
|
(defun ielm-format-error (err) |
|
|
;; Return a string form of the error ERR. |
|
|
(format "%s%s" |
|
|
(or (get (car err) 'error-message) "Peculiar error") |
|
|
(if (cdr err) |
|
|
(format ": %s" (ielm-format-errors (cdr err))) |
|
|
""))) |
|
|
|
|
284 |
;;; Evaluation |
;;; Evaluation |
285 |
|
|
286 |
(defun ielm-eval-input (ielm-string) |
(defun ielm-eval-input (ielm-string) |
311 |
(setq rout (read-from-string ielm-string)) |
(setq rout (read-from-string ielm-string)) |
312 |
(setq ielm-form (car rout)) |
(setq ielm-form (car rout)) |
313 |
(setq ielm-pos (cdr rout))) |
(setq ielm-pos (cdr rout))) |
314 |
(error (setq ielm-result (ielm-format-error err)) |
(error (setq ielm-result (error-message-string err)) |
315 |
(setq ielm-error-type "Read error"))) |
(setq ielm-error-type "Read error"))) |
316 |
(if ielm-error-type nil |
(if ielm-error-type nil |
317 |
;; Make sure working buffer has not been killed |
;; Make sure working buffer has not been killed |
320 |
ielm-error-type "IELM Error" |
ielm-error-type "IELM Error" |
321 |
ielm-wbuf (current-buffer)) |
ielm-wbuf (current-buffer)) |
322 |
(if (ielm-is-whitespace (substring ielm-string ielm-pos)) |
(if (ielm-is-whitespace (substring ielm-string ielm-pos)) |
323 |
;; need this awful let convolution to work around |
;; To correctly handle the ielm-local variables *, |
324 |
;; an Emacs bug involving local vbls and let binding |
;; ** and ***, we need a temporary buffer to be |
325 |
(let ((*save *) |
;; current at entry to the inner of the next two let |
326 |
(**save **) |
;; forms. We need another temporary buffer to exit |
327 |
(***save ***)) |
;; that same let. To avoid problems, neither of |
328 |
|
;; these buffers should be alive during the |
329 |
|
;; evaluation of ielm-form. |
330 |
|
(let ((*1 *) |
331 |
|
(*2 **) |
332 |
|
(*3 ***) |
333 |
|
ielm-temp-buffer) |
334 |
(set-match-data ielm-match-data) |
(set-match-data ielm-match-data) |
335 |
(save-excursion |
(save-excursion |
336 |
(set-buffer ielm-working-buffer) |
(with-temp-buffer |
337 |
(condition-case err |
(condition-case err |
338 |
(let ((* *save) |
(unwind-protect |
339 |
(** **save) |
;; The next let form creates default |
340 |
(*** ***save) |
;; bindings for *, ** and ***. But |
341 |
(ielm-obuf (current-buffer))) |
;; these default bindings are |
342 |
(setq ielm-result (eval ielm-form)) |
;; identical to the ielm-local |
343 |
(setq ielm-wbuf (current-buffer)) |
;; bindings. Hence, during the |
344 |
;; The eval may have changed current-buffer; |
;; evaluation of ielm-form, the |
345 |
;; need to set it back here to avoid a bug |
;; ielm-local values are going to be |
346 |
;; in let. Don't want to use save-excursion |
;; used in all buffers except for |
347 |
;; because we want to allow changes in point. |
;; other ielm buffers, which override |
348 |
(set-buffer ielm-obuf)) |
;; them. Normally, the variables *1, |
349 |
(error (setq ielm-result (ielm-format-error err)) |
;; *2 and *3 also have default |
350 |
(setq ielm-error-type "Eval error")) |
;; bindings, which are not overridden. |
351 |
(quit (setq ielm-result "Quit during evaluation") |
(let ((* *1) |
352 |
(setq ielm-error-type "Eval error")))) |
(** *2) |
353 |
|
(*** *3)) |
354 |
|
(kill-buffer (current-buffer)) |
355 |
|
(set-buffer ielm-wbuf) |
356 |
|
(setq ielm-result (eval ielm-form)) |
357 |
|
(setq ielm-wbuf (current-buffer)) |
358 |
|
(setq |
359 |
|
ielm-temp-buffer |
360 |
|
(generate-new-buffer " *ielm-temp*")) |
361 |
|
(set-buffer ielm-temp-buffer)) |
362 |
|
(when ielm-temp-buffer |
363 |
|
(kill-buffer ielm-temp-buffer))) |
364 |
|
(error (setq ielm-result (error-message-string err)) |
365 |
|
(setq ielm-error-type "Eval error")) |
366 |
|
(quit (setq ielm-result "Quit during evaluation") |
367 |
|
(setq ielm-error-type "Eval error"))))) |
368 |
(setq ielm-match-data (match-data))) |
(setq ielm-match-data (match-data))) |
369 |
(setq ielm-error-type "IELM error") |
(setq ielm-error-type "IELM error") |
370 |
(setq ielm-result "More than one sexp in input")))) |
(setq ielm-result "More than one sexp in input")))) |
419 |
"Major mode for interactively evaluating Emacs Lisp expressions. |
"Major mode for interactively evaluating Emacs Lisp expressions. |
420 |
Uses the interface provided by `comint-mode' (which see). |
Uses the interface provided by `comint-mode' (which see). |
421 |
|
|
422 |
* \\<ielm-map>\\[ielm-send-input] evaluates the sexp following the prompt. There must be at most |
* \\<ielm-map>\\[ielm-send-input] evaluates the sexp following the prompt. There must be at most |
423 |
one top-level sexp per prompt. |
one top level sexp per prompt. |
424 |
|
|
425 |
* \\[ielm-return] inserts a newline and indents, or evaluates a |
* \\[ielm-return] inserts a newline and indents, or evaluates a |
426 |
complete expression (but see variable `ielm-dynamic-return'). |
complete expression (but see variable `ielm-dynamic-return'). |
430 |
* \\[comint-dynamic-complete] completes Lisp symbols (or filenames, within strings), |
* \\[comint-dynamic-complete] completes Lisp symbols (or filenames, within strings), |
431 |
or indents the line if there is nothing to complete. |
or indents the line if there is nothing to complete. |
432 |
|
|
|
During evaluations, the values of the variables `*', `**', and `***' |
|
|
are the results of the previous, second previous and third previous |
|
|
evaluations respectively. |
|
|
|
|
433 |
The current working buffer may be changed (with a call to |
The current working buffer may be changed (with a call to |
434 |
`set-buffer', or with \\[ielm-change-working-buffer]), and its value |
`set-buffer', or with \\[ielm-change-working-buffer]), and its value |
435 |
is preserved between successive evaluations. In this way, expressions |
is preserved between successive evaluations. In this way, expressions |
437 |
Display the name of the working buffer with \\[ielm-print-working-buffer], |
Display the name of the working buffer with \\[ielm-print-working-buffer], |
438 |
or the buffer itself with \\[ielm-display-working-buffer]. |
or the buffer itself with \\[ielm-display-working-buffer]. |
439 |
|
|
440 |
|
During evaluations, the values of the variables `*', `**', and `***' |
441 |
|
are the results of the previous, second previous and third previous |
442 |
|
evaluations respectively. If the working buffer is another IELM |
443 |
|
buffer, then the values in the working buffer are used. The variables |
444 |
|
`*1', `*2' and `*3', yield the process buffer values. |
445 |
|
|
446 |
Expressions evaluated by IELM are not subject to `debug-on-quit' or |
Expressions evaluated by IELM are not subject to `debug-on-quit' or |
447 |
`debug-on-error'. |
`debug-on-error'. |
448 |
|
|
462 |
(setq paragraph-start comint-prompt-regexp) |
(setq paragraph-start comint-prompt-regexp) |
463 |
(setq comint-input-sender 'ielm-input-sender) |
(setq comint-input-sender 'ielm-input-sender) |
464 |
(setq comint-process-echoes nil) |
(setq comint-process-echoes nil) |
465 |
|
(make-local-variable 'comint-dynamic-complete-functions) |
466 |
(setq comint-dynamic-complete-functions |
(setq comint-dynamic-complete-functions |
467 |
'(ielm-tab comint-replace-by-expanded-history ielm-complete-filename ielm-complete-symbol)) |
'(ielm-tab comint-replace-by-expanded-history ielm-complete-filename ielm-complete-symbol)) |
468 |
(setq comint-get-old-input 'ielm-get-old-input) |
(setq comint-get-old-input 'ielm-get-old-input) |
483 |
(setq fill-paragraph-function 'lisp-fill-paragraph) |
(setq fill-paragraph-function 'lisp-fill-paragraph) |
484 |
|
|
485 |
;; Value holders |
;; Value holders |
|
(setq * nil) |
|
486 |
(make-local-variable '*) |
(make-local-variable '*) |
487 |
(setq ** nil) |
(setq * nil) |
488 |
(make-local-variable '**) |
(make-local-variable '**) |
489 |
(setq *** nil) |
(setq ** nil) |
490 |
(make-local-variable '***) |
(make-local-variable '***) |
491 |
|
(setq *** nil) |
492 |
(set (make-local-variable 'ielm-match-data) nil) |
(set (make-local-variable 'ielm-match-data) nil) |
493 |
|
|
494 |
;; font-lock support |
;; font-lock support |
497 |
'(ielm-font-lock-keywords nil nil ((?: . "w") (?- . "w") (?* . "w")))) |
'(ielm-font-lock-keywords nil nil ((?: . "w") (?- . "w") (?* . "w")))) |
498 |
|
|
499 |
;; A dummy process to keep comint happy. It will never get any input |
;; A dummy process to keep comint happy. It will never get any input |
500 |
(if (comint-check-proc (current-buffer)) nil |
(unless (comint-check-proc (current-buffer)) |
501 |
;; Was cat, but on non-Unix platforms that might not exist, so |
;; Was cat, but on non-Unix platforms that might not exist, so |
502 |
;; use hexl instead, which is part of the Emacs distribution. |
;; use hexl instead, which is part of the Emacs distribution. |
503 |
(start-process "ielm" (current-buffer) "hexl") |
(condition-case nil |
504 |
|
(start-process "ielm" (current-buffer) "hexl") |
505 |
|
(file-error (start-process "ielm" (current-buffer) "cat"))) |
506 |
(process-kill-without-query (ielm-process)) |
(process-kill-without-query (ielm-process)) |
507 |
(goto-char (point-max)) |
(goto-char (point-max)) |
508 |
|
|
509 |
|
;; Lisp output can include raw characters that confuse comint's |
510 |
|
;; carriage control code. |
511 |
|
(set (make-local-variable 'comint-inhibit-carriage-motion) t) |
512 |
|
|
513 |
;; Add a silly header |
;; Add a silly header |
514 |
(insert ielm-header) |
(insert ielm-header) |
515 |
(ielm-set-pm (point-max)) |
(ielm-set-pm (point-max)) |
516 |
|
(unless comint-use-prompt-regexp-instead-of-fields |
517 |
|
(add-text-properties |
518 |
|
(point-min) (point-max) |
519 |
|
'(rear-nonsticky t field output inhibit-line-move-field-capture t))) |
520 |
(comint-output-filter (ielm-process) ielm-prompt) |
(comint-output-filter (ielm-process) ielm-prompt) |
521 |
(set-marker comint-last-input-start (ielm-pm)) |
(set-marker comint-last-input-start (ielm-pm)) |
522 |
(set-process-filter (get-buffer-process (current-buffer)) 'comint-output-filter)) |
(set-process-filter (get-buffer-process (current-buffer)) 'comint-output-filter)) |
523 |
|
|
524 |
(run-hooks 'ielm-mode-hook)) |
(run-hooks 'ielm-mode-hook)) |
525 |
|
|
526 |
(defun ielm-get-old-input nil |
(defun ielm-get-old-input nil |