4

I know I can yank into the stack in calc using C-y. However, it seems that calc automatically assumes that I'm yanking in a base-10 number. If I try to specify a radix (like 16# for hex) before yanking and then pressing C-y I get the error message [Bad format] from (calcDigit-nondigit).

If I actually prefix my killed text with 16# then it works, but that's a little tedious. Is there any way to tell calc "hey, I'm about to yank a number of base n"?


Concrete examples:

(1) yank a hex number with hex set as calc's default radix (doesn't work)

  1. Kill the following text: deadbeef
  2. Switch to a calc buffer
  3. Make hex the default radix with d 6
  4. Hit C-y

(2) yank a hex number, with radix prefix typed into calc minibuffer (doesn't work)

  1. Kill the following text: deadbeef
  2. Switch to a calc buffer
  3. Tell calc that we're about to enter a hex number by typing 16#
  4. Hit C-y

(3) yank a hex number along with the necessary calc radix prefix (works)

  1. Kill the following text: 16#deadbeef
  2. Switch to a calc buffer
  3. Hit C-y

(3) works, but I'd like to get either (1) or (2) working. If (3) is the only option I guess I'll write my own function to prepend my last kill with a calc radix prefix...

mgalgs
  • 474
  • 4
  • 12
  • I'm afraid there's no way to do that since the string deadbeef is a valid Calc identifier, i.e. it could just name a variable or a function, so it would be wrong to interpret it as a number. – wvxvw Jun 25 '15 at 21:46
  • Hmm, but if I type 16#deadbeef it doesn't interpret it as an identifier... Why does it do so when I yank the text deadbeef after typing 16#? – mgalgs Jun 25 '15 at 22:11
  • An identifier syntax must start with a non-digit, while number must start with a digit. It's a bit more complex than that (punctuation etc), but for this example it should explain the reason. – wvxvw Jun 25 '15 at 22:51

2 Answers2

5

Update (Oct 12 2015)

Below calc-yank implementation is now added to emacs trunk.

It will be available in the next stable emacs release.


I reviewed the original definition of calc-yank and the good thing is that it does not have any argument. So I added my own argument, radix, and slightly modified how the let-bound var thing is derived.

By default, the below modified function will work the exact same as the original calc-yank.

But if you want to yank the value in the kill ring as a hexadecimal number, you will be able to now do so now by doing C-u 6 C-y or C-6 C-y or M-6 C-y.

To test it, copy 1000 to the kill-ring.

Then,

  • C-2 C-y will paste 8 (2#1000),
  • C-8 C-y will paste 512 (8#1000),
  • C-0 C-y will paste 1000 (10#1000),
  • C-6 C-y will paste 4096 (16#1000)

.. and C-y will paste 1000 (1000).

(defun calc-yank (radix)
          "Yank a value into the Calculator buffer.

Valid numeric prefixes for RADIX: 0, 2, 6, 8 No radix notation is prepended for any other numeric prefix.

If RADIX is 2, prepend "2#" - Binary. If RADIX is 8, prepend "8#" - Octal. If RADIX is 0, prepend "10#" - Decimal. If RADIX is 6, prepend "16#" - Hexadecimal.

If RADIX is a non-nil list (created using \[universal-argument]), the user will be prompted to enter the radix in the minibuffer.

If RADIX is nil or if the yanked string already has a calc radix prefix, the yanked string will be passed on directly to the Calculator buffer without any alteration." (interactive "P") (calc-wrapper (calc-pop-push-record-list 0 "yank" (let* (radix-num radix-notation valid-num-regexp (thing-raw (if (fboundp 'current-kill) (current-kill 0 t) (car kill-ring-yank-pointer))) (thing (if (or (null radix) ;; Match examples: -2#10, 10\n(10#10,01) (string-match-p "^[-(][0-9]\{1,2\}#" thing-raw)) thing-raw (progn (if (listp radix) (progn (setq radix-num (read-number "Set radix for yanked content (2-36): ")) (when (not (and (integerp radix-num) (<= 2 radix-num) (>= 36 radix-num))) (error (concat "The radix has to be an " "integer between 2 and 36.")))) (setq radix-num (cond ((eq radix 2) 2) ((eq radix 8) 8) ((eq radix 0) 10) ((eq radix 6) 16) (t (message (concat "No radix prepended " "for invalid numeric* " "prefix %0d.") radix) nil)))) (if radix-num (progn (setq radix-notation (concat (number-to-string radix-num) "#")) (setq valid-num-regexp (cond ;; radix 2 to 10 ((and (<= 2 radix-num) (>= 10 radix-num)) (concat "[0-" (number-to-string (1- radix-num)) "]+")) ;; radix 11 ((= 11 radix-num) "[0-9aA]+") ;; radix 12+ (t (concat "[0-9" "a-" (format "%c" (+ 86 radix-num)) "A-" (format "%c" (+ 54 radix-num)) "]+")))) ;; Ensure that the radix-notation is prefixed ;; correctly even for multi-line yanks like below, ;; 111 ;; 1111 (replace-regexp-in-string valid-num-regexp (concat radix-notation "\&") thing-raw)) thing-raw))))) (if (eq (car-safe calc-last-kill) thing) (cdr calc-last-kill) (if (stringp thing) (let ((val (math-read-exprs (calc-clean-newlines thing)))) (if (eq (car-safe val) 'error) (progn (setq val (math-read-exprs thing)) (if (eq (car-safe val) 'error) (error "Bad format in yanked data") val)) val))))))))

Kaushal Modi
  • 25,651
  • 4
  • 80
  • 183
0

You ask:

Is there any way to tell calc "hey, I'm about to yank a number of base n"?

Unfortunately no. In the Calc manual I found this:

Numbers are not stored with any particular radix attached. 

However, you could try storing and yanking from registers.

r i (calc-insert-register)
Emacs User
  • 5,643
  • 18
  • 48