How can i achieve my goal? Should i take another approach?
IIUC the problem arises from a misuse of
nconc. The value of
unread-command-events is often
nil, in which case
nconc will not alter it in-place, as there is no
cdr to modify. Instead, you should probably be using
setq to record the value change of
invocation of command does nothing
unread-test is rewritten as
(defun unread-test ()
"Repeat input after toggling input method."
(nconc (listify-key-sequence "Hello, World!") unread-command-events)))
then invoking it will cause the characters corresponding to
Hello, World! to be inserted into the current (writable) buffer.
From OP's comment:
I would like my command to allow me to fix strings that were typed with wrong input method. See http://paste.lisp.org/+7OXT for example
Here is a listing of the linked example, for posterity:
(defun krv/punto (p m)
"Repeat input after toggling input method"
(interactive (if (use-region-p)
(list (region-beginning) (region-end))
(let* ((region-string (buffer-substring p m))
(if (not old-input-method)
;; if there is no current input method, just take character
;; we have imput method, try to translate characters back
(let ((quail-list (quail-find-key ch)))
(if (equal quail-list t)
(cl-mapcan (lambda (str) (listify-key-sequence str))
(delete-region p m)
(setq unread-command-events (nconc unread-command-events input-keys)))
This example behaved as intended for me after only a little bit of tweaking. Specifically, having mandatory arguments means the
interactive spec cannot just return
nil; either it must return
'(nil nil) or the arguments must be optional. The latter option makes more sense to me in this case, as the function changes its behaviour subject to whether the region is active.
Below is my attempt at correcting this hiccup and simplifying the code overall:
(defun krv/punto (&optional beg end)
"Toggle input method and repeat any input in region."
(interactive (and (use-region-p)
(list (region-beginning) (region-end))))
(let ((events (and beg end
(mapcan (lambda (char)
(let ((keys (quail-find-key char)))
(if (consp keys)
(mapcan #'listify-key-sequence keys)
(delete-and-extract-region beg end)))))
(setq unread-command-events (nconc events unread-command-events))))
- This follows the suggestion in
(elisp) Event Input Misc of prepending, instead of appending, to
- If you are not yet running Emacs 25 you can use
cl-mapcan in place of
mapcan as you did before.
You can invert the innermost
if form as follows, if you prefer:
(if (booleanp keys)
(mapcan #'listify-key-sequence keys))
What's interesting is that Emacs includes the package
robin.el, which is a newer and simpified version of
quail.el supporting precisely your intended behaviour - translating buffer regions back and forth between input methods. The package implementation can afford to be very simple because it only strives to achieve a subset of its predecessor's functionality. In particular, it forgoes CJK character support. I think it's a (understandable) shame that barely any input methods use it.