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...

  • 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
4

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))))))))
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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.