root/trunk/lisp/calculator.el

Revision 4220, 72.6 kB (checked in by miyoshi, 8 months ago)

Sync up with Emacs22.2.

  • Property svn:eol-style set to LF
Line 
1 ;;; calculator.el --- a [not so] simple calculator for Emacs
2
3 ;; Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004,
4 ;;   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5
6 ;; Author: Eli Barzilay <eli@barzilay.org>
7 ;; Keywords: tools, convenience
8 ;; Time-stamp: <2006-02-06 13:36:00 ttn>
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify it
13 ;; under the terms of the GNU General Public License as published by the
14 ;; Free Software Foundation; either version 3, or (at your option) any
15 ;; later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 ;; MA 02110-1301, USA.
26
27 ;;;=====================================================================
28 ;;; Commentary:
29 ;;
30 ;; A calculator for Emacs.
31 ;; Why should you reach for your mouse to get xcalc (calc.exe, gcalc or
32 ;; whatever), when you have Emacs running already?
33 ;;
34 ;; If this is not part of your Emacs distribution, then simply bind
35 ;; `calculator' to a key and make it an autoloaded function, e.g.:
36 ;;   (autoload 'calculator "calculator"
37 ;;     "Run the Emacs calculator." t)
38 ;;   (global-set-key [(control return)] 'calculator)
39 ;;
40 ;; Written by Eli Barzilay: Maze is Life!  eli@barzilay.org
41 ;;                                         http://www.barzilay.org/
42 ;;
43 ;; For latest version, check
44 ;;     http://www.barzilay.org/misc/calculator.el
45 ;;
46
47 ;;; History:
48 ;; I hate history.
49
50 (eval-and-compile
51   (if (fboundp 'defgroup) nil
52     (defmacro defgroup (&rest forms) nil)
53     (defmacro defcustom (s v d &rest r) (list 'defvar s v d))))
54
55 ;;;=====================================================================
56 ;;; Customization:
57
58 (defgroup calculator nil
59   "Simple Emacs calculator."
60   :prefix "calculator"
61   :version "21.1"
62   :group 'tools
63   :group 'convenience)
64
65 (defcustom calculator-electric-mode nil
66   "*Run `calculator' electrically, in the echo area.
67 Electric mode saves some place but changes the way you interact with the
68 calculator."
69   :type  'boolean
70   :group 'calculator)
71
72 (defcustom calculator-use-menu t
73   "*Make `calculator' create a menu.
74 Note that this requires easymenu.  Must be set before loading."
75   :type  'boolean
76   :group 'calculator)
77
78 (defcustom calculator-bind-escape nil
79   "*If non-nil, set escape to exit the calculator."
80   :type  'boolean
81   :group 'calculator)
82
83 (defcustom calculator-unary-style 'postfix
84   "*Value is either 'prefix or 'postfix.
85 This determines the default behavior of unary operators."
86   :type    '(choice (const prefix) (const postfix))
87   :group   'calculator)
88
89 (defcustom calculator-prompt "Calc=%s> "
90   "*The prompt used by the Emacs calculator.
91 It should contain a \"%s\" somewhere that will indicate the i/o radixes;
92 this will be a two-character string as described in the documentation
93 for `calculator-mode'."
94   :type  'string
95   :group 'calculator)
96
97 (defcustom calculator-number-digits 3
98   "*The calculator's number of digits used for standard display.
99 Used by the `calculator-standard-display' function - it will use the
100 format string \"%.NC\" where this number is N and C is a character given
101 at runtime."
102   :type  'integer
103   :group 'calculator)
104
105 (defcustom calculator-radix-grouping-mode t
106   "*Use digit grouping in radix output mode.
107 If this is set, chunks of `calculator-radix-grouping-digits' characters
108 will be separated by `calculator-radix-grouping-separator' when in radix
109 output mode is active (determined by `calculator-output-radix')."
110   :type  'boolean
111   :group 'calculator)
112
113 (defcustom calculator-radix-grouping-digits 4
114   "*The number of digits used for grouping display in radix modes.
115 See `calculator-radix-grouping-mode'."
116   :type  'integer
117   :group 'calculator)
118
119 (defcustom calculator-radix-grouping-separator "'"
120   "*The separator used in radix grouping display.
121 See `calculator-radix-grouping-mode'."
122   :type  'string
123   :group 'calculator)
124
125 (defcustom calculator-remove-zeros t
126   "*Non-nil value means delete all redundant zero decimal digits.
127 If this value is not t, and not nil, redundant zeros are removed except
128 for one and if it is nil, nothing is removed.
129 Used by the `calculator-remove-zeros' function."
130   :type  '(choice (const t) (const leave-decimal) (const nil))
131   :group 'calculator)
132
133 (defcustom calculator-displayer '(std ?n)
134   "*A displayer specification for numerical values.
135 This is the displayer used to show all numbers in an expression.  Result
136 values will be displayed according to the first element of
137 `calculator-displayers'.
138
139 The displayer is a symbol, a string or an expression.  A symbol should
140 be the name of a one-argument function, a string is used with a single
141 argument and an expression will be evaluated with the variable `num'
142 bound to whatever should be displayed.  If it is a function symbol, it
143 should be able to handle special symbol arguments, currently 'left and
144 'right which will be sent by special keys to modify display parameters
145 associated with the displayer function (for example to change the number
146 of digits displayed).
147
148 An exception to the above is the case of the list (std C) where C is a
149 character, in this case the `calculator-standard-displayer' function
150 will be used with this character for a format string."
151   :group 'calculator)
152
153 (defcustom calculator-displayers
154   '(((std ?n) "Standard display, decimal point or scientific")
155     (calculator-eng-display "Eng display")
156     ((std ?f) "Standard display, decimal point")
157     ((std ?e) "Standard display, scientific")
158     ("%S"     "Emacs printer"))
159   "*A list of displayers.
160 Each element is a list of a displayer and a description string.  The
161 first element is the one which is currently used, this is for the display
162 of result values not values in expressions.  A displayer specification
163 is the same as the values that can be stored in `calculator-displayer'.
164
165 `calculator-rotate-displayer' rotates this list."
166   :type  'sexp
167   :group 'calculator)
168
169 (defcustom calculator-paste-decimals t
170   "*If non-nil, convert pasted integers so they have a decimal point.
171 This makes it possible to paste big integers since they will be read as
172 floats, otherwise the Emacs reader will fail on them."
173   :type  'boolean
174   :group 'calculator)
175
176 (defcustom calculator-copy-displayer nil
177   "*If non-nil, this is any value that can be used for
178 `calculator-displayer', to format a string before copying it with
179 `calculator-copy'.  If nil, then `calculator-displayer's normal value is
180 used."
181   :type  'boolean
182   :group 'calculator)
183
184 (defcustom calculator-2s-complement nil
185   "*If non-nil, show negative numbers in 2s complement in radix modes.
186 Otherwise show as a negative number."
187   :type  'boolean
188   :group 'calculator)
189
190 (defcustom calculator-mode-hook nil
191   "*List of hook functions for `calculator-mode' to run.
192 Note: if `calculator-electric-mode' is on, then this hook will get
193 activated in the minibuffer - in that case it should not do much more
194 than local key settings and other effects that will change things
195 outside the scope of calculator related code."
196   :type  'hook
197   :group 'calculator)
198
199 (defcustom calculator-user-registers nil
200   "*An association list of user-defined register bindings.
201 Each element in this list is a list of a character and a number that
202 will be stored in that character's register.
203
204 For example, use this to define the golden ratio number:
205   (setq calculator-user-registers '((?g .  1.61803398875)))
206 before you load calculator."
207   :type  '(repeat (cons character number))
208   :set   '(lambda (_ val)
209             (and (boundp 'calculator-registers)
210                  (setq calculator-registers
211                        (append val calculator-registers)))
212             (setq calculator-user-registers val))
213   :group 'calculator)
214
215 (defcustom calculator-user-operators nil
216   "*A list of additional operators.
217 This is a list in the same format as specified in the documentation for
218 `calculator-operators', that you can use to bind additional calculator
219 operators.  It is probably not a good idea to modify this value with
220 `customize' since it is too complex...
221
222 Examples:
223
224 * A very simple one, adding a postfix \"x-to-y\" conversion keys, using
225   t as a prefix key:
226
227   (setq calculator-user-operators
228         '((\"tf\" cl-to-fr (+ 32 (/ (* X 9) 5)) 1)
229           (\"tc\" fr-to-cl (/ (* (- X 32) 5) 9) 1)
230           (\"tp\" kg-to-lb (/ X 0.453592)       1)
231           (\"tk\" lb-to-kg (* X 0.453592)       1)
232           (\"tF\" mt-to-ft (/ X 0.3048)         1)
233           (\"tM\" ft-to-mt (* X 0.3048)         1)))
234
235 * Using a function-like form is very simple, X for an argument (Y the
236   second in case of a binary operator), TX is a truncated version of X
237   and F does a recursive call, Here is a [very inefficient] Fibonacci
238   number calculation:
239
240   (add-to-list 'calculator-user-operators
241                '(\"F\" fib (if (<= TX 1)
242                          1
243                          (+ (F (- TX 1)) (F (- TX 2)))) 0))
244
245   Note that this will be either postfix or prefix, according to
246   `calculator-unary-style'."
247   :type  '(repeat (list string symbol sexp integer integer))
248   :group 'calculator)
249
250 ;;;=====================================================================
251 ;;; Code:
252
253 ;;;---------------------------------------------------------------------
254 ;;; Variables
255
256 (defvar calculator-initial-operators
257   '(;; "+"/"-" have keybindings of themselves, not calculator-ops
258     ("=" =     identity        1 -1)
259     (nobind "+" +  +           2  4)
260     (nobind "-" -  -           2  4)
261     (nobind "+" +  +          -1  9)
262     (nobind "-" -  -          -1  9)
263     ("(" \(    identity       -1 -1)
264     (")" \)    identity       +1 10)
265     ;; normal keys
266     ("|"  or   (logior TX TY)  2  2)
267     ("#"  xor  (logxor TX TY)  2  2)
268     ("&"  and  (logand TX TY)  2  3)
269     ("*"  *    *               2  5)
270     ("/"  /    /               2  5)
271     ("\\" div  (/ TX TY)       2  5)
272     ("%"  rem  (% TX TY)       2  5)
273     ("L"  log  log             2  6)
274     ("S"  sin  (sin DX)        x  6)
275     ("C"  cos  (cos DX)        x  6)
276     ("T"  tan  (tan DX)        x  6)
277     ("IS" asin (D (asin X))    x  6)
278     ("IC" acos (D (acos X))    x  6)
279     ("IT" atan (D (atan X))    x  6)
280     ("Q"  sqrt sqrt            x  7)
281     ("^"  ^    expt            2  7)
282     ("!"  !    calculator-fact x  7)
283     (";"  1/   (/ 1 X)         1  7)
284     ("_"  -    -               1  8)
285     ("~"  ~    (lognot TX)     x  8)
286     (">"  repR calculator-repR 1  8)
287     ("<"  repL calculator-repL 1  8)
288     ("v"  avg  (/ (apply '+ L) (length L)) 0 8)
289     ("l"  tot  (apply '+ L)    0 8)
290     )
291   "A list of initial operators.
292 This is a list in the same format as `calculator-operators'.  Whenever
293 `calculator' starts, it looks at the value of this variable, and if it
294 is not empty, its contents is prepended to `calculator-operators' and
295 the appropriate key bindings are made.
296
297 This variable is then reset to nil.  Don't use this if you want to add
298 user-defined operators, use `calculator-user-operators' instead.")
299
300 (defvar calculator-operators nil
301   "The calculator operators, each a list with:
302
303 1. The key that is bound to for this operation (usually a string);
304
305 2. The displayed symbol for this function;
306
307 3. The function symbol, or a form that uses the variables `X' and `Y',
308    (if it is a binary operator), `TX' and `TY' (truncated integer
309    versions), `DX' (converted to radians if degrees mode is on), `D'
310    (function for converting radians to degrees if deg mode is on), `L'
311    (list of saved values), `F' (function for recursive iteration calls)
312    and evaluates to the function value - these variables are capital;
313
314 4. The function's arity, optional, one of: 2 => binary, -1 => prefix
315    unary, +1 => postfix unary, 0 => a 0-arg operator func, non-number =>
316    postfix/prefix as determined by `calculator-unary-style' (the
317    default);
318
319 5. The function's precedence - should be in the range of 1 (lowest) to
320    9 (highest) (optional, defaults to 1);
321
322 It it possible have a unary prefix version of a binary operator if it
323 comes later in this list.  If the list begins with the symbol 'nobind,
324 then no key binding will take place - this is only useful for predefined
325 keys.
326
327 Use `calculator-user-operators' to add operators to this list, see its
328 documentation for an example.")
329
330 (defvar calculator-stack nil
331   "Stack contents - operations and operands.")
332
333 (defvar calculator-curnum nil
334   "Current number being entered (as a string).")
335
336 (defvar calculator-stack-display nil
337   "Cons of the stack and its string representation.")
338
339 (defvar calculator-char-radix
340   '((?D . nil) (?B . bin) (?O . oct) (?H . hex) (?X . hex))
341   "A table to convert input characters to corresponding radix symbols.")
342
343 (defvar calculator-output-radix nil
344   "The mode for display, one of: nil (decimal), 'bin, 'oct or 'hex.")
345
346 (defvar calculator-input-radix nil
347   "The mode for input, one of: nil (decimal), 'bin, 'oct or 'hex.")
348
349 (defvar calculator-deg nil
350   "Non-nil if trig functions operate on degrees instead of radians.")
351
352 (defvar calculator-saved-list nil
353   "A list of saved values collected.")
354
355 (defvar calculator-saved-ptr 0
356   "The pointer to the current saved number.")
357
358 (defvar calculator-add-saved nil
359   "Bound to t when a value should be added to the saved-list.")
360
361 (defvar calculator-display-fragile nil
362   "When non-nil, we see something that the next digit should replace.")
363
364 (defvar calculator-buffer nil
365   "The current calculator buffer.")
366
367 (defvar calculator-eng-extra nil
368   "Internal value used by `calculator-eng-display'.")
369
370 (defvar calculator-eng-tmp-show nil
371   "Internal value used by `calculator-eng-display'.")
372
373 (defvar calculator-last-opXY nil
374   "The last binary operation and its arguments.
375 Used for repeating operations in calculator-repR/L.")
376
377 (defvar calculator-registers ; use user-bindings first
378   (append calculator-user-registers (list (cons ?e e) (cons ?p pi)))
379   "The association list of calculator register values.")
380
381 (defvar calculator-saved-global-map nil
382   "Saved global key map.")
383
384 (defvar calculator-restart-other-mode nil
385   "Used to hack restarting with the electric mode changed.")
386
387 ;;;---------------------------------------------------------------------
388 ;;; Key bindings
389
390 (defvar calculator-mode-map nil
391   "The calculator key map.")
392
393 (or calculator-mode-map
394   (let ((map (make-sparse-keymap)))
395     (suppress-keymap map t)
396     (define-key map "i" nil)
397     (define-key map "o" nil)
398     (let ((p
399            '((calculator-open-paren  "[")
400              (calculator-close-paren "]")
401              (calculator-op-or-exp   "+" "-" [kp-add] [kp-subtract])
402              (calculator-digit       "0" "1" "2" "3" "4" "5" "6" "7" "8"
403                                      "9" "a" "b" "c" "d" "f"
404                                      [kp-0] [kp-1] [kp-2] [kp-3] [kp-4]
405                                      [kp-5] [kp-6] [kp-7] [kp-8] [kp-9])
406              (calculator-op          [kp-divide] [kp-multiply])
407              (calculator-decimal     "." [kp-decimal])
408              (calculator-exp         "e")
409              (calculator-dec/deg-mode "D")
410              (calculator-set-register "s")
411              (calculator-get-register "g")
412              (calculator-radix-mode        "H" "X" "O" "B")
413              (calculator-radix-input-mode  "id" "ih" "ix" "io" "ib"
414                                            "iD" "iH" "iX" "iO" "iB")
415              (calculator-radix-output-mode "od" "oh" "ox" "oo" "ob"
416                                            "oD" "oH" "oX" "oO" "oB")
417              (calculator-rotate-displayer      "'")
418              (calculator-rotate-displayer-back "\"")
419              (calculator-displayer-prev        "{")
420              (calculator-displayer-next        "}")
421              (calculator-saved-up      [up] [?\C-p])
422              (calculator-saved-down    [down] [?\C-n])
423              (calculator-quit          "q" [?\C-g])
424              (calculator-enter         [enter] [linefeed] [kp-enter]
425                                        [return] [?\r] [?\n])
426              (calculator-save-on-list  " " [space])
427              (calculator-clear-saved   [?\C-c] [(control delete)])
428              (calculator-save-and-quit [(control return)]
429                                        [(control kp-enter)])
430              (calculator-paste         [insert] [(shift insert)]
431                                        [paste] [mouse-2] [?\C-y])
432              (calculator-clear         [delete] [?\C-?] [?\C-d])
433              (calculator-help          [?h] [??] [f1] [help])
434              (calculator-copy          [(control insert)] [copy])
435              (calculator-backspace     [backspace])
436              )))
437       (while p
438         ;; reverse the keys so first defs come last - makes the more
439         ;; sensible bindings visible in the menu
440         (let ((func (car (car p))) (keys (reverse (cdr (car p)))))
441           (while keys
442             (define-key map (car keys) func)
443             (setq keys (cdr keys))))
444         (setq p (cdr p))))
445     (if calculator-bind-escape
446       (progn (define-key map [?\e] 'calculator-quit)
447              (define-key map [escape] 'calculator-quit))
448       (define-key map [?\e ?\e ?\e] 'calculator-quit))
449     ;; make C-h work in text-mode
450     (or window-system (define-key map [?\C-h] 'calculator-backspace))
451     ;; set up a menu
452     (if (and calculator-use-menu (not (boundp 'calculator-menu)))
453       (let ((radix-selectors
454              (mapcar (lambda (x)
455                        `([,(nth 0 x)
456                           (calculator-radix-mode ,(nth 2 x))
457                           :style radio
458                           :keys ,(nth 2 x)
459                           :selected
460                           (and
461                            (eq calculator-input-radix ',(nth 1 x))
462                            (eq calculator-output-radix ',(nth 1 x)))]
463                          [,(concat (nth 0 x) " Input")
464                           (calculator-radix-input-mode ,(nth 2 x))
465                           :keys ,(concat "i" (downcase (nth 2 x)))
466                           :style radio
467                           :selected
468                           (eq calculator-input-radix ',(nth 1 x))]
469                          [,(concat (nth 0 x) " Output")
470                           (calculator-radix-output-mode ,(nth 2 x))
471                           :keys ,(concat "o" (downcase (nth 2 x)))
472                           :style radio
473                           :selected
474                           (eq calculator-output-radix ',(nth 1 x))]))
475                      '(("Decimal"     nil "D")
476                        ("Binary"      bin "B")
477                        ("Octal"       oct "O")
478                        ("Hexadecimal" hex "H"))))
479             (op '(lambda (name key)
480                         `[,name (calculator-op ,key) :keys ,key])))
481         (easy-menu-define
482          calculator-menu map "Calculator menu."
483          `("Calculator"
484            ["Help"
485             (let ((last-command 'calculator-help)) (calculator-help))
486             :keys "?"]
487            "---"
488            ["Copy"  calculator-copy]
489            ["Paste" calculator-paste]
490            "---"
491            ["Electric mode"
492             (progn (calculator-quit)
493                    (setq calculator-restart-other-mode t)
494                    (run-with-timer 0.1 nil '(lambda () (message nil)))
495                    ;; the message from the menu will be visible,
496                    ;; couldn't make it go away...
497                    (calculator))
498             :active (not calculator-electric-mode)]
499            ["Normal mode"
500             (progn (setq calculator-restart-other-mode t)
501                    (calculator-quit))
502             :active calculator-electric-mode]
503            "---"
504            ("Functions"
505             ,(funcall op "Repeat-right" ">")
506             ,(funcall op "Repeat-left"  "<")
507             "------General------"
508             ,(funcall op "Reciprocal"   ";")
509             ,(funcall op "Log"          "L")
510             ,(funcall op "Square-root"  "Q")
511             ,(funcall op "Factorial"    "!")
512             "------Trigonometric------"
513             ,(funcall op "Sinus"        "S")
514             ,(funcall op "Cosine"       "C")
515             ,(funcall op "Tangent"      "T")
516             ,(funcall op "Inv-Sinus"    "IS")
517             ,(funcall op "Inv-Cosine"   "IC")
518             ,(funcall op "Inv-Tangent"  "IT")
519             "------Bitwise------"
520             ,(funcall op "Or"           "|")
521             ,(funcall op "Xor"          "#")
522             ,(funcall op "And"          "&")
523             ,(funcall op "Not"          "~"))
524            ("Saved List"
525             ["Eval+Save"      calculator-save-on-list]
526             ["Prev number"    calculator-saved-up]
527             ["Next number"    calculator-saved-down]
528             ["Delete current" calculator-clear
529              :active (and calculator-display-fragile
530                           calculator-saved-list
531                           (= (car calculator-stack)
532                              (nth calculator-saved-ptr
533                                   calculator-saved-list)))]
534             ["Delete all" calculator-clear-saved]
535             "---"
536             ,(funcall op "List-total"   "l")
537             ,(funcall op "List-average" "v"))
538            ("Registers"
539             ["Get register" calculator-get-register]
540             ["Set register" calculator-set-register])
541            ("Modes"
542             ["Radians"
543              (progn
544                (and (or calculator-input-radix calculator-output-radix)
545                     (calculator-radix-mode "D"))
546                (and calculator-deg (calculator-dec/deg-mode)))
547              :keys "D"
548              :style radio
549              :selected (not (or calculator-input-radix
550                                 calculator-output-radix
551                                 calculator-deg))]
552             ["Degrees"
553              (progn
554                (and (or calculator-input-radix calculator-output-radix)
555                     (calculator-radix-mode "D"))
556                (or calculator-deg (calculator-dec/deg-mode)))
557              :keys "D"
558              :style radio
559              :selected (and calculator-deg
560                             (not (or calculator-input-radix
561                                      calculator-output-radix)))]
562             "---"
563             ,@(mapcar 'car radix-selectors)
564             ("Separate I/O"
565              ,@(mapcar (lambda (x) (nth 1 x)) radix-selectors)
566              "---"
567              ,@(mapcar (lambda (x) (nth 2 x)) radix-selectors)))
568            ("Decimal Display"
569             ,@(mapcar (lambda (d)
570                         (vector (cadr d)
571                                 ;; Note: inserts actual object here
572                                 `(calculator-rotate-displayer ',d)))
573                       calculator-displayers)
574             "---"
575             ["Change Prev Display" calculator-displayer-prev]
576             ["Change Next Display" calculator-displayer-next])
577            "---"
578            ["Copy+Quit" calculator-save-and-quit]
579            ["Quit"      calculator-quit]))))
580     (setq calculator-mode-map map)))
581
582 ;;;---------------------------------------------------------------------
583 ;;; Startup and mode stuff
584
585 (defun calculator-mode ()
586   ;; this help is also used as the major help screen
587   "A [not so] simple calculator for Emacs.
588
589 This calculator is used in the same way as other popular calculators
590 like xcalc or calc.exe - but using an Emacs interface.
591
592 Expressions are entered using normal infix notation, parens are used as
593 normal.  Unary functions are usually postfix, but some depends on the
594 value of `calculator-unary-style' (if the style for an operator below is
595 specified, then it is fixed, otherwise it depends on this variable).
596 `+' and `-' can be used as either binary operators or prefix unary
597 operators.  Numbers can be entered with exponential notation using `e',
598 except when using a non-decimal radix mode for input (in this case `e'
599 will be the hexadecimal digit).
600
601 Here are the editing keys:
602 * `RET' `='      evaluate the current expression
603 * `C-insert'     copy the whole current expression to the `kill-ring'
604 * `C-return'     evaluate, save result the `kill-ring' and exit
605 * `insert'       paste a number if the one was copied (normally)
606 * `delete' `C-d' clear last argument or whole expression (hit twice)
607 * `backspace'    delete a digit or a previous expression element
608 * `h' `?'        pop-up a quick reference help
609 * `ESC' `q'      exit (`ESC' can be used if `calculator-bind-escape' is
610                  non-nil, otherwise use three consecutive `ESC's)
611
612 These operators are pre-defined:
613 * `+' `-' `*' `/' the common binary operators
614 * `\\' `%'         integer division and reminder
615 * `_' `;'         postfix unary negation and reciprocal
616 * `^' `L'         binary operators for x^y and log(x) in base y
617 * `Q' `!'         unary square root and factorial
618 * `S' `C' `T'     unary trigonometric operators - sin, cos and tan
619 * `|' `#' `&' `~' bitwise operators - or, xor, and, not
620
621 The trigonometric functions can be inverted if prefixed with an `I', see
622 below for the way to use degrees instead of the default radians.
623
624 Two special postfix unary operators are `>' and `<': whenever a binary
625 operator is performed, it is remembered along with its arguments; then
626 `>' (`<') will apply the same operator with the same right (left)
627 argument.
628
629 hex/oct/bin modes can be set for input and for display separately.
630 Another toggle-able mode is for using degrees instead of radians for
631 trigonometric functions.
632 The keys to switch modes are (`X' is shortcut for `H'):
633 * `D'             switch to all-decimal mode, or toggle degrees/radians
634 * `B' `O' `H' `X' binary/octal/hexadecimal modes for input & display
635 * `i' `o'         followed by one of `D' `B' `O' `H' `X' (case
636                   insensitive) sets only the input or display radix mode
637 The prompt indicates the current modes:
638 * \"D=\": degrees mode;
639 * \"?=\": (? is B/O/H) this is the radix for both input and output;
640 * \"=?\": (? is B/O/H) the display radix (when input is decimal);
641 * \"??\": (? is D/B/O/H) 1st char for input radix, 2nd for display.
642
643 Also, the quote key can be used to switch display modes for decimal
644 numbers (double-quote rotates back), and the two brace characters
645 \(\"{\" and \"}\" change display parameters that these displayers use (if
646 they handle such).  If output is using any radix mode, then these keys
647 toggle digit grouping mode and the chunk size.
648
649 Values can be saved for future reference in either a list of saved
650 values, or in registers.
651
652 The list of saved values is useful for statistics operations on some
653 collected data.  It is possible to navigate in this list, and if the
654 value shown is the current one on the list, an indication is displayed
655 as \"[N]\" if this is the last number and there are N numbers, or
656 \"[M/N]\" if the M-th value is shown.
657 * `SPC'            evaluate the current value as usual, but also adds
658                    the result to the list of saved values
659 * `l' `v'          computes total / average of saved values
660 * `up' `C-p'       browse to the previous value in the list
661 * `down' `C-n'     browse to the next value in the list
662 * `delete' `C-d'   remove current value from the list (if it is on it)
663 * `C-delete' `C-c' delete the whole list
664
665 Registers are variable-like place-holders for values:
666 * `s' followed by a character attach the current value to that character
667 * `g' followed by a character fetches the attached value
668
669 There are many variables that can be used to customize the calculator.
670 Some interesting customization variables are:
671 * `calculator-electric-mode'  use only the echo-area electrically.
672 * `calculator-unary-style'    set most unary ops to pre/postfix style.
673 * `calculator-user-registers' to define user-preset registers.
674 * `calculator-user-operators' to add user-defined operators.
675 See the documentation for these variables, and \"calculator.el\" for
676 more information.
677
678 \\{calculator-mode-map}"
679   (interactive)
680   (kill-all-local-variables)
681   (setq major-mode 'calculator-mode)
682   (setq mode-name "Calculator")
683   (use-local-map calculator-mode-map)
684   (run-mode-hooks 'calculator-mode-hook))
685
686 (eval-when-compile (require 'electric) (require 'ehelp))
687
688 ;;;###autoload
689 (defun calculator ()
690   "Run the Emacs calculator.
691 See the documentation for `calculator-mode' for more information."
692   (interactive)
693   (if calculator-restart-other-mode
694     (setq calculator-electric-mode (not calculator-electric-mode)))
695   (if calculator-initial-operators
696     (progn (calculator-add-operators calculator-initial-operators)
697            (setq calculator-initial-operators nil)
698            ;; don't change this since it is a customization variable,
699            ;; its set function will add any new operators
700            (calculator-add-operators calculator-user-operators)))
701   (setq calculator-buffer (get-buffer-create "*calculator*"))
702   (if calculator-electric-mode
703     (save-window-excursion
704       (progn (require 'electric) (message nil)) ; hide load message
705       (let (old-g-map old-l-map (echo-keystrokes 0)
706             (garbage-collection-messages nil)) ; no gc msg when electric
707         (set-window-buffer (minibuffer-window) calculator-buffer)
708         (select-window (minibuffer-window))
709         (calculator-reset)
710         (calculator-update-display)
711         (setq old-l-map (current-local-map))
712         (setq old-g-map (current-global-map))
713         (setq calculator-saved-global-map (current-global-map))
714         (use-local-map nil)
715         (use-global-map calculator-mode-map)
716         (run-hooks 'calculator-mode-hook)
717         (unwind-protect
718             (catch 'calculator-done
719               (Electric-command-loop
720                'calculator-done
721                ;; can't use 'noprompt, bug in electric.el
722                '(lambda () 'noprompt)
723                nil
724                (lambda (x y) (calculator-update-display))))
725           (and calculator-buffer
726                (catch 'calculator-done (calculator-quit)))
727           (use-local-map old-l-map)
728           (use-global-map old-g-map))))
729     (progn
730       (cond
731         ((not (get-buffer-window calculator-buffer))
732          (let ((split-window-keep-point nil)
733                (window-min-height 2))
734            ;; maybe leave two lines for our window because of the normal
735            ;; `raised' modeline in Emacs 21
736            (select-window
737             (split-window-vertically
738              ;; If the modeline might interfere with the calculator buffer,
739              ;; use 3 lines instead.
740              (if (and (fboundp 'face-attr-construct)
741                       (let* ((dh (plist-get (face-attr-construct 'default) :height))
742                              (mf (face-attr-construct 'modeline))
743                              (mh (plist-get mf :height)))
744                         ;; If the modeline is shorter than the default,
745                         ;; stick with 2 lines.  (It may be necessary to
746                         ;; check how much shorter.)
747                         (and
748                          (not
749                           (or (and (integerp dh)
750                                    (integerp mh)
751                                    (< mh dh))
752                               (and (numberp mh)
753                                    (not (integerp mh))
754                                    (< mh 1))))
755                          (or
756                           ;; If the modeline is taller than the default,
757                           ;; use 3 lines.
758                           (and (integerp dh)
759                                (integerp mh)
760                         &n