unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Felician Nemeth <felician.nemeth@gmail.com>
To: Lars Ingebrigtsen <larsi@gnus.org>
Cc: 47215@debbugs.gnu.org
Subject: bug#47215: 28.0.50; Let M-x switch between M-x and M-X
Date: Sat, 10 Apr 2021 19:56:49 +0200	[thread overview]
Message-ID: <87r1ji3twe.fsf@betli.tmit.bme.hu> (raw)
In-Reply-To: <87czv9g74a.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sun, 04 Apr 2021 21:52:21 +0200")

[-- Attachment #1: Type: text/plain, Size: 1842 bytes --]

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Felician Nemeth <felician.nemeth@gmail.com> writes:
>
>>> I'm not quite sure how to implement this, though -- we basically end up
>>> in `completing-read', and `execute-extended-command-for-buffer' would
>>> have to define an `M-x' binding there, I guess...  and then somehow call
>>> `read-extended-command' with the text already in the minibuffer.
>>>
>>> Anybody got an idea as to how to implement this without rewriting
>>> `read-extended-command' completely?
>>
>> The execute-extended-commands have two undocumented optional arguments
>> (command-name and typed).  What are they used for?
>>
>> Anyway, following the fallback logic of `ido-find-file', I was able to
>> rebind `M-x' and save the content of the minibuffer with a non-standard
>> exit from `execute-extended-command'.  Maybe the ugly code below can
>> give ideas to someone more knowledgeable.
>
> Thanks -- I was wondering more about the situation where you've typed
>
> M-X foo|bar
>
> (| for point)
>
> and then hit `M-x' because you want to switch to the other mode.
> Ideally, `M-x' should do that, and also preserve the text the user has
> typed, and the cursor position.  I don't see an obvious simple way to do
> that... 

I've discovered that the initial-input argument of `completing-read` can
be written as (STRING . POSITION).  The attached patch makes use of it
and shows a simple implementation of my original wish.

However, the patch creates code duplication.  Also, I don't know how it
copes with recursive editing: maybe it's not a good idea to rebind M-x
when `enable-recursive-minibuffers' is t.  Finally, the docstring says
initial-input is deprecated.

I'm happy to work on the patch if you guide me to the right direction,
but this time I'd rather receive a fish instead of being taught how to
fish :)


[-- Attachment #2: m-x.patch --]
[-- Type: #("text/x-diff" 0 11 (face iswitchb-current-match)), Size: 4324 bytes --]

diff --git a/lisp/simple.el b/lisp/simple.el
index c48e644345..1bd8ba5993 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -1949,7 +1949,46 @@ read-extended-command-predicate
                         command-completion-default-include-p)
                  (function :tag "Other function")))
 
-(defun read-extended-command ()
+(defun execute-extended-command--cycle ()
+  (interactive)
+  (throw 'cycle
+         (cons 'cycle (cons (minibuffer-contents)
+                            (- (point) (minibuffer-prompt-end))))))
+
+(defun read-extended-command (&optional prompt)
+  (let ((minibuffer-local-must-match-map minibuffer-local-must-match-map)
+        (read-extended-command-predicate read-extended-command-predicate)
+        initial-input ret)
+    (define-key minibuffer-local-must-match-map
+      (kbd "M-x") #'execute-extended-command--cycle)
+    (while (not ret)
+      (setq ret (catch 'cycle
+                  (read-extended-command-1 prompt initial-input)))
+      (when (and (consp ret) (eq 'cycle (car ret)))
+        ;; Cycle to the next setting.  There's only two, so it's easy to do.
+        (if read-extended-command-predicate
+            (setq prompt "M-x "
+                  read-extended-command-predicate nil)
+          (let ((keymaps
+                  ;; The major mode's keymap and any active minor modes.
+                  (cons
+                   (current-local-map)
+                   (mapcar
+                    #'cdr
+                    (seq-filter
+                     (lambda (elem)
+                       (symbol-value (car elem)))
+                     minor-mode-map-alist)))))
+            (setq prompt "M-X ")
+            (setq read-extended-command-predicate
+                  (lambda (symbol buffer)
+                    (or (command-completion-using-modes-p symbol buffer)
+                        (where-is-internal symbol keymaps))))))
+        (setq initial-input (cdr ret))
+        (setq ret nil)))
+    ret))
+
+(defun read-extended-command-1 (prompt initial-input)
   "Read command name to invoke in `execute-extended-command'.
 This function uses the `read-extended-command-predicate' user option."
   (let ((buffer (current-buffer)))
@@ -1976,8 +2015,8 @@ read-extended-command
 		              (cons def (delete def all))
 		            all)))))
       ;; Read a string, completing from and restricting to the set of
-      ;; all defined commands.  Don't provide any initial input.
-      ;; Save the command read on the extended-command history list.
+      ;; all defined commands.  Save the command read on the
+      ;; extended-command history list.
       (completing-read
        (concat (cond
 	        ((eq current-prefix-arg '-) "- ")
@@ -1994,9 +2033,7 @@ read-extended-command
 	       ;; but actually a prompt other than "M-x" would be confusing,
 	       ;; because "M-x" is a well-known prompt to read a command
 	       ;; and it serves as a shorthand for "Extended command: ".
-               (if (memq 'shift (event-modifiers last-command-event))
-	           "M-X "
-	         "M-x "))
+               (or prompt "M-x "))
        (lambda (string pred action)
          (if (and suggest-key-bindings (eq action 'metadata))
 	     '(metadata
@@ -2013,7 +2050,7 @@ read-extended-command
                          (funcall read-extended-command-predicate sym buffer)
                        (error (message "read-extended-command-predicate: %s: %s"
                                        sym (error-message-string err))))))))
-       t nil 'extended-command-history))))
+       t initial-input 'extended-command-history))))
 
 (defun command-completion-using-modes-p (symbol buffer)
   "Say whether SYMBOL has been marked as a mode-specific command in BUFFER."
@@ -2241,7 +2278,7 @@ execute-extended-command-for-buffer
              (or (command-completion-using-modes-p symbol buffer)
                  (where-is-internal symbol keymaps)))))
      (list current-prefix-arg
-           (read-extended-command)
+           (read-extended-command "M-X ")
            execute-extended-command--last-typed)))
   (with-suppressed-warnings ((interactive-only execute-extended-command))
     (execute-extended-command prefixarg command-name typed)))

  reply	other threads:[~2021-04-10 17:56 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-17 17:56 bug#47215: 28.0.50; Let M-x switch between M-x and M-X Felician Nemeth
2021-03-18  5:08 ` Lars Ingebrigtsen
2021-04-04 17:51   ` Felician Nemeth
2021-04-04 19:52     ` Lars Ingebrigtsen
2021-04-10 17:56       ` Felician Nemeth [this message]
2021-04-11 17:36         ` Lars Ingebrigtsen
2021-04-11 18:29           ` bug#47215: [External] : " Drew Adams
2022-06-24 18:18         ` Lars Ingebrigtsen
2022-06-24 18:55           ` Juri Linkov
2022-06-24 19:00             ` Lars Ingebrigtsen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87r1ji3twe.fsf@betli.tmit.bme.hu \
    --to=felician.nemeth@gmail.com \
    --cc=47215@debbugs.gnu.org \
    --cc=larsi@gnus.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).