* lisp/calculator.el: more improvements and bugfixes.

- Mark `calculator-paste-decimals' as obsolete.  (It wasn't having an
  effect anyway.)

- Simplify `calculator-number-to-string' by throwing most of the work
  onto `number-to-string', leaving just some tweaks for decimal inputs.
  This leads to some minor changes, for example, pasting "1x1" in hex
  mode would warn that "x" is ignored and result in "11" (and it wasn't
  done in decimal mode), whereas now it just ignores everything from the
  "x" and on and result in a "1" just like in decimal input mode.  Also,
  overflows are left for `number-to-string' to deal with.

- `calculator-paste' is very simple as a result.

- Extend the simplified `calculator-paste': with a prefix argument it
  pastes a string as if the characters were entered.  This can be used
  to reduce expressions, but note that it's a simple literal operation,
  so precedence can be messed, a number can be paster while entering a
  number, spaces and newlines matter, etc.

- Fix a minor bug where "e+" in hex mode wouldn't use "+" as an
  operator.

- Fix a bug in `calculator-put-value': avoid grouping in the display
  that is used to construct `calculator-curnum'.  This would trigger
  when pasting or getting a value from a register in some radix mode
  with a large enough value.  Another fix: make the output radix equal
  the input one, otherwise numbers could be converted twice.
This commit is contained in:
Eli Barzilay 2015-11-29 15:24:27 -05:00
parent 1b4570bc08
commit f248292ede

View file

@ -161,6 +161,8 @@ This makes it possible to paste big integers since they will be read as
floats, otherwise the Emacs reader will fail on them." floats, otherwise the Emacs reader will fail on them."
:type 'boolean :type 'boolean
:group 'calculator) :group 'calculator)
(make-obsolete-variable 'calculator-paste-decimals
"it is no longer used." nil)
(defcustom calculator-copy-displayer nil (defcustom calculator-copy-displayer nil
"If non-nil, this is any value that can be used for "If non-nil, this is any value that can be used for
@ -855,39 +857,13 @@ The result should not exceed the screen width."
"Convert the given STR to a number, according to the value of "Convert the given STR to a number, according to the value of
`calculator-input-radix'." `calculator-input-radix'."
(if calculator-input-radix (if calculator-input-radix
(let ((radix (string-to-number str (cadr (assq calculator-input-radix
(cdr (assq calculator-input-radix '((bin 2) (oct 8) (hex 16)))))
'((bin . 2) (oct . 8) (hex . 16))))) (let* ((str (replace-regexp-in-string
(i -1) (value 0) (new-value 0)) "\\.\\([^0-9].*\\)?$" ".0\\1" str))
;; assume mostly valid input (e.g., characters in range) (str (replace-regexp-in-string
(while (< (setq i (1+ i)) (length str)) "[eE][+-]?\\([^0-9].*\\)?$" "e0\\1" str)))
(setq new-value (string-to-number str))))
(let* ((ch (upcase (aref str i)))
(n (cond ((< ch ?0) nil)
((<= ch ?9) (- ch ?0))
((< ch ?A) nil)
((<= ch ?Z) (- ch (- ?A 10)))
(t nil))))
(if (and n (<= 0 n) (< n radix))
(+ n (* radix value))
(progn
(calculator-message
"Warning: Ignoring bad input character `%c'." ch)
(sit-for 1)
value))))
(when (if (< new-value 0) (> value 0) (< value 0))
(calculator-message "Warning: Overflow in input."))
(setq value new-value))
value)
(car (read-from-string
(cond ((equal "." str) "0.0")
((string-match-p "[eE][+-]?$" str) (concat str "0"))
((string-match-p "\\.[0-9]\\|[eE]" str) str)
((string-match-p "\\." str)
;; do this because Emacs reads "23." as an integer
(concat str "0"))
((stringp str) (concat str ".0"))
(t "0.0"))))))
(defun calculator-push-curnum () (defun calculator-push-curnum ()
"Push the numeric value of the displayed number to the stack." "Push the numeric value of the displayed number to the stack."
@ -1329,7 +1305,8 @@ Used with +/- for entering them as digits in numbers like 1e-3 (there is
no need for negative numbers since these are handled by unary no need for negative numbers since these are handled by unary
operators)." operators)."
(interactive) (interactive)
(if (and (not calculator-display-fragile) (if (and (not calculator-input-radix)
(not calculator-display-fragile)
calculator-curnum calculator-curnum
(string-match-p "[eE]$" calculator-curnum)) (string-match-p "[eE]$" calculator-curnum))
(calculator-digit) (calculator-digit)
@ -1497,25 +1474,27 @@ Used by `calculator-paste' and `get-register'."
(or calculator-display-fragile (or calculator-display-fragile
(not (numberp (car calculator-stack))))) (not (numberp (car calculator-stack)))))
(calculator-clear-fragile) (calculator-clear-fragile)
(setq calculator-curnum (let ((calculator-displayer "%S")) (setq calculator-curnum
(calculator-number-to-string val))) (let ((calculator-displayer "%S")
(calculator-radix-grouping-mode nil)
(calculator-output-radix calculator-input-radix))
(calculator-number-to-string val)))
(calculator-update-display))) (calculator-update-display)))
(defun calculator-paste () (defun calculator-paste (arg)
"Paste a value from the `kill-ring'." "Paste a value from the `kill-ring'.
(interactive)
(calculator-put-value With a prefix argument, paste the raw string as a sequence of key
(let ((str (replace-regexp-in-string presses, which can be used to paste expressions. Note that this
"^ *\\(.+[^ ]\\) *$" "\\1" (current-kill 0)))) is literal; examples: spaces will store values, pasting \"1+2\"
(when (and (not calculator-input-radix) will not produce 3 if it's done you're entering a number or after
calculator-paste-decimals a multiplication."
(string-match (interactive "P")
"\\([0-9]+\\)\\(\\.[0-9]+\\)?\\(e[0-9]+\\)?" (let ((str (current-kill 0)))
str)) (if arg
(setq str (concat (or (match-string 1 str) "0") (setq unread-command-events
(or (match-string 2 str) ".0") `(,@(listify-key-sequence str) ,@unread-command-events))
(or (match-string 3 str) "")))) (calculator-put-value (calculator-string-to-number str)))))
(ignore-errors (calculator-string-to-number str)))))
(defun calculator-register-read-with-preview (prompt) (defun calculator-register-read-with-preview (prompt)
"Similar to `register-read-with-preview' but for calculator "Similar to `register-read-with-preview' but for calculator