Subject: Re: bug#43120: 28.0.50; fido-mode: M-j before completions appear selects wrong choice

From: João Távora <[email-masked]>
Date: Wed, 09 Sep 2020 23:08:44 +0100

Stefan Monnier <[email-masked]> writes:

>> Alternatively (and a bit sillily), two remaps for two different commands:
>> one for exit-minibuffer and one for minibuffer-complete-and-exit.
>
> I'd go with that, yes,
>
> Also, because it will handle the case where the user has added a binding
> to `minibuffer-complete-and-exit` to the keymap where RET is bound to
> `exit-minibuffer`.

OK, how's this look?

Though I'm starting to think that when require-match is nil, an
icomplete user wouldn't want the new icomplete-show-matches-on-no-input
behaviour anyway.  But I'm not one of those.  Else, if she does, doesn't
it mean she wants fido-mode instead?

The question is thus: remap exit-minibuffer or not?  It means usually:
exit with whatever has been input, which may well be the empty string.

João

diff --git a/lisp/icomplete.el b/lisp/icomplete.el
index 4e546807b7..6d48aa84d4 100644
--- a/lisp/icomplete.el
+++ b/lisp/icomplete.el
@@ -157,21 +157,31 @@ icomplete-post-command-hook
 (defvar icomplete-minibuffer-map
   (let ((map (make-sparse-keymap)))
     (define-key map [?\M-\t] 'icomplete-force-complete)
-    (define-key map [remap minibuffer-complete-and-exit] 'icomplete-ret)
+    (define-key map [remap minibuffer-complete-and-exit] 'icomplete-complete-and-exit)
+    (define-key map [remap exit-minibuffer] 'icomplete-exit)
     (define-key map [?\C-j]  'icomplete-force-complete-and-exit)
     (define-key map [?\C-.]  'icomplete-forward-completions)
     (define-key map [?\C-,]  'icomplete-backward-completions)
     map)
   "Keymap used by `icomplete-mode' in the minibuffer.")
 
-(defun icomplete-ret ()
-  "Exit minibuffer for icomplete."
-  (interactive)
+(defun icomplete--maybe-force (fallback)
+  "Helper for `icomplete-complete-and-exit' and `icomplete-exit'."
   (if (and icomplete-show-matches-on-no-input
            (car completion-all-sorted-completions)
            (eql (icomplete--field-end) (icomplete--field-beg)))
       (icomplete-force-complete-and-exit)
-    (minibuffer-complete-and-exit)))
+    (funcall fallback)))
+
+(defun icomplete-complete-and-exit ()
+  "Complete, then exit minibuffer for icomplete."
+  (interactive)
+  (icomplete--maybe-force #'minibuffer-complete-and-exit))
+
+(defun icomplete-exit ()
+  "Exit minibuffer for icomplete."
+  (interactive)
+  (icomplete--maybe-force #'exit-minibuffer))
 
 (defun icomplete-force-complete-and-exit ()
   "Complete the minibuffer with the longest possible match and exit.