diff options
| author | Dave Love | 2000-11-14 18:52:08 +0000 |
|---|---|---|
| committer | Dave Love | 2000-11-14 18:52:08 +0000 |
| commit | 25c269ef6e910382e8a1e9b97cc0c87480ae5653 (patch) | |
| tree | 93d67a640c233cc15f3a02b206478b0709dfa667 | |
| parent | 0894e696763f4faef3023e7445480b35a2a11860 (diff) | |
| download | emacs-25c269ef6e910382e8a1e9b97cc0c87480ae5653.tar.gz emacs-25c269ef6e910382e8a1e9b97cc0c87480ae5653.zip | |
New maintainer version.
| -rw-r--r-- | lisp/ChangeLog | 5 | ||||
| -rw-r--r-- | lisp/calculator.el | 626 |
2 files changed, 444 insertions, 187 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 7c636855205..920e609444e 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -4,6 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | 2000-11-14 Dave Love <fx@gnu.org> | 5 | 2000-11-14 Dave Love <fx@gnu.org> |
| 6 | 6 | ||
| 7 | * calculator.el: New maintainer version. | ||
| 8 | |||
| 9 | * diff-mode.el (diff-imenu-generic-expression): Modify unidiff | ||
| 10 | pattern. | ||
| 11 | |||
| 7 | * cmuscheme.el: Doc fixes. | 12 | * cmuscheme.el: Doc fixes. |
| 8 | (cmuscheme) <defgroup>: Use `scheme' as parent. | 13 | (cmuscheme) <defgroup>: Use `scheme' as parent. |
| 9 | (cmuscheme-program-name): Remove. Change uses to | 14 | (cmuscheme-program-name): Remove. Change uses to |
diff --git a/lisp/calculator.el b/lisp/calculator.el index ad385a9de4d..ab84d088e6b 100644 --- a/lisp/calculator.el +++ b/lisp/calculator.el | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | ;;; calculator.el --- A simple pocket calculator. | 1 | ;;; calculator.el --- A [not so] simple calculator for Emacs. |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1998 by Free Software Foundation, Inc. | 3 | ;; Copyright (C) 1998, 2000 by Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | ;; Author: Eli Barzilay <eli@lambda.cs.cornell.edu> | 5 | ;; Author: Eli Barzilay <eli@www.barzilay.org> |
| 6 | ;; Keywords: tools, convenience | 6 | ;; Keywords: tools, convenience |
| 7 | ;; Time-stamp: <2000-02-16 21:07:54 eli> | 7 | ;; Time-stamp: <2000-11-07 15:04:06 eli> |
| 8 | 8 | ||
| 9 | ;; This file is part of GNU Emacs. | 9 | ;; This file is part of GNU Emacs. |
| 10 | 10 | ||
| @@ -23,33 +23,35 @@ | |||
| 23 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | 23 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
| 24 | ;; MA 02111-1307, USA. | 24 | ;; MA 02111-1307, USA. |
| 25 | 25 | ||
| 26 | ;;;============================================================================ | ||
| 26 | ;;; Commentary: | 27 | ;;; Commentary: |
| 27 | ;; | 28 | ;; |
| 28 | ;; A simple pocket calculator for Emacs. | 29 | ;; A calculator for Emacs. |
| 29 | ;; Why touch your mouse to get xcalc (or calc.exe), when you have Emacs? | 30 | ;; Why should you each for your mouse to get xcalc (calc.exe, gcalc or |
| 31 | ;; whatever), when you have Emacs running already? | ||
| 30 | ;; | 32 | ;; |
| 31 | ;; If this is not part of your Emacs distribution, then simply bind | 33 | ;; If this is not part of your Emacs distribution, then simply bind |
| 32 | ;; `calculator' to a key and make it an autoloaded function, e.g.: | 34 | ;; `calculator' to a key and make it an autoloaded function, e.g.: |
| 33 | ;; (autoload 'calculator "calculator" | 35 | ;; (autoload 'calculator "calculator" |
| 34 | ;; "Run the pocket calculator." t) | 36 | ;; "Run the Emacs calculator." t) |
| 35 | ;; (global-set-key [(control return)] 'calculator) | 37 | ;; (global-set-key [(control return)] 'calculator) |
| 36 | ;; | 38 | ;; |
| 37 | ;; Written by Eli Barzilay: Maze is Life! eli@cs.cornell.edu | 39 | ;; Written by Eli Barzilay: Maze is Life! eli@barzilay.org |
| 38 | ;; http://www.cs.cornell.edu/eli | 40 | ;; http://www.barzilay.org/ |
| 39 | ;; | 41 | ;; |
| 40 | ;; For latest version, check | 42 | ;; For latest version, check |
| 41 | ;; http://www.cs.cornell.edu/eli/misc/calculator.el | 43 | ;; http://www.barzilay.org/misc/calculator.el |
| 42 | |||
| 43 | 44 | ||
| 44 | (eval-and-compile | 45 | (eval-and-compile |
| 45 | (if (fboundp 'defgroup) nil | 46 | (if (fboundp 'defgroup) nil |
| 46 | (defmacro defgroup (&rest forms) nil) | 47 | (defmacro defgroup (&rest forms) nil) |
| 47 | (defmacro defcustom (s v d &rest r) (list 'defvar s v d)))) | 48 | (defmacro defcustom (s v d &rest r) (list 'defvar s v d)))) |
| 48 | 49 | ||
| 50 | ;;;============================================================================ | ||
| 49 | ;;; Customization: | 51 | ;;; Customization: |
| 50 | 52 | ||
| 51 | (defgroup calculator nil | 53 | (defgroup calculator nil |
| 52 | "Simple pocket calculator." | 54 | "Simple Emacs calculator." |
| 53 | :prefix "calculator" | 55 | :prefix "calculator" |
| 54 | :version "21.1" | 56 | :version "21.1" |
| 55 | :group 'tools | 57 | :group 'tools |
| @@ -57,8 +59,8 @@ | |||
| 57 | 59 | ||
| 58 | (defcustom calculator-electric-mode nil | 60 | (defcustom calculator-electric-mode nil |
| 59 | "*Run `calculator' electrically, in the echo area. | 61 | "*Run `calculator' electrically, in the echo area. |
| 60 | Note that if you use electric-mode, you wouldn't be able to use | 62 | Electric mode saves some place but changes the way you interact with the |
| 61 | conventional help keys." | 63 | calculator." |
| 62 | :type 'boolean | 64 | :type 'boolean |
| 63 | :group 'calculator) | 65 | :group 'calculator) |
| 64 | 66 | ||
| @@ -79,43 +81,69 @@ This determines the default behavior of unary operators." | |||
| 79 | :type '(choice (const prefix) (const postfix)) | 81 | :type '(choice (const prefix) (const postfix)) |
| 80 | :group 'calculator) | 82 | :group 'calculator) |
| 81 | 83 | ||
| 82 | (defcustom calculator-prompt "Calculator=%s> " | 84 | (defcustom calculator-prompt "Calc=%s> " |
| 83 | "*The prompt used by the pocket calculator. | 85 | "*The prompt used by the Emacs calculator. |
| 84 | It should contain a \"%s\" somewhere that will indicate the i/o radixes, | 86 | It should contain a \"%s\" somewhere that will indicate the i/o radixes, |
| 85 | this string will be a two-character string as described in the | 87 | this string will be a two-character string as described in the |
| 86 | documentation for `calculator-mode'." | 88 | documentation for `calculator-mode'." |
| 87 | :type 'string | 89 | :type 'string |
| 88 | :group 'calculator) | 90 | :group 'calculator) |
| 89 | 91 | ||
| 90 | (defcustom calculator-epsilon 1e-15 | 92 | (defcustom calculator-number-digits 3 |
| 91 | "*A threshold for results. | 93 | "*The calculator's number of digits used for standard display. |
| 92 | If any result computed in `calculator-funcall' is smaller than this in | 94 | Used by the `calculator-standard-display' function - it will use the |
| 93 | its absolute value, then zero will be returned." | 95 | format string \"%.NC\" where this number is N and C is a character given |
| 94 | :type 'number | 96 | at runtime." |
| 95 | :group 'calculator) | ||
| 96 | |||
| 97 | (defcustom calculator-number-format "%1.3f" | ||
| 98 | "*The calculator's string used to display normal numbers." | ||
| 99 | :type 'string | 97 | :type 'string |
| 100 | :group 'calculator) | 98 | :group 'calculator) |
| 101 | 99 | ||
| 102 | (defcustom calculator-number-exp-ulimit 1e16 | 100 | (defcustom calculator-remove-zeros t |
| 103 | "*The calculator's upper limit for normal numbers." | 101 | "*Non-nil value means delete all redundant zero decimal digits. |
| 104 | :type 'number | 102 | If this value is not t, and not nil, redundant zeros are removed except |
| 103 | for one and if it is nil, nothing is removed. | ||
| 104 | Used by the `calculator-remove-zeros' function." | ||
| 105 | :type '(choice (const t) (const leave-decimal) (const nil)) | ||
| 105 | :group 'calculator) | 106 | :group 'calculator) |
| 106 | 107 | ||
| 107 | (defcustom calculator-number-exp-llimit 0.001 | 108 | (defcustom calculator-displayer '(std ?n) |
| 108 | "*The calculator's lower limit for normal numbers." | 109 | "*A displayer specification for numerical values. |
| 109 | :type 'number | 110 | This is the displayer used to show all numbers in an expression. Result |
| 111 | values will be displayed according to the first element of | ||
| 112 | `calculator-displayers'. | ||
| 113 | |||
| 114 | The displayer is a symbol, a string or an expression. A symbol should | ||
| 115 | be the name of a one-argument function, a string is used with a single | ||
| 116 | argument and an expression will be evaluated with the variable `num' | ||
| 117 | bound to whatever should be displayed. If it is a function symbol, it | ||
| 118 | should be able to handle special symbol arguments, currently 'left and | ||
| 119 | 'right which will be sent by special keys to modify display parameters | ||
| 120 | associated with the displayer function (for example to change the number | ||
| 121 | of digits displayed). | ||
| 122 | |||
| 123 | An exception to the above is the case of the list (std C) where C is a | ||
| 124 | character, in this case the `calculator-standard-displayer' function | ||
| 125 | will be used with this character for a format string.") | ||
| 126 | |||
| 127 | (defcustom calculator-displayers | ||
| 128 | '(((std ?n) "Standard dislpay, decimal point or scientific") | ||
| 129 | (calculator-eng-display "Eng display") | ||
| 130 | ((std ?f) "Standard display, decimal point") | ||
| 131 | ((std ?e) "Standard dislpay, scientific") | ||
| 132 | ("%S" "Emacs printer")) | ||
| 133 | "*A list of displayers. | ||
| 134 | Each element is a list of a displayer and a description string. The | ||
| 135 | first element is the one which is curently used, this is for the display | ||
| 136 | of result values not values in expressions. A displayer specification | ||
| 137 | is the same as the values that can be stored in `calculator-displayer'. | ||
| 138 | |||
| 139 | `calculator-rotate-displayer' rotates this list." | ||
| 140 | :type 'sexp | ||
| 110 | :group 'calculator) | 141 | :group 'calculator) |
| 111 | 142 | ||
| 112 | (defcustom calculator-number-exp-format "%g" | 143 | (defcustom calculator-paste-decimals t |
| 113 | "*The calculator's string used to display exponential numbers." | 144 | "*If non-nil, convert pasted integers so they have a decimal point. |
| 114 | :type 'string | 145 | This makes it possible to paste big integers since they will be read as |
| 115 | :group 'calculator) | 146 | floats, otherwise the Emacs reader will fail on them." |
| 116 | |||
| 117 | (defcustom calculator-show-integers t | ||
| 118 | "*Non-nil value means delete all zero digits after the decimal point." | ||
| 119 | :type 'boolean | 147 | :type 'boolean |
| 120 | :group 'calculator) | 148 | :group 'calculator) |
| 121 | 149 | ||
| @@ -126,18 +154,18 @@ Otherwise show as a negative number." | |||
| 126 | :group 'calculator) | 154 | :group 'calculator) |
| 127 | 155 | ||
| 128 | (defcustom calculator-mode-hook nil | 156 | (defcustom calculator-mode-hook nil |
| 129 | "*List of hook functions run by `calculator-mode'." | 157 | "*List of hook functions for `calculator-mode' to run." |
| 130 | :type 'hook | 158 | :type 'hook |
| 131 | :group 'calculator) | 159 | :group 'calculator) |
| 132 | 160 | ||
| 133 | (defcustom calculator-user-registers nil | 161 | (defcustom calculator-user-registers nil |
| 134 | "*An association list of user-defined register bindings. | 162 | "*An association list of user-defined register bindings. |
| 135 | |||
| 136 | Each element in this list is a list of a character and a number that | 163 | Each element in this list is a list of a character and a number that |
| 137 | will be stored in that character's register. | 164 | will be stored in that character's register. |
| 138 | 165 | ||
| 139 | For example, use this to define the golden ratio number: | 166 | For example, use this to define the golden ratio number: |
| 140 | (setq calculator-user-registers '((?g . 1.61803398875)))" | 167 | (setq calculator-user-registers '((?g . 1.61803398875))) |
| 168 | before you load calculator." | ||
| 141 | :type '(repeat (cons character number)) | 169 | :type '(repeat (cons character number)) |
| 142 | :set '(lambda (_ val) | 170 | :set '(lambda (_ val) |
| 143 | (and (boundp 'calculator-registers) | 171 | (and (boundp 'calculator-registers) |
| @@ -148,7 +176,6 @@ For example, use this to define the golden ratio number: | |||
| 148 | 176 | ||
| 149 | (defcustom calculator-user-operators nil | 177 | (defcustom calculator-user-operators nil |
| 150 | "*A list of additional operators. | 178 | "*A list of additional operators. |
| 151 | |||
| 152 | This is a list in the same format as specified in the documentation for | 179 | This is a list in the same format as specified in the documentation for |
| 153 | `calculator-operators', that you can use to bind additional calculator | 180 | `calculator-operators', that you can use to bind additional calculator |
| 154 | operators. It is probably not a good idea to modify this value with | 181 | operators. It is probably not a good idea to modify this value with |
| @@ -174,23 +201,27 @@ Examples: | |||
| 174 | 201 | ||
| 175 | (add-to-list 'calculator-user-operators | 202 | (add-to-list 'calculator-user-operators |
| 176 | '(\"F\" fib (if (<= TX 1) | 203 | '(\"F\" fib (if (<= TX 1) |
| 177 | 1 | 204 | 1 |
| 178 | (+ (F (- TX 1)) (F (- TX 2)))) 0)) | 205 | (+ (F (- TX 1)) (F (- TX 2)))) 0)) |
| 179 | 206 | ||
| 180 | Note that this will be either postfix or prefix, according to | 207 | Note that this will be either postfix or prefix, according to |
| 181 | `calculator-unary-style'." | 208 | `calculator-unary-style'." |
| 182 | :type '(repeat (list string symbol sexp integer integer)) | 209 | :type '(repeat (list string symbol sexp integer integer)) |
| 183 | :group 'calculator) | 210 | :group 'calculator) |
| 184 | 211 | ||
| 212 | ;;;============================================================================ | ||
| 185 | ;;; Code: | 213 | ;;; Code: |
| 186 | 214 | ||
| 215 | ;;;---------------------------------------------------------------------------- | ||
| 216 | ;;; Variables | ||
| 217 | |||
| 187 | (defvar calculator-initial-operators | 218 | (defvar calculator-initial-operators |
| 188 | '(;; "+"/"-" have keybindings of themselves, not calculator-ops | 219 | '(;; "+"/"-" have keybindings of themselves, not calculator-ops |
| 189 | ("=" = identity 1 -1) | 220 | ("=" = identity 1 -1) |
| 190 | (nobind "+" + + 2 4) | 221 | (nobind "+" + + 2 4) |
| 191 | (nobind "-" - - 2 4) | 222 | (nobind "-" - - 2 4) |
| 192 | (nobind "+" + + -1 9) | 223 | (nobind "+" + + -1 9) |
| 193 | (nobind "-" - - -1 9) | 224 | (nobind "-" - - -1 9) |
| 194 | ("(" \( identity -1 -1) | 225 | ("(" \( identity -1 -1) |
| 195 | (")" \) identity +1 10) | 226 | (")" \) identity +1 10) |
| 196 | ;; normal keys | 227 | ;; normal keys |
| @@ -220,7 +251,6 @@ Examples: | |||
| 220 | ("l" tot (apply '+ L) 0 8) | 251 | ("l" tot (apply '+ L) 0 8) |
| 221 | ) | 252 | ) |
| 222 | "A list of initial operators. | 253 | "A list of initial operators. |
| 223 | |||
| 224 | This is a list in the same format as `calculator-operators'. Whenever | 254 | This is a list in the same format as `calculator-operators'. Whenever |
| 225 | `calculator' starts, it looks at the value of this variable, and if it | 255 | `calculator' starts, it looks at the value of this variable, and if it |
| 226 | is not empty, its contents is prepended to `calculator-operators' and | 256 | is not empty, its contents is prepended to `calculator-operators' and |
| @@ -243,12 +273,13 @@ user-defined operators, use `calculator-user-operators' instead.") | |||
| 243 | (list of saved values), `F' (function for recursive iteration calls) | 273 | (list of saved values), `F' (function for recursive iteration calls) |
| 244 | and evaluates to the function value - these variables are capital; | 274 | and evaluates to the function value - these variables are capital; |
| 245 | 275 | ||
| 246 | 4. The function's arity, optional, one of: 2=binary, -1=prefix unary, | 276 | 4. The function's arity, optional, one of: 2 => binary, -1 => prefix |
| 247 | +1=postfix unary, 0=a 0-arg operator func, non-number=postfix/prefix | 277 | unary, +1 => postfix unary, 0 => a 0-arg operator func, non-number => |
| 248 | as determined by `calculator-unary-style' (the default); | 278 | postfix/prefix as determined by `calculator-unary-style' (the |
| 279 | default); | ||
| 249 | 280 | ||
| 250 | 5. The function's precedence - should be in the range of 1=lowest to | 281 | 5. The function's precedence - should be in the range of 1 (lowest) to |
| 251 | 9=highest (optional, defaults to 1); | 282 | 9 (highest) (optional, defaults to 1); |
| 252 | 283 | ||
| 253 | It it possible have a unary prefix version of a binary operator if it | 284 | It it possible have a unary prefix version of a binary operator if it |
| 254 | comes later in this list. If the list begins with the symbol 'nobind, | 285 | comes later in this list. If the list begins with the symbol 'nobind, |
| @@ -295,6 +326,12 @@ documentation for an example.") | |||
| 295 | (defvar calculator-buffer nil | 326 | (defvar calculator-buffer nil |
| 296 | "The current calculator buffer.") | 327 | "The current calculator buffer.") |
| 297 | 328 | ||
| 329 | (defvar calculator-eng-extra nil | ||
| 330 | "Internal value used by `calculator-eng-display'.") | ||
| 331 | |||
| 332 | (defvar calculator-eng-tmp-show nil | ||
| 333 | "Internal value used by `calculator-eng-display'.") | ||
| 334 | |||
| 298 | (defvar calculator-last-opXY nil | 335 | (defvar calculator-last-opXY nil |
| 299 | "The last binary operation and its arguments. | 336 | "The last binary operation and its arguments. |
| 300 | Used for repeating operations in calculator-repR/L.") | 337 | Used for repeating operations in calculator-repR/L.") |
| @@ -307,7 +344,10 @@ Used for repeating operations in calculator-repR/L.") | |||
| 307 | "Saved global key map.") | 344 | "Saved global key map.") |
| 308 | 345 | ||
| 309 | (defvar calculator-restart-other-mode nil | 346 | (defvar calculator-restart-other-mode nil |
| 310 | "Used to hack restarting with the mode electric mode changed.") | 347 | "Used to hack restarting with the electric mode changed.") |
| 348 | |||
| 349 | ;;;---------------------------------------------------------------------------- | ||
| 350 | ;;; Key bindings | ||
| 311 | 351 | ||
| 312 | (defvar calculator-mode-map nil | 352 | (defvar calculator-mode-map nil |
| 313 | "The calculator key map.") | 353 | "The calculator key map.") |
| @@ -318,16 +358,16 @@ Used for repeating operations in calculator-repR/L.") | |||
| 318 | (define-key map "i" nil) | 358 | (define-key map "i" nil) |
| 319 | (define-key map "o" nil) | 359 | (define-key map "o" nil) |
| 320 | (let ((p | 360 | (let ((p |
| 321 | '(("(" "[" "{") | 361 | '((calculator-open-paren "[") |
| 322 | (")" "]" "}") | 362 | (calculator-close-paren "]") |
| 323 | (calculator-op-or-exp "+" "-" [kp-add] [kp-subtract]) | 363 | (calculator-op-or-exp "+" "-" [kp-add] [kp-subtract]) |
| 324 | (calculator-digit "0" "1" "2" "3" "4" "5" "6" "7" "8" | 364 | (calculator-digit "0" "1" "2" "3" "4" "5" "6" "7" "8" |
| 325 | "9" "a" "b" "c" "d" "f" | 365 | "9" "a" "b" "c" "d" "f" |
| 326 | [kp-0] [kp-1] [kp-2] [kp-3] [kp-4] | 366 | [kp-0] [kp-1] [kp-2] [kp-3] [kp-4] |
| 327 | [kp-5] [kp-6] [kp-7] [kp-8] [kp-9]) | 367 | [kp-5] [kp-6] [kp-7] [kp-8] [kp-9]) |
| 328 | (calculator-op [kp-divide] [kp-multiply]) | 368 | (calculator-op [kp-divide] [kp-multiply]) |
| 329 | (calculator-decimal "." [kp-decimal]) | 369 | (calculator-decimal "." [kp-decimal]) |
| 330 | (calculator-exp "e") | 370 | (calculator-exp "e") |
| 331 | (calculator-dec/deg-mode "D") | 371 | (calculator-dec/deg-mode "D") |
| 332 | (calculator-set-register "s") | 372 | (calculator-set-register "s") |
| 333 | (calculator-get-register "g") | 373 | (calculator-get-register "g") |
| @@ -336,16 +376,20 @@ Used for repeating operations in calculator-repR/L.") | |||
| 336 | "iD" "iH" "iX" "iO" "iB") | 376 | "iD" "iH" "iX" "iO" "iB") |
| 337 | (calculator-radix-output-mode "od" "oh" "ox" "oo" "ob" | 377 | (calculator-radix-output-mode "od" "oh" "ox" "oo" "ob" |
| 338 | "oD" "oH" "oX" "oO" "oB") | 378 | "oD" "oH" "oX" "oO" "oB") |
| 379 | (calculator-rotate-displayer "'") | ||
| 380 | (calculator-rotate-displayer-back "\"") | ||
| 381 | (calculator-displayer-left "{") | ||
| 382 | (calculator-displayer-right "}") | ||
| 339 | (calculator-saved-up [up] [?\C-p]) | 383 | (calculator-saved-up [up] [?\C-p]) |
| 340 | (calculator-saved-down [down] [?\C-n]) | 384 | (calculator-saved-down [down] [?\C-n]) |
| 341 | (calculator-quit "q" [?\C-g]) | 385 | (calculator-quit "q" [?\C-g]) |
| 342 | ("=" [enter] [linefeed] [kp-enter] | 386 | (calculator-enter [enter] [linefeed] [kp-enter] |
| 343 | [?\r] [?\n]) | 387 | [return] [?\r] [?\n]) |
| 344 | (calculator-save-on-list " " [space]) | 388 | (calculator-save-on-list " " [space]) |
| 345 | (calculator-clear-saved [?\C-c] [(control delete)]) | 389 | (calculator-clear-saved [?\C-c] [(control delete)]) |
| 346 | (calculator-save-and-quit [(control return)] | 390 | (calculator-save-and-quit [(control return)] |
| 347 | [(control kp-enter)]) | 391 | [(control kp-enter)]) |
| 348 | (calculator-paste [insert] [(shift insert)]) | 392 | (calculator-paste [insert] [(shift insert)] [mouse-2]) |
| 349 | (calculator-clear [delete] [?\C-?] [?\C-d]) | 393 | (calculator-clear [delete] [?\C-?] [?\C-d]) |
| 350 | (calculator-help [?h] [??] [f1] [help]) | 394 | (calculator-help [?h] [??] [f1] [help]) |
| 351 | (calculator-copy [(control insert)]) | 395 | (calculator-copy [(control insert)]) |
| @@ -482,13 +526,26 @@ Used for repeating operations in calculator-repR/L.") | |||
| 482 | ,@(mapcar (lambda (x) (nth 1 x)) radix-selectors) | 526 | ,@(mapcar (lambda (x) (nth 1 x)) radix-selectors) |
| 483 | "---" | 527 | "---" |
| 484 | ,@(mapcar (lambda (x) (nth 2 x)) radix-selectors))) | 528 | ,@(mapcar (lambda (x) (nth 2 x)) radix-selectors))) |
| 529 | ("Decimal Dislpay" | ||
| 530 | ,@(mapcar (lambda (d) | ||
| 531 | (vector (cadr d) | ||
| 532 | ;; Note: inserts actual object here | ||
| 533 | `(calculator-rotate-displayer ',d))) | ||
| 534 | calculator-displayers) | ||
| 535 | "---" | ||
| 536 | ["Change Display Left" calculator-displayer-left] | ||
| 537 | ["Change Display Right" calculator-displayer-right]) | ||
| 485 | "---" | 538 | "---" |
| 486 | ["Copy+Quit" calculator-save-and-quit] | 539 | ["Copy+Quit" calculator-save-and-quit] |
| 487 | ["Quit" calculator-quit])))) | 540 | ["Quit" calculator-quit])))) |
| 488 | (setq calculator-mode-map map))) | 541 | (setq calculator-mode-map map))) |
| 489 | 542 | ||
| 543 | ;;;---------------------------------------------------------------------------- | ||
| 544 | ;;; Startup and mode stuff | ||
| 545 | |||
| 490 | (defun calculator-mode () | 546 | (defun calculator-mode () |
| 491 | "A simple pocket calculator in Emacs. | 547 | ;; this help is also used as the major help screen |
| 548 | "A [not so] simple calculator for Emacs. | ||
| 492 | 549 | ||
| 493 | This calculator is used in the same way as other popular calculators | 550 | This calculator is used in the same way as other popular calculators |
| 494 | like xcalc or calc.exe - but using an Emacs interface. | 551 | like xcalc or calc.exe - but using an Emacs interface. |
| @@ -544,6 +601,11 @@ The prompt indicates the current modes: | |||
| 544 | * \"=?\": (? is B/O/H) the display radix (when input is decimal); | 601 | * \"=?\": (? is B/O/H) the display radix (when input is decimal); |
| 545 | * \"??\": (? is D/B/O/H) 1st char for input radix, 2nd for display. | 602 | * \"??\": (? is D/B/O/H) 1st char for input radix, 2nd for display. |
| 546 | 603 | ||
| 604 | Also, the quote character can be used to switch display modes for | ||
| 605 | decimal numbers (double-quote rotates back), and the two brace | ||
| 606 | characters (\"{\" and \"}\" change display parameters that these | ||
| 607 | displayers use (if they handle such). | ||
| 608 | |||
| 547 | Values can be saved for future reference in either a list of saved | 609 | Values can be saved for future reference in either a list of saved |
| 548 | values, or in registers. | 610 | values, or in registers. |
| 549 | 611 | ||
| @@ -581,9 +643,11 @@ more information. | |||
| 581 | (use-local-map calculator-mode-map) | 643 | (use-local-map calculator-mode-map) |
| 582 | (run-hooks 'calculator-mode-hook)) | 644 | (run-hooks 'calculator-mode-hook)) |
| 583 | 645 | ||
| 646 | (eval-when-compile (require 'electric) (require 'ehelp)) | ||
| 647 | |||
| 584 | ;;;###autoload | 648 | ;;;###autoload |
| 585 | (defun calculator () | 649 | (defun calculator () |
| 586 | "Run the pocket calculator. | 650 | "Run the Emacs calculator. |
| 587 | See the documentation for `calculator-mode' for more information." | 651 | See the documentation for `calculator-mode' for more information." |
| 588 | (interactive) | 652 | (interactive) |
| 589 | (if calculator-restart-other-mode | 653 | (if calculator-restart-other-mode |
| @@ -592,7 +656,7 @@ See the documentation for `calculator-mode' for more information." | |||
| 592 | (progn (calculator-add-operators calculator-initial-operators) | 656 | (progn (calculator-add-operators calculator-initial-operators) |
| 593 | (setq calculator-initial-operators nil) | 657 | (setq calculator-initial-operators nil) |
| 594 | ;; don't change this since it is a customization variable, | 658 | ;; don't change this since it is a customization variable, |
| 595 | ;; its set function will add any new operators. | 659 | ;; its set function will add any new operators |
| 596 | (calculator-add-operators calculator-user-operators))) | 660 | (calculator-add-operators calculator-user-operators))) |
| 597 | (if calculator-electric-mode | 661 | (if calculator-electric-mode |
| 598 | (save-window-excursion | 662 | (save-window-excursion |
| @@ -632,14 +696,16 @@ See the documentation for `calculator-mode' for more information." | |||
| 632 | (let ((split-window-keep-point nil) | 696 | (let ((split-window-keep-point nil) |
| 633 | (window-min-height 2)) | 697 | (window-min-height 2)) |
| 634 | (select-window | 698 | (select-window |
| 635 | ;; Maybe leave two lines for our window because | 699 | ;; maybe leave two lines for our window because |
| 636 | ;; of the normal `raised' modeline in Emacs 21. | 700 | ;; of the normal `raised' modeline in Emacs 21 |
| 637 | (split-window-vertically | 701 | (split-window-vertically |
| 638 | (- (window-height) | 702 | (- (window-height) |
| 639 | (if (plist-get (face-attr-construct 'modeline) | 703 | (if (and |
| 640 | :box) | 704 | (fboundp 'face-attr-construct) |
| 641 | 3 | 705 | (plist-get (face-attr-construct 'modeline) |
| 642 | 2)))) | 706 | :box)) |
| 707 | 3 | ||
| 708 | 2)))) | ||
| 643 | (switch-to-buffer | 709 | (switch-to-buffer |
| 644 | (get-buffer-create "*calculator*")))))) | 710 | (get-buffer-create "*calculator*")))))) |
| 645 | (set-buffer calculator-buffer) | 711 | (set-buffer calculator-buffer) |
| @@ -650,6 +716,9 @@ See the documentation for `calculator-mode' for more information." | |||
| 650 | (if (and calculator-restart-other-mode calculator-electric-mode) | 716 | (if (and calculator-restart-other-mode calculator-electric-mode) |
| 651 | (calculator))) | 717 | (calculator))) |
| 652 | 718 | ||
| 719 | ;;;---------------------------------------------------------------------------- | ||
| 720 | ;;; Operatos | ||
| 721 | |||
| 653 | (defun calculator-op-arity (op) | 722 | (defun calculator-op-arity (op) |
| 654 | "Return OP's arity, 2, +1 or -1." | 723 | "Return OP's arity, 2, +1 or -1." |
| 655 | (let ((arity (or (nth 3 op) 'x))) | 724 | (let ((arity (or (nth 3 op) 'x))) |
| @@ -690,6 +759,9 @@ Adds MORE-OPS to `calculator-operator', called initially to handle | |||
| 690 | (setq calculator-operators | 759 | (setq calculator-operators |
| 691 | (append (nreverse added-ops) calculator-operators)))) | 760 | (append (nreverse added-ops) calculator-operators)))) |
| 692 | 761 | ||
| 762 | ;;;---------------------------------------------------------------------------- | ||
| 763 | ;;; Display stuff | ||
| 764 | |||
| 693 | (defun calculator-reset () | 765 | (defun calculator-reset () |
| 694 | "Reset calculator variables." | 766 | "Reset calculator variables." |
| 695 | (or calculator-restart-other-mode | 767 | (or calculator-restart-other-mode |
| @@ -769,12 +841,155 @@ The string is set not to exceed the screen width." | |||
| 769 | ((string-match "\\.[0-9]\\|[eE]" calculator-curnum) | 841 | ((string-match "\\.[0-9]\\|[eE]" calculator-curnum) |
| 770 | calculator-curnum) | 842 | calculator-curnum) |
| 771 | ((string-match "\\." calculator-curnum) | 843 | ((string-match "\\." calculator-curnum) |
| 772 | ;; do this because Emacs reads "23." as an integer. | 844 | ;; do this because Emacs reads "23." as an integer |
| 773 | (concat calculator-curnum "0")) | 845 | (concat calculator-curnum "0")) |
| 774 | ((stringp calculator-curnum) | 846 | ((stringp calculator-curnum) |
| 775 | (concat calculator-curnum ".0")) | 847 | (concat calculator-curnum ".0")) |
| 776 | (t "0.0")))))) | 848 | (t "0.0")))))) |
| 777 | 849 | ||
| 850 | (defun calculator-rotate-displayer (&optional new-disp) | ||
| 851 | "Switch to the next displayer on the `calculator-displayers' list. | ||
| 852 | Can be called with an optional argument NEW-DISP to force rotation to | ||
| 853 | that argument." | ||
| 854 | (interactive) | ||
| 855 | (setq calculator-displayers | ||
| 856 | (if (and new-disp (memq new-disp calculator-displayers)) | ||
| 857 | (let ((tmp nil)) | ||
| 858 | (while (not (eq (car calculator-displayers) new-disp)) | ||
| 859 | (setq tmp (cons (car calculator-displayers) tmp)) | ||
| 860 | (setq calculator-displayers (cdr calculator-displayers))) | ||
| 861 | (setq calculator-displayers | ||
| 862 | (nconc calculator-displayers (nreverse tmp)))) | ||
| 863 | (nconc (cdr calculator-displayers) | ||
| 864 | (list (car calculator-displayers))))) | ||
| 865 | (message "Using %s." (cadr (car calculator-displayers))) | ||
| 866 | (if calculator-electric-mode | ||
| 867 | (progn (sit-for 1) (message nil))) | ||
| 868 | (calculator-enter)) | ||
| 869 | |||
| 870 | (defun calculator-rotate-displayer-back () | ||
| 871 | "Like `calculator-rotate-displayer', but rotates modes back." | ||
| 872 | (interactive) | ||
| 873 | (calculator-rotate-displayer (car (last calculator-displayers)))) | ||
| 874 | |||
| 875 | (defun calculator-displayer-left () | ||
| 876 | "Send the current displayer function a 'left argument. | ||
| 877 | This is used to modify display arguments (if the current displayer | ||
| 878 | function supports this)." | ||
| 879 | (interactive) | ||
| 880 | (and (car calculator-displayers) | ||
| 881 | (let ((disp (caar calculator-displayers))) | ||
| 882 | (cond ((symbolp disp) (funcall disp 'left)) | ||
| 883 | ((and (consp disp) (eq 'std (car disp))) | ||
| 884 | (calculator-standard-displayer 'left (cadr disp))))))) | ||
| 885 | |||
| 886 | (defun calculator-displayer-right () | ||
| 887 | "Send the current displayer function a 'right argument. | ||
| 888 | This is used to modify display arguments (if the current displayer | ||
| 889 | function supports this)." | ||
| 890 | (interactive) | ||
| 891 | (and (car calculator-displayers) | ||
| 892 | (let ((disp (caar calculator-displayers))) | ||
| 893 | (cond ((symbolp disp) (funcall disp 'right)) | ||
| 894 | ((and (consp disp) (eq 'std (car disp))) | ||
| 895 | (calculator-standard-displayer 'right (cadr disp))))))) | ||
| 896 | |||
| 897 | (defun calculator-remove-zeros (numstr) | ||
| 898 | "Get a number string NUMSTR and remove unnecessary zeroes. | ||
| 899 | the behavior of this function is controlled by | ||
| 900 | `calculator-remove-zeros'." | ||
| 901 | (cond ((and (eq calculator-remove-zeros t) | ||
| 902 | (string-match "\\.0+\\([eE][+-]?[0-9]*\\)?$" numstr)) | ||
| 903 | ;; remove all redundant zeros leaving an integer | ||
| 904 | (if (match-beginning 1) | ||
| 905 | (concat (substring numstr 0 (match-beginning 0)) | ||
| 906 | (match-string 1 numstr)) | ||
| 907 | (substring numstr 0 (match-beginning 0)))) | ||
| 908 | ((and calculator-remove-zeros | ||
| 909 | (string-match | ||
| 910 | "\\..\\([0-9]*[1-9]\\)?\\(0+\\)\\([eE][+-]?[0-9]*\\)?$" | ||
| 911 | numstr)) | ||
| 912 | ;; remove zeros, except for first after the "." | ||
| 913 | (if (match-beginning 3) | ||
| 914 | (concat (substring numstr 0 (match-beginning 2)) | ||
| 915 | (match-string 3 numstr)) | ||
| 916 | (substring numstr 0 (match-beginning 2)))) | ||
| 917 | (t numstr))) | ||
| 918 | |||
| 919 | (defun calculator-standard-displayer (num char) | ||
| 920 | "Standard display function, used to display NUM. | ||
| 921 | Its behavior is determined by `calculator-number-digits' and the given | ||
| 922 | CHAR argument (both will be used to compose a format string). If the | ||
| 923 | char is \"n\" then this function will choose one between %f or %e, this | ||
| 924 | is a work around %g jumping to exponential notation too fast. | ||
| 925 | |||
| 926 | The special 'left and 'right symbols will make it change the current | ||
| 927 | number of digits displayed (`calculator-number-digits'). | ||
| 928 | |||
| 929 | It will also remove redundant zeros from the result." | ||
| 930 | (if (symbolp num) | ||
| 931 | (cond ((eq num 'left) | ||
| 932 | (and (> calculator-number-digits 0) | ||
| 933 | (setq calculator-number-digits | ||
| 934 | (1- calculator-number-digits)) | ||
| 935 | (calculator-enter))) | ||
| 936 | ((eq num 'right) | ||
| 937 | (setq calculator-number-digits | ||
| 938 | (1+ calculator-number-digits)) | ||
| 939 | (calculator-enter))) | ||
| 940 | (let ((str (format | ||
| 941 | (concat "%." | ||
| 942 | (number-to-string calculator-number-digits) | ||
| 943 | (if (eq char ?n) | ||
| 944 | (let ((n (abs num))) | ||
| 945 | (if (or (< n 0.001) (> n 1e8)) "e" "f")) | ||
| 946 | (string char))) | ||
| 947 | num))) | ||
| 948 | (calculator-remove-zeros str)))) | ||
| 949 | |||
| 950 | (defun calculator-eng-display (num) | ||
| 951 | "Display NUM in engineering notation. | ||
| 952 | The number of decimal digits used is controlled by | ||
| 953 | `calculator-number-digits', so to change it at runtime you have to use | ||
| 954 | the 'left or 'right when one of the standard modes is used." | ||
| 955 | (if (symbolp num) | ||
| 956 | (cond ((eq num 'left) | ||
| 957 | (setq calculator-eng-extra | ||
| 958 | (if calculator-eng-extra | ||
| 959 | (1+ calculator-eng-extra) | ||
| 960 | 1)) | ||
| 961 | (let ((calculator-eng-tmp-show t)) (calculator-enter))) | ||
| 962 | ((eq num 'right) | ||
| 963 | (setq calculator-eng-extra | ||
| 964 | (if calculator-eng-extra | ||
| 965 | (1- calculator-eng-extra) | ||
| 966 | -1)) | ||
| 967 | (let ((calculator-eng-tmp-show t)) (calculator-enter)))) | ||
| 968 | (let ((exp 0)) | ||
| 969 | (and (not (= 0 num)) | ||
| 970 | (progn | ||
| 971 | (while (< (abs num) 1.0) | ||
| 972 | (setq num (* num 1000.0)) (setq exp (- exp 3))) | ||
| 973 | (while (> (abs num) 999.0) | ||
| 974 | (setq num (/ num 1000.0)) (setq exp (+ exp 3))) | ||
| 975 | (and calculator-eng-tmp-show | ||
| 976 | (not (= 0 calculator-eng-extra)) | ||
| 977 | (let ((i calculator-eng-extra)) | ||
| 978 | (while (> i 0) | ||
| 979 | (setq num (* num 1000.0)) (setq exp (- exp 3)) | ||
| 980 | (setq i (1- i))) | ||
| 981 | (while (< i 0) | ||
| 982 | (setq num (/ num 1000.0)) (setq exp (+ exp 3)) | ||
| 983 | (setq i (1+ i))))))) | ||
| 984 | (or calculator-eng-tmp-show (setq calculator-eng-extra nil)) | ||
| 985 | (let ((str (format (concat "%." calculator-number-digits "f") | ||
| 986 | num))) | ||
| 987 | (concat (let ((calculator-remove-zeros | ||
| 988 | ;; make sure we don't leave integers | ||
| 989 | (and calculator-remove-zeros 'x))) | ||
| 990 | (calculator-remove-zeros str)) | ||
| 991 | "e" (number-to-string exp)))))) | ||
| 992 | |||
| 778 | (defun calculator-num-to-string (num) | 993 | (defun calculator-num-to-string (num) |
| 779 | "Convert NUM to a displayable string." | 994 | "Convert NUM to a displayable string." |
| 780 | (cond | 995 | (cond |
| @@ -799,21 +1014,20 @@ The string is set not to exceed the screen width." | |||
| 799 | (if (and (not calculator-2s-complement) (< num 0)) | 1014 | (if (and (not calculator-2s-complement) (< num 0)) |
| 800 | (concat "-" str) | 1015 | (concat "-" str) |
| 801 | str)))) | 1016 | str)))) |
| 802 | ((and (numberp num) | 1017 | ((and (numberp num) (car calculator-displayers)) |
| 803 | ;; is this a normal-range number? | 1018 | (let ((disp (if (= 1 (length calculator-stack)) |
| 804 | (>= (abs num) calculator-number-exp-llimit) | 1019 | ;; customizable display for a single value |
| 805 | (< (abs num) calculator-number-exp-ulimit)) | 1020 | (caar calculator-displayers) |
| 806 | (let ((str (format calculator-number-format num))) | 1021 | calculator-displayer))) |
| 807 | (cond | 1022 | (cond ((stringp disp) (format disp num)) |
| 808 | ((and calculator-show-integers (string-match "\\.?0+$" str)) | 1023 | ((symbolp disp) (funcall disp num)) |
| 809 | ;; remove all redundant zeros | 1024 | ((and (consp disp) |
| 810 | (substring str 0 (match-beginning 0))) | 1025 | (eq 'std (car disp))) |
| 811 | ((and (not calculator-show-integers) | 1026 | (calculator-standard-displayer |
| 812 | (string-match "\\..\\(.*[^0]\\)?\\(0+\\)$" str)) | 1027 | num (cadr disp))) |
| 813 | ;; remove zeros, except for first after the "." | 1028 | ((listp disp) (eval disp)) |
| 814 | (substring str 0 (match-beginning 2))) | 1029 | (t (prin1-to-string num t))))) |
| 815 | (t str)))) | 1030 | ;; operators are printed here |
| 816 | ((numberp num) (format calculator-number-exp-format num)) | ||
| 817 | (t (prin1-to-string (nth 1 num) t)))) | 1031 | (t (prin1-to-string (nth 1 num) t)))) |
| 818 | 1032 | ||
| 819 | (defun calculator-update-display (&optional force) | 1033 | (defun calculator-update-display (&optional force) |
| @@ -851,6 +1065,9 @@ If optional argument FORCE is non-nil, don't use the cached string." | |||
| 851 | (goto-char (1+ (length calculator-prompt))) | 1065 | (goto-char (1+ (length calculator-prompt))) |
| 852 | (goto-char (1- (point))))) | 1066 | (goto-char (1- (point))))) |
| 853 | 1067 | ||
| 1068 | ;;;---------------------------------------------------------------------------- | ||
| 1069 | ;;; Stack computations | ||
| 1070 | |||
| 854 | (defun calculator-reduce-stack (prec) | 1071 | (defun calculator-reduce-stack (prec) |
| 855 | "Reduce the stack using top operator. | 1072 | "Reduce the stack using top operator. |
| 856 | PREC is a precedence - reduce everything with higher precedence." | 1073 | PREC is a precedence - reduce everything with higher precedence." |
| @@ -936,12 +1153,51 @@ PREC is a precedence - reduce everything with higher precedence." | |||
| 936 | (t ;; no more iterations | 1153 | (t ;; no more iterations |
| 937 | nil)))) | 1154 | nil)))) |
| 938 | 1155 | ||
| 1156 | (defun calculator-funcall (f &optional X Y) | ||
| 1157 | "If F is a symbol, evaluate (F X Y). | ||
| 1158 | Otherwise, it should be a list, evaluate it with X, Y bound to the | ||
| 1159 | arguments." | ||
| 1160 | ;; remember binary ops for calculator-repR/L | ||
| 1161 | (if Y (setq calculator-last-opXY (list f X Y))) | ||
| 1162 | (condition-case nil | ||
| 1163 | ;; there used to be code here that returns 0 if the result was | ||
| 1164 | ;; smaller than calculator-epsilon (1e-15). I don't think this is | ||
| 1165 | ;; necessary now. | ||
| 1166 | (if (symbolp f) | ||
| 1167 | (cond ((and X Y) (funcall f X Y)) | ||
| 1168 | (X (funcall f X)) | ||
| 1169 | (t (funcall f))) | ||
| 1170 | ;; f is an expression | ||
| 1171 | (let* ((__f__ f) ; so we can get this value below... | ||
| 1172 | (TX (calculator-truncate X)) | ||
| 1173 | (TY (and Y (calculator-truncate Y))) | ||
| 1174 | (DX (if calculator-deg (/ (* X pi) 180) X)) | ||
| 1175 | (L calculator-saved-list) | ||
| 1176 | (Fbound (fboundp 'F)) | ||
| 1177 | (Fsave (and Fbound (symbol-function 'F))) | ||
| 1178 | (Dbound (fboundp 'D)) | ||
| 1179 | (Dsave (and Dbound (symbol-function 'D)))) | ||
| 1180 | ;; a shortened version of flet | ||
| 1181 | (fset 'F (function | ||
| 1182 | (lambda (&optional x y) | ||
| 1183 | (calculator-funcall __f__ x y)))) | ||
| 1184 | (fset 'D (function | ||
| 1185 | (lambda (x) | ||
| 1186 | (if calculator-deg (/ (* x 180) pi) x)))) | ||
| 1187 | (unwind-protect (eval f) | ||
| 1188 | (if Fbound (fset 'F Fsave) (fmakunbound 'F)) | ||
| 1189 | (if Dbound (fset 'D Dsave) (fmakunbound 'D))))) | ||
| 1190 | (error 0))) | ||
| 1191 | |||
| 939 | (eval-when-compile ; silence the compiler | 1192 | (eval-when-compile ; silence the compiler |
| 940 | (or (fboundp 'event-key) | 1193 | (or (fboundp 'event-key) |
| 941 | (defun event-key (&rest _) nil)) | 1194 | (defun event-key (&rest _) nil)) |
| 942 | (or (fboundp 'key-press-event-p) | 1195 | (or (fboundp 'key-press-event-p) |
| 943 | (defun key-press-event-p (&rest _) nil))) | 1196 | (defun key-press-event-p (&rest _) nil))) |
| 944 | 1197 | ||
| 1198 | ;;;---------------------------------------------------------------------------- | ||
| 1199 | ;;; Input interaction | ||
| 1200 | |||
| 945 | (defun calculator-last-input (&optional keys) | 1201 | (defun calculator-last-input (&optional keys) |
| 946 | "Last char (or event or event sequence) that was read. | 1202 | "Last char (or event or event sequence) that was read. |
| 947 | Optional string argument KEYS will force using it as the keys entered." | 1203 | Optional string argument KEYS will force using it as the keys entered." |
| @@ -958,7 +1214,7 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 958 | ;; if Emacs will someday have a event-key, then this would | 1214 | ;; if Emacs will someday have a event-key, then this would |
| 959 | ;; probably be modified anyway | 1215 | ;; probably be modified anyway |
| 960 | (and (fboundp 'event-key) (key-press-event-p k) | 1216 | (and (fboundp 'event-key) (key-press-event-p k) |
| 961 | (setq k (event-key k))) | 1217 | (event-key k) (setq k (event-key k))) |
| 962 | ;; assume all symbols are translatable with an ascii-character | 1218 | ;; assume all symbols are translatable with an ascii-character |
| 963 | (and (symbolp k) | 1219 | (and (symbolp k) |
| 964 | (setq k (or (get k 'ascii-character) ? ))) | 1220 | (setq k (or (get k 'ascii-character) ? ))) |
| @@ -973,7 +1229,7 @@ OP is the operator (if any) that caused this call." | |||
| 973 | (= -1 (calculator-op-arity op)) | 1229 | (= -1 (calculator-op-arity op)) |
| 974 | (= 0 (calculator-op-arity op)))) | 1230 | (= 0 (calculator-op-arity op)))) |
| 975 | ;; reset if last calc finished, and now get a num or prefix or 0-ary | 1231 | ;; reset if last calc finished, and now get a num or prefix or 0-ary |
| 976 | ;; op. | 1232 | ;; op |
| 977 | (calculator-reset)) | 1233 | (calculator-reset)) |
| 978 | (setq calculator-display-fragile nil)) | 1234 | (setq calculator-display-fragile nil)) |
| 979 | 1235 | ||
| @@ -989,7 +1245,7 @@ OP is the operator (if any) that caused this call." | |||
| 989 | ((eq calculator-input-radix 'oct) (<= inp ?7)) | 1245 | ((eq calculator-input-radix 'oct) (<= inp ?7)) |
| 990 | (t t))) | 1246 | (t t))) |
| 991 | ;; enter digit if starting a new computation or have an op on the | 1247 | ;; enter digit if starting a new computation or have an op on the |
| 992 | ;; stack. | 1248 | ;; stack |
| 993 | (progn | 1249 | (progn |
| 994 | (calculator-clear-fragile) | 1250 | (calculator-clear-fragile) |
| 995 | (let ((digit (upcase (char-to-string inp)))) | 1251 | (let ((digit (upcase (char-to-string inp)))) |
| @@ -1008,7 +1264,7 @@ OP is the operator (if any) that caused this call." | |||
| 1008 | (not (and calculator-curnum | 1264 | (not (and calculator-curnum |
| 1009 | (string-match "[.eE]" calculator-curnum)))) | 1265 | (string-match "[.eE]" calculator-curnum)))) |
| 1010 | ;; enter the period on the same condition as a digit, only if no | 1266 | ;; enter the period on the same condition as a digit, only if no |
| 1011 | ;; period or exponent entered yet. | 1267 | ;; period or exponent entered yet |
| 1012 | (progn | 1268 | (progn |
| 1013 | (calculator-clear-fragile) | 1269 | (calculator-clear-fragile) |
| 1014 | (setq calculator-curnum (concat (or calculator-curnum "0") ".")) | 1270 | (setq calculator-curnum (concat (or calculator-curnum "0") ".")) |
| @@ -1023,7 +1279,7 @@ OP is the operator (if any) that caused this call." | |||
| 1023 | (not (numberp (car calculator-stack)))) | 1279 | (not (numberp (car calculator-stack)))) |
| 1024 | (not (and calculator-curnum | 1280 | (not (and calculator-curnum |
| 1025 | (string-match "[eE]" calculator-curnum)))) | 1281 | (string-match "[eE]" calculator-curnum)))) |
| 1026 | ;; same condition as above, also no E so far. | 1282 | ;; same condition as above, also no E so far |
| 1027 | (progn | 1283 | (progn |
| 1028 | (calculator-clear-fragile) | 1284 | (calculator-clear-fragile) |
| 1029 | (setq calculator-curnum (concat (or calculator-curnum "1") "e")) | 1285 | (setq calculator-curnum (concat (or calculator-curnum "1") "e")) |
| @@ -1033,53 +1289,66 @@ OP is the operator (if any) that caused this call." | |||
| 1033 | "Enter an operator on the stack, doing all necessary reductions. | 1289 | "Enter an operator on the stack, doing all necessary reductions. |
| 1034 | Optional string argument KEYS will force using it as the keys entered." | 1290 | Optional string argument KEYS will force using it as the keys entered." |
| 1035 | (interactive) | 1291 | (interactive) |
| 1036 | (let* ((last-inp (calculator-last-input keys)) | 1292 | (catch 'op-error |
| 1037 | (op (assoc last-inp calculator-operators))) | 1293 | (let* ((last-inp (calculator-last-input keys)) |
| 1038 | (calculator-clear-fragile op) | 1294 | (op (assoc last-inp calculator-operators))) |
| 1039 | (if (and calculator-curnum (/= (calculator-op-arity op) 0)) | 1295 | (calculator-clear-fragile op) |
| 1040 | (setq calculator-stack | 1296 | (if (and calculator-curnum (/= (calculator-op-arity op) 0)) |
| 1041 | (cons (calculator-curnum-value) calculator-stack))) | 1297 | (setq calculator-stack |
| 1042 | (setq calculator-curnum nil) | 1298 | (cons (calculator-curnum-value) calculator-stack))) |
| 1043 | (if (and (= 2 (calculator-op-arity op)) | 1299 | (setq calculator-curnum nil) |
| 1044 | (not (and calculator-stack | 1300 | (if (and (= 2 (calculator-op-arity op)) |
| 1045 | (numberp (nth 0 calculator-stack))))) | 1301 | (not (and calculator-stack |
| 1046 | ;; we have a binary operator but no number - search for a prefix | 1302 | (numberp (nth 0 calculator-stack))))) |
| 1047 | ;; version | 1303 | ;; we have a binary operator but no number - search for a prefix |
| 1048 | (let ((rest-ops calculator-operators)) | 1304 | ;; version |
| 1049 | (while (not (equal last-inp (car (car rest-ops)))) | 1305 | (let ((rest-ops calculator-operators)) |
| 1050 | (setq rest-ops (cdr rest-ops))) | 1306 | (while (not (equal last-inp (car (car rest-ops)))) |
| 1051 | (setq op (assoc last-inp (cdr rest-ops))) | 1307 | (setq rest-ops (cdr rest-ops))) |
| 1052 | (if (not (and op (= -1 (calculator-op-arity op)))) | 1308 | (setq op (assoc last-inp (cdr rest-ops))) |
| 1053 | (error "Binary operator without a first operand")))) | 1309 | (if (not (and op (= -1 (calculator-op-arity op)))) |
| 1054 | (calculator-reduce-stack | 1310 | ;;(error "Binary operator without a first operand") |
| 1055 | (cond ((eq (nth 1 op) '\() 10) | 1311 | (progn |
| 1056 | ((eq (nth 1 op) '\)) 0) | 1312 | (message "Binary operator without a first operand") |
| 1057 | (t (calculator-op-prec op)))) | 1313 | (if calculator-electric-mode |
| 1058 | (if (or (and (= -1 (calculator-op-arity op)) | 1314 | (progn (sit-for 1) (message nil))) |
| 1059 | (numberp (car calculator-stack))) | 1315 | (throw 'op-error nil))))) |
| 1060 | (and (/= (calculator-op-arity op) -1) | 1316 | (calculator-reduce-stack |
| 1061 | (/= (calculator-op-arity op) 0) | 1317 | (cond ((eq (nth 1 op) '\() 10) |
| 1062 | (not (numberp (car calculator-stack))))) | 1318 | ((eq (nth 1 op) '\)) 0) |
| 1063 | (error "Unterminated expression")) | 1319 | (t (calculator-op-prec op)))) |
| 1064 | (setq calculator-stack (cons op calculator-stack)) | 1320 | (if (or (and (= -1 (calculator-op-arity op)) |
| 1065 | (calculator-reduce-stack (calculator-op-prec op)) | 1321 | (numberp (car calculator-stack))) |
| 1066 | (and (= (length calculator-stack) 1) | 1322 | (and (/= (calculator-op-arity op) -1) |
| 1067 | (numberp (nth 0 calculator-stack)) | 1323 | (/= (calculator-op-arity op) 0) |
| 1068 | ;; the display is fragile if it contains only one number | 1324 | (not (numberp (car calculator-stack))))) |
| 1069 | (setq calculator-display-fragile t) | 1325 | ;;(error "Unterminated expression") |
| 1070 | ;; add number to the saved-list | 1326 | (progn |
| 1071 | calculator-add-saved | 1327 | (message "Unterminated expression") |
| 1072 | (if (= 0 calculator-saved-ptr) | 1328 | (if calculator-electric-mode |
| 1073 | (setq calculator-saved-list | 1329 | (progn (sit-for 1) (message nil))) |
| 1074 | (cons (car calculator-stack) calculator-saved-list)) | 1330 | (throw 'op-error nil))) |
| 1075 | (let ((p (nthcdr (1- calculator-saved-ptr) | 1331 | (setq calculator-stack (cons op calculator-stack)) |
| 1076 | calculator-saved-list))) | 1332 | (calculator-reduce-stack (calculator-op-prec op)) |
| 1077 | (setcdr p (cons (car calculator-stack) (cdr p)))))) | 1333 | (and (= (length calculator-stack) 1) |
| 1078 | (calculator-update-display))) | 1334 | (numberp (nth 0 calculator-stack)) |
| 1335 | ;; the display is fragile if it contains only one number | ||
| 1336 | (setq calculator-display-fragile t) | ||
| 1337 | ;; add number to the saved-list | ||
| 1338 | calculator-add-saved | ||
| 1339 | (if (= 0 calculator-saved-ptr) | ||
| 1340 | (setq calculator-saved-list | ||
| 1341 | (cons (car calculator-stack) calculator-saved-list)) | ||
| 1342 | (let ((p (nthcdr (1- calculator-saved-ptr) | ||
| 1343 | calculator-saved-list))) | ||
| 1344 | (setcdr p (cons (car calculator-stack) (cdr p)))))) | ||
| 1345 | (calculator-update-display)))) | ||
| 1079 | 1346 | ||
| 1080 | (defun calculator-op-or-exp () | 1347 | (defun calculator-op-or-exp () |
| 1081 | "Either enter an operator or a digit. | 1348 | "Either enter an operator or a digit. |
| 1082 | Used with +/- for entering them as digits in numbers like 1e-3." | 1349 | Used with +/- for entering them as digits in numbers like 1e-3 (there is |
| 1350 | no need for negative numbers since these are handled by unary | ||
| 1351 | operators)." | ||
| 1083 | (interactive) | 1352 | (interactive) |
| 1084 | (if (and (not calculator-display-fragile) | 1353 | (if (and (not calculator-display-fragile) |
| 1085 | calculator-curnum | 1354 | calculator-curnum |
| @@ -1087,6 +1356,9 @@ Used with +/- for entering them as digits in numbers like 1e-3." | |||
| 1087 | (calculator-digit) | 1356 | (calculator-digit) |
| 1088 | (calculator-op))) | 1357 | (calculator-op))) |
| 1089 | 1358 | ||
| 1359 | ;;;---------------------------------------------------------------------------- | ||
| 1360 | ;;; Input/output modes (not display) | ||
| 1361 | |||
| 1090 | (defun calculator-dec/deg-mode () | 1362 | (defun calculator-dec/deg-mode () |
| 1091 | "Set decimal mode for display & input, if decimal, toggle deg mode." | 1363 | "Set decimal mode for display & input, if decimal, toggle deg mode." |
| 1092 | (interactive) | 1364 | (interactive) |
| @@ -1136,6 +1408,9 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1136 | calculator-char-radix)))) | 1408 | calculator-char-radix)))) |
| 1137 | (calculator-update-display t)) | 1409 | (calculator-update-display t)) |
| 1138 | 1410 | ||
| 1411 | ;;;---------------------------------------------------------------------------- | ||
| 1412 | ;;; Saved values list | ||
| 1413 | |||
| 1139 | (defun calculator-save-on-list () | 1414 | (defun calculator-save-on-list () |
| 1140 | "Evaluate current expression, put result on the saved values list." | 1415 | "Evaluate current expression, put result on the saved values list." |
| 1141 | (interactive) | 1416 | (interactive) |
| @@ -1146,6 +1421,7 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1146 | "Clear the list of saved values in `calculator-saved-list'." | 1421 | "Clear the list of saved values in `calculator-saved-list'." |
| 1147 | (interactive) | 1422 | (interactive) |
| 1148 | (setq calculator-saved-list nil) | 1423 | (setq calculator-saved-list nil) |
| 1424 | (setq calculator-saved-ptr 0) | ||
| 1149 | (calculator-update-display t)) | 1425 | (calculator-update-display t)) |
| 1150 | 1426 | ||
| 1151 | (defun calculator-saved-move (n) | 1427 | (defun calculator-saved-move (n) |
| @@ -1175,6 +1451,9 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1175 | (interactive) | 1451 | (interactive) |
| 1176 | (calculator-saved-move -1)) | 1452 | (calculator-saved-move -1)) |
| 1177 | 1453 | ||
| 1454 | ;;;---------------------------------------------------------------------------- | ||
| 1455 | ;;; Misc functions | ||
| 1456 | |||
| 1178 | (defun calculator-open-paren () | 1457 | (defun calculator-open-paren () |
| 1179 | "Equivalents of `(' use this." | 1458 | "Equivalents of `(' use this." |
| 1180 | (interactive) | 1459 | (interactive) |
| @@ -1231,9 +1510,9 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1231 | "Copy current number to the `kill-ring'." | 1510 | "Copy current number to the `kill-ring'." |
| 1232 | (interactive) | 1511 | (interactive) |
| 1233 | (calculator-enter) | 1512 | (calculator-enter) |
| 1234 | ;; remove trailing .0 and spaces .0 | 1513 | ;; remove trailing spaces and and an index |
| 1235 | (let ((s (cdr calculator-stack-display))) | 1514 | (let ((s (cdr calculator-stack-display))) |
| 1236 | (if (string-match "^\\(.*[^ ]\\) *$" s) | 1515 | (if (string-match "^\\([^ ]+\\) *\\(\\[[0-9/]+\\]\\)? *$" s) |
| 1237 | (setq s (match-string 1 s))) | 1516 | (setq s (match-string 1 s))) |
| 1238 | (kill-new s))) | 1517 | (kill-new s))) |
| 1239 | 1518 | ||
| @@ -1264,8 +1543,18 @@ Used by `calculator-paste' and `get-register'." | |||
| 1264 | "Paste a value from the `kill-ring'." | 1543 | "Paste a value from the `kill-ring'." |
| 1265 | (interactive) | 1544 | (interactive) |
| 1266 | (calculator-put-value | 1545 | (calculator-put-value |
| 1267 | (condition-case nil (car (read-from-string (current-kill 0))) | 1546 | (let ((str (current-kill 0))) |
| 1268 | (error nil)))) | 1547 | (if calculator-paste-decimals |
| 1548 | (progn | ||
| 1549 | (string-match "\\([0-9]+\\)\\(\\.[0-9]+\\)?\\(e[0-9]+\\)?" str) | ||
| 1550 | (if (or (match-string 1 str) | ||
| 1551 | (match-string 2 str) | ||
| 1552 | (match-string 3 str)) | ||
| 1553 | (setq str (concat (match-string 1 str) | ||
| 1554 | (or (match-string 2 str) ".0") | ||
| 1555 | (match-string 3 str)))))) | ||
| 1556 | (condition-case nil (car (read-from-string str)) | ||
| 1557 | (error nil))))) | ||
| 1269 | 1558 | ||
| 1270 | (defun calculator-get-register (reg) | 1559 | (defun calculator-get-register (reg) |
| 1271 | "Get a value from a register REG." | 1560 | "Get a value from a register REG." |
| @@ -1279,8 +1568,8 @@ Used by `calculator-paste' and `get-register'." | |||
| 1279 | + - * / \\(div) %(rem) _(-X,postfix) ;(1/X,postfix) ^(exp) L(og) | 1568 | + - * / \\(div) %(rem) _(-X,postfix) ;(1/X,postfix) ^(exp) L(og) |
| 1280 | Q(sqrt) !(fact) S(in) C(os) T(an) |(or) #(xor) &(and) ~(not) | 1569 | Q(sqrt) !(fact) S(in) C(os) T(an) |(or) #(xor) &(and) ~(not) |
| 1281 | * >/< repeats last binary operation with its 2nd (1st) arg as postfix op | 1570 | * >/< repeats last binary operation with its 2nd (1st) arg as postfix op |
| 1282 | * I inverses next trig function | 1571 | * I inverses next trig function * '/\"/{} - display/display args |
| 1283 | * D - switch to all-decimal mode, or toggles deg/rad mode | 1572 | * D - switch to all-decimal, or toggle deg/rad mode |
| 1284 | * B/O/H/X - binary/octal/hex mode for i/o (X is a shortcut for H) | 1573 | * B/O/H/X - binary/octal/hex mode for i/o (X is a shortcut for H) |
| 1285 | * i/o - prefix for d/b/o/x - set only input/output modes | 1574 | * i/o - prefix for d/b/o/x - set only input/output modes |
| 1286 | * enter/= - evaluate current expr. * s/g - set/get a register | 1575 | * enter/= - evaluate current expr. * s/g - set/get a register |
| @@ -1343,43 +1632,6 @@ Used by `calculator-paste' and `get-register'." | |||
| 1343 | (calculator-copy) | 1632 | (calculator-copy) |
| 1344 | (calculator-quit)) | 1633 | (calculator-quit)) |
| 1345 | 1634 | ||
| 1346 | (defun calculator-funcall (f &optional X Y) | ||
| 1347 | "If F is a symbol, evaluate (F X Y). | ||
| 1348 | Otherwise, it should be a list, evaluate it with X, Y bound to the | ||
| 1349 | arguments." | ||
| 1350 | ;; remember binary ops for calculator-repR/L | ||
| 1351 | (if Y (setq calculator-last-opXY (list f X Y))) | ||
| 1352 | (condition-case nil | ||
| 1353 | (let ((result | ||
| 1354 | (if (symbolp f) | ||
| 1355 | (cond ((and X Y) (funcall f X Y)) | ||
| 1356 | (X (funcall f X)) | ||
| 1357 | (t (funcall f))) | ||
| 1358 | ;; f is an expression | ||
| 1359 | (let* ((__f__ f) ; so we can get this value below... | ||
| 1360 | (TX (calculator-truncate X)) | ||
| 1361 | (TY (and Y (calculator-truncate Y))) | ||
| 1362 | (DX (if calculator-deg (/ (* X pi) 180) X)) | ||
| 1363 | (L calculator-saved-list) | ||
| 1364 | (Fbound (fboundp 'F)) | ||
| 1365 | (Fsave (and Fbound (symbol-function 'F))) | ||
| 1366 | (Dbound (fboundp 'D)) | ||
| 1367 | (Dsave (and Dbound (symbol-function 'D)))) | ||
| 1368 | ;; a shortened version of flet | ||
| 1369 | (fset 'F (function | ||
| 1370 | (lambda (&optional x y) | ||
| 1371 | (calculator-funcall __f__ x y)))) | ||
| 1372 | (fset 'D (function | ||
| 1373 | (lambda (x) | ||
| 1374 | (if calculator-deg (/ (* x 180) pi) x)))) | ||
| 1375 | (unwind-protect (eval f) | ||
| 1376 | (if Fbound (fset 'F Fsave) (fmakunbound 'F)) | ||
| 1377 | (if Dbound (fset 'D Dsave) (fmakunbound 'D))))))) | ||
| 1378 | (if (< (abs result) calculator-epsilon) | ||
| 1379 | 0 | ||
| 1380 | result)) | ||
| 1381 | (error 0))) | ||
| 1382 | |||
| 1383 | (defun calculator-repR (x) | 1635 | (defun calculator-repR (x) |
| 1384 | "Repeats the last binary operation with its second argument and X. | 1636 | "Repeats the last binary operation with its second argument and X. |
| 1385 | To use this, apply a binary operator (evaluate it), then call this." | 1637 | To use this, apply a binary operator (evaluate it), then call this." |