;;; eval-expr.el --- enhanced eval-expression command;; Copyright (C) 1991 Free Software Foundation, Inc.;; Copyright (C) 1991 Joe Wells;; Copyright (C) 1998 Noah S. Friedman;; Author: Noah Friedman <friedman@splode.com>;; Maintainer: friedman@splode.com;; Keywords: extensions;; Created: 1998-07-30;; $Id$;; This program is free software; you can redistribute it and/or modify;; it under the terms of the GNU General Public License as published by;; the Free Software Foundation; either version 2, or (at your option);; any later version.;;;; This program is distributed in the hope that it will be useful,;; but WITHOUT ANY WARRANTY; without even the implied warranty of;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the;; GNU General Public License for more details.;;;; You should have received a copy of the GNU General Public License;; along with this program; if not, you can either send email to this;; program's maintainer or write to: The Free Software Foundation,;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.;;; Commentary:;; Updates of this program may be available via the URL;; http://www.splode.com/~friedman/software/emacs-lisp/;; To use this package, put this in your .emacs:;;;; (require 'eval-expr);; (eval-expr-install);; Highlights:;;;; * When reading the Lisp object interactively from the minibuffer, the;; minibuffer uses the Emacs Lisp Mode syntax table. (Emacs 19.18 or;; later only.);;;; * If you type an incomplete or otherwise syntactically invalid;; expression (e.g. you forget a closing paren), you can fix your;; mistake without having to type it all over again.;;;; * Displays the result in a buffer if it is too big to fit in the echo;; area. This buffer is placed in Emacs Lisp Mode.;; (If you give a prefix arg, the result is placed in the current;; buffer instead of the echo area or a separate temporary buffer.);;;; * The variables `eval-expr-print-level' and `eval-expr-print-length';; can be used to constrain the attempt to print recursive data;; structures. These variables are independent of the global;; `print-level' and `print-length' variables so that eval-expression;; can be used more easily for debugging.;; This program is loosely based on an earlier implemention written by Joe;; Wells <jbw@cs.bu.edu> called eval-expression-fix.el (last revised;; 1991-10-12). That version was originally written for Emacs 18 and,;; while it worked with some quirky side effects in Emacs 19, created even;; more problems in Emacs 20 and didn't work in XEmacs at all.;;;; This rewrite should work in Emacs 19.18 or later, Emacs 20,;; and any version of XEmacs. It will not work in Emacs 18.;;; Code:;;;###autoload(defvareval-expr-error-message-delay3"*Amount of time, in seconds, to display in echo area before continuing.");;;###autoload(defvareval-expr-prompt"Eval: ""*Prompt used by eval-expr.");;;###autoload(defvareval-expr-honor-debug-on-errort"*If non-nil, do not trap evaluation errors.Instead, allow errors to throw user into the debugger, provideddebug-on-error specifies that the particular error is a debuggable condition.");;;###autoload(defvareval-expr-print-level(default-value'print-level)"*Like print-level, but affect results printed by `eval-expr' only.");;;###autoload(defvareval-expr-print-length(default-value'print-length)"*Like print-length, but affect results printed by `eval-expr' only.")(defvareval-expr-output-buffer-name"*Eval Expression Output*")(defvareval-expr-error-buffer-name"*Eval Expression Error*")(defvareval-expr-whitespace(mapcar'string-to-char'(" ""\t""\n")))(defalias'eval-expr-orig-commandnil);;;###autoload(defuneval-expr-install()"Replace standard eval-expression command with enhanced eval-expr."(interactive)(or(symbol-function'eval-expr-orig-command)(fset'eval-expr-orig-command(symbol-function'eval-expression)))(defalias'eval-expression'eval-expr))(defuneval-expr-uninstall()"Restore original, unenhanced eval-expression command."(interactive)(fset'eval-expression(symbol-function'eval-expr-orig-command)));;;###autoload(defuneval-expr(ee::expression&optionalee::insert-value)"Evaluate EXPRESSION and print value in minibuffer, temp, or current buffer.A temp output buffer is used if there is more than one line in theevaluated result.If invoked with a prefix arg, or second lisp argument EE::INSERT-VALUE isnon-nil, then insert final value into the current buffer at point.Value is also consed on to front of the variable `values'."(interactive(list(eval-expr-read-lisp-object-minibuffereval-expr-prompt)current-prefix-arg))(let*((ee::errornil)(ee::result(cond((andeval-expr-honor-debug-on-errordebug-on-error)(evalee::expression))(t(condition-caseee::err-data(evalee::expression)(error(setqee::erroree::err-data)))))))(cond(ee::error(eval-expr-error-messageee::errornilt)(beept))(ee::insert-value(eval-expr-print'prin1ee::result(current-buffer)))(t(setqvalues(consee::resultvalues))(eval-expr-display-messageeval-expr-output-buffer-name(function(lambda()(eval-expr-print'prin1ee::result))))))ee::result))(defuneval-expr-read-lisp-object-minibuffer(prompt&optionalinput)(or(nullinput)(setqinput(eval-expr-print'prin1-to-stringinput)))(let((minibuffer-setup-hookminibuffer-setup-hook)(retryt)(resultnil)(exprnil)(indexnil)(i0))(add-hook'minibuffer-setup-hook'eval-expr-minibuffer-setup)(whileretry(condition-caseerr-data(progn(setqinput(read-from-minibufferprompt(if(numberpindex)(consinput(1+index))input)(and(boundp'read-expression-map)read-expression-map)nil'read-expression-history))(setqindexnil)(setqresult(read-from-stringinput))(setqexpr(carresult))(setqindex(cdrresult))(setqiindex);; This mimics a useful test done in read_minbuf (which is;; called by Fread_from_minibuffer) when expflag is true. But;; this test doesn't happen when calling Fread_from_string;; directly as we've done here, so do it now in lisp.(while(<i(lengthinput))(or(memq(arefinputi)eval-expr-whitespace)(error"Trailing garbage following expression"))(setqi(1+i)))(setqretrynil))(error(eval-expr-error-messageerr-datat))))expr))(defuneval-expr-minibuffer-setup()(set-syntax-tableemacs-lisp-mode-syntax-table));;; Display routines(defuneval-expr-error-message(condition-data&optionalwaitpraw-error)(let((error(carcondition-data))(data(cdrcondition-data))(cursor-in-echo-areat)(error-strnil))(and(consperror)(null(cdrerror))(setqerror(carerror)))(and(conspdata)(null(cdrdata))(setqdata(cardata)))(and(symbolperror)(notraw-error)(setqerror-str(geterror'error-message)))(and(eval-expr-display-messageeval-expr-error-buffer-name(cond((nulldata)(format"Error: %s"(orerror-strerror)))((eqerror'error)(format"Error: %s"data))(error-str(format"%s: %s"error-strdata))(t(format"Error: %s; Data: %s"errordata))))waitp(sit-foreval-expr-error-message-delay))))(defuneval-expr-display-message(output-bufferthunk)(let*((buffer(generate-new-buffer" *"))(standard-outputbuffer)(echo-area-pt))(save-excursion(set-bufferbuffer)(cond((stringpthunk); this is a cheat(insertthunk))(t(funcallthunk)))(goto-char(point-min))(move-to-column(1-(frame-width)))(cond((and(eobp)(<(point)(window-width(minibuffer-window))))(message"%s"(buffer-substring(point-min)(point-max))))(t(setqecho-area-pnil)(with-output-to-temp-bufferoutput-buffer(save-excursion(set-bufferoutput-buffer)(or(eqmajor-mode'emacs-lisp-mode)(emacs-lisp-mode))(insert-bufferbuffer))))))(kill-bufferbuffer)echo-area-p))(put'eval-expr-display-message'lisp-indent-function1)(defuneval-expr-print(func&restargs)(let((print-leveleval-expr-print-level)(print-lengtheval-expr-print-length))(applyfuncargs)))(provide'eval-expr);;; eval-expr.el ends here.