5

I have in my .emacs:

(when (>= emacs-major-version 23)
  (define-key global-map "\C-x8g" (lambda nil (interactive) (ucs-insert `,(cdr (assoc-string "HRYVNIA SIGN" (ucs-names) t)))))
  (define-key global-map "\C-x8e" (lambda nil (interactive) (ucs-insert `,(cdr (assoc-string "EURO SIGN" (ucs-names) t)))))
  )

and with Cygwin Emacs-w32 v26 for:

(assoc-string "EURO SIGN" (ucs-names) t)

I get nil. Is it a bug? How can I get character by Unicode symbol name compatible with Emacs 24/25/26?

Drew
  • 75,699
  • 9
  • 109
  • 225
gavenkoa
  • 3,352
  • 19
  • 36
  • I do wonder: why are you poking around in ucs-names? What prevents you from just doing `(insert-char ?₴)` directly? – rpluim Jul 19 '18 at 08:11
  • 1
    My `.emacs` had `-*- coding: cp1251 -*-` in 2008... I've changed it to utf-8 but habits have remained since that time. – gavenkoa Jul 19 '18 at 08:44
  • 1
    You can use Unicode escape syntax: `(insert-char ?\N{HRYVNIA SIGN})` – link0ff Jul 31 '19 at 23:10

2 Answers2

5

Do this, instead, starting with Emacs 26:

(gethash "EURO SIGN" (ucs-names))

In other words, use something like this:

(if (> emacs-major-version 25)
    (gethash "EURO SIGN" (ucs-names))
  (cdr (assoc-string "EURO SIGN" (ucs-names) t)))

Unfortunately, for people trying to provide backward-compatibility, they made an incompatible change in ucs-names, from using an alist to using a hash table, in Emacs 26.

Using a hash table is a good idea (more performant), but it breaks backward-compatibility.

They could have made ucs-names test the Emacs version and do the right thing for each version, but (unfortunately) Emacs Dev apparently didn't care about backward compatibility in this case, even though providing compatibility is simple here.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • "Emacs Dev doesn't really care about backward compatibility" - hmm, that's not my experience. It feels like you're generalizing from this specific case, which to me looks like it was an oversight. – npostavs Jul 30 '19 at 19:29
  • Updated to be specific to this case - thanks. IMO it's also the case more generally that backward compatibility is not always a very high priority. But yes, backward compatibility is considered. Let's just say that it's not considered as much as I would like. – Drew Jul 30 '19 at 20:57
  • My imagination must be failing me today: how could ucs-names have switched to using a hash table whilst maintaining backward compatibility? Or are you saying the hash table version should have had a different name? – rpluim Jul 31 '19 at 08:44
1

I ended with:

(defun my--get-char (name)
  "Get character by Unicode `name'."
  (cond
   ((>= 26 emacs-major-version)
    (gethash name (ucs-names)))
   ((>= 23 emacs-major-version)
    (cdr (assoc-string name (ucs-names))))
   (t (error "Emacs version is too old and lacks Unicode support..."))))

(when (>= emacs-major-version 23)
  (define-key global-map "\C-x8g" (lambda nil (interactive) (ucs-insert (my--get-char "HRYVNIA SIGN"))))
  (define-key global-map "\C-x8e" (lambda nil (interactive) (ucs-insert (my--get-char "EURO SIGN"))))
  )
gavenkoa
  • 3,352
  • 19
  • 36
  • 2
    Why the `t` as default value for the `gethash` call? Do you really want it to return `t` if the char cannot be found? E.g., `(gethash "NONSENSE" (ucs-names) t)` returns `t`, not a char and not `nil`. Maybe you meant to use the `t` with `assoc-string`, which lets `name` be any case (lower, upper, mixed)? – Drew Jul 19 '18 at 04:01
  • @Drew Fixed, thanks! – gavenkoa Jul 28 '19 at 10:49