GNU bug report logs - #79026
30.1; TAB in Minibuffer when using a quail input-method should complete the longest common suffix of candidates

Previous Next

Package: emacs;

Reported by: Cass Alexandru <g.cassian.alexandru <at> posteo.eu>

Date: Tue, 15 Jul 2025 12:30:02 UTC

Severity: wishlist

Found in version 30.1

Full log


View this message in rfc822 format

From: Visuwesh <visuweshm <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: Arash Esbati <arash <at> gnu.org>, Cass Alexandru <g.cassian.alexandru <at> posteo.eu>, 79026 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: bug#79026: 30.1; TAB in Minibuffer when using a quail input-method should complete the longest common suffix of candidates
Date: Wed, 16 Jul 2025 20:39:41 +0530
[செவ்வாய் ஜூலை 15, 2025] Eli Zaretskii wrote:

> It doesn't look like quail-completion (which is the command bound to
> TAB in that input method) is supposed to work as you expect.  Instead,
> it is a fancy visual feedback for typing long sequences, fancier than
> what Emacs usually shows in the echo-area (which is just the list of
> candidates for the next character).
>
> IOW, after pressing TAB, you are supposed to:
>
>   . realize that there's just one candidate "\above"
>   . type its characters one by one, guided by the moving highlight in
>     the *Quail Completions* buffer as you go
>
> Stefan and Arash, am I right?

Looking at quail-completion, it only seems to list the possible
translations and their keys.  There is quail-choose-completion but it
seems to be broken (it inserts the same translation twice when trying it
with tamil-phonetic), and does not work at all for TeX (maybe because of
non-nil TRANSLATION-KEYS (why BTW?)).  If it works, then you can click
on the translation shown in *Quail Completions* to insert it.

I gave a shot implementing a CAPF for Quail but it does not "recontinue"
the translation process if one "rejects" the completion completely i.e.,
using C-g.

To try it out, evaluate the following in emacs -Q

    (defun vz/quail--string (def key)
      "Return the translation of KEY as specified by DEF."
      (let ((translation (quail-get-translation (car def) key (length key))))
        (if (characterp translation)
            (string translation)
          ;; When there are multiple candidates, then a vector is
          ;; returned.
          (and (consp translation)
               (append (cdr translation) nil)))))

    (defun vz/quail--candidates (key &optional map candidates)
      "Return an alist of translations and corresponding keys leading from KEY.
    The optional argument MAP is the `quail-map' for KEY, and CANDIDATES is
    an internal variable."
      (let* ((map (or map (quail-lookup-key key nil t)))
             (map (if (and (symbolp map) (functionp map))
                      (funcall map key (length key))
                    map)))
        ;; If car of MAP is non-nil, then KEY translates to car of MAP.
        (when (car map)
          (let ((translation (vz/quail--string map key)))
            (if (stringp translation)
                (push (cons translation key) candidates)
              (dolist (tr translation)
                (push (cons tr key) candidates)))))
        ;; If cdr of MAP is non-nil, then the translation continues on
        ;; forward.
        (when (cdr map)
          ;; See `quail-completion-1'.
          (dolist (rest (if (functionp (cdr map))
                            (funcall (cdr map))
                          (cdr map)))
            (setq candidates
                  (append (vz/quail--candidates (concat key (string (car rest)))
                                                (cdr rest))
                          candidates))))
        candidates))

    (defun vz/quail--capf ()
      (let ((candidates (vz/quail--candidates quail-current-key)))
        ;; For `quail-overlay', see `quail-delete-region'.
        (when (and candidates (overlay-start quail-overlay)))
        (quail-delete-region)
        (list (overlay-start quail-overlay)
              (overlay-end quail-overlay)
              (completion-table-with-metadata
               candidates
               `((annotation-function
                  . ,(lambda (string)
                       (concat "\t← " (cdr (assoc string candidates)))))))
              :exit-function
              (lambda (string status)
                (when (memq status '(finished sole))
                  ;; Setting to nil is required for sole candidate.
                  (setq quail-current-str nil)
                  (quail-terminate-translation))))))

    (defun vz/quail-complete-at-point ()
      (interactive)
      (let ((completion-at-point-functions (list #'vz/quail--capf)))
        (completion-at-point)))

    (with-temp-buffer
      ;; Load the TeX IM.
      (let (message-log-max) (activate-input-method "TeX"))
      (let ((quail-current-package (assoc "TeX" quail-package-alist)))
        (define-key (nth 5 quail-current-package)
                    (kbd "TAB")
                    #'vz/quail-complete-at-point)))

    (define-key quail-translation-keymap (kbd "TAB") #'vz/quail-complete-at-point)

and say C-u C-\ TeX RET to activate the TeX IM.  Then say \al TAB which
should pop up the *Completions* buffer from which you can select the
desired translation.  For reasons I have not explored, M-<up> and
M-<down> does not work and kills the completion.  




This bug report was last modified 65 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.