unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Juri Linkov <juri@linkov.net>
To: Dmitry Gutov <dmitry@gutov.dev>
Cc: Spencer Baugh <sbaugh@janestreet.com>,
	63648@debbugs.gnu.org, sbaugh@catern.com
Subject: bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands
Date: Wed, 30 Aug 2023 19:27:27 +0300	[thread overview]
Message-ID: <86y1hs4kkg.fsf@mail.linkov.net> (raw)
In-Reply-To: <ef5bd8eb-40f9-663d-9a13-f59f9745652e@gutov.dev> (Dmitry Gutov's message of "Tue, 29 Aug 2023 23:40:19 +0300")

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

>> There is no code where to bind a dynamic variable, because its value
>> should be available for the next command in the command loop.
>> If you agree there is no other way to implement this than next-default-directory,
>> then I could bring up the discussion on emacs-devel.
>
> Before we dive into all that, why not try advice on 'command-execute'? For
> the PoC code at least. It's in Lisp since 2013.

Thanks for bringing up 'command-execute'.  I forgot it was moved from C to Lisp,
so the change is simpler and not needed to discuss on emacs-devel.  Then advice
on 'command-execute' will be required to support older Emacs versions in project.el.
But for Emacs 30 I modified my previous patch, and the next version is below:

> The comment in its body does say "Called directly from the C code", but I'm
> not sure if that has any direct implications for us.

Also interesting how 'command-execute' handles 'debug-on-next-call'
similar to 'next-default-directory'.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: next-default-directory.patch --]
[-- Type: text/x-diff, Size: 11333 bytes --]

diff --git a/lisp/simple.el b/lisp/simple.el
index 05a3c4b93d6..ff665111a5d 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -2752,6 +2752,9 @@ oclosure-interactive-form
   (let ((if (cconv--interactive-helper--if f)))
     `(interactive ,(if (functionp if) `(funcall ',if) if))))
 
+(defvar next-default-directory nil
+  "Default directory for the next command.")
+
 (defun command-execute (cmd &optional record-flag keys special)
   ;; BEWARE: Called directly from the C code.
   "Execute CMD as an editor command.
@@ -2803,7 +2806,11 @@ command-execute
           (execute-kbd-macro final prefixarg))
          (t
           ;; Pass `cmd' rather than `final', for the backtrace's sake.
-          (prog1 (call-interactively cmd record-flag keys)
+          (prog1 (if next-default-directory
+                     (let ((default-directory next-default-directory))
+                       (prog1 (call-interactively cmd record-flag keys)
+                         (setq next-default-directory nil)))
+                   (call-interactively cmd record-flag keys))
             (when-let ((info
                         (and (symbolp cmd)
                              (not (get cmd 'command-execute-obsolete-warned))
diff --git a/lisp/window.el b/lisp/window.el
index b9b032c33e9..006531ab017 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -9122,7 +9114,8 @@ display-buffer-override-next-command
 		     (> (minibuffer-depth) minibuffer-depth)
 		     ;; But don't remove immediately after
 		     ;; adding the hook by the same command below.
-		     (eq this-command command))
+		     (eq this-command command)
+		     (eq this-command 'project-switch-project))
               (funcall exitfun))))
     ;; Call post-function after the next command finishes (bug#49057).
     (add-hook 'post-command-hook postfun)
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 7aaf7a9f9fb..f87bb750e23 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -193,9 +193,10 @@ project-find-functions
   'project-current-directory-override
   "29.1")
 
-(defvar project-current-directory-override nil
-  "Value to use instead of `default-directory' when detecting the project.
-When it is non-nil, `project-current' will always skip prompting too.")
+(define-obsolete-variable-alias
+  'project-current-directory-override
+  'next-default-directory
+  "30.1")
 
 (defcustom project-prompter #'project-prompt-project-dir
   "Function to call to prompt for a project.
@@ -227,12 +228,11 @@ project-current
 
 See the doc string of `project-find-functions' for the general form
 of the project instance object."
-  (unless directory (setq directory (or project-current-directory-override
-                                        default-directory)))
+  (unless directory (setq directory default-directory))
   (let ((pr (project--find-in-directory directory)))
     (cond
      (pr)
-     ((unless project-current-directory-override
+     ((unless next-default-directory
         maybe-prompt)
       (setq directory (funcall project-prompter)
             pr (project--find-in-directory directory))))
@@ -846,8 +846,8 @@ project-prefix-map
 
 ;;;###autoload (define-key ctl-x-map "p" project-prefix-map)
 
-;; We can't have these place-specific maps inherit from
-;; project-prefix-map because project--other-place-command needs to
+;; Maybe we can have these place-specific maps inherit from
+;; project-prefix-map because set-transient-map maybe needs to
 ;; know which map the key binding came from, as if it came from one of
 ;; these maps, we don't want to set display-buffer-overriding-action
 
@@ -863,16 +863,6 @@ project-other-frame-map
     map)
   "Keymap for project commands that display buffers in other frames.")
 
-(defun project--other-place-command (action &optional map)
-  (let* ((key (read-key-sequence-vector nil t))
-         (place-cmd (lookup-key map key))
-         (generic-cmd (lookup-key project-prefix-map key))
-         (switch-to-buffer-obey-display-actions t)
-         (display-buffer-overriding-action (unless place-cmd action)))
-    (if-let ((cmd (or place-cmd generic-cmd)))
-        (call-interactively cmd)
-      (user-error "%s is undefined" (key-description key)))))
-
 ;;;###autoload
 (defun project-other-window-command ()
   "Run project command, displaying resultant buffer in another window.
@@ -882,9 +872,10 @@ project-other-window-command
 \\{project-prefix-map}
 \\{project-other-window-map}"
   (interactive)
-  (project--other-place-command '((display-buffer-pop-up-window)
-                                  (inhibit-same-window . t))
-                                project-other-window-map))
+  (let ((inhibit-message t)) (other-window-prefix))
+  (message "Display next project command buffer in a new window...")
+  (set-transient-map (make-composed-keymap project-prefix-map
+                                           project-other-window-map)))
 
 ;;;###autoload (define-key ctl-x-4-map "p" #'project-other-window-command)
 
@@ -897,8 +888,10 @@ project-other-frame-command
 \\{project-prefix-map}
 \\{project-other-frame-map}"
   (interactive)
-  (project--other-place-command '((display-buffer-pop-up-frame))
-                                project-other-frame-map))
+  (let ((inhibit-message t)) (other-frame-prefix))
+  (message "Display next project command buffer in a new frame...")
+  (set-transient-map (make-composed-keymap project-prefix-map
+                                           project-other-frame-map)))
 
 ;;;###autoload (define-key ctl-x-5-map "p" #'project-other-frame-command)
 
@@ -910,7 +903,9 @@ project-other-tab-command
 
 \\{project-prefix-map}"
   (interactive)
-  (project--other-place-command '((display-buffer-in-new-tab))))
+  (let ((inhibit-message t)) (other-tab-prefix))
+  (message "Display next project command buffer in a new tab...")
+  (set-transient-map project-prefix-map))
 
 ;;;###autoload
 (when (bound-and-true-p tab-prefix-map)
@@ -993,13 +988,13 @@ project--find-default-from
   "Ensure FILENAME is in PROJECT.
 
 Usually, just return FILENAME.  But if
-`project-current-directory-override' is set, adjust it to be
+`next-default-directory' is set, adjust it to be
 relative to PROJECT instead.
 
 This supports using a relative file name from the current buffer
 when switching projects with `project-switch-project' and then
 using a command like `project-find-file'."
-  (if-let (filename-proj (and project-current-directory-override
+  (if-let (filename-proj (and next-default-directory
                             (project-current nil default-directory)))
       ;; file-name-concat requires Emacs 28+
       (concat (file-name-as-directory (project-root project))
@@ -1893,16 +1888,17 @@ project-switch-commands
                     (character :tag "Explicit key"))))
           (symbol :tag "Single command")))
 
-(defcustom project-switch-use-entire-map nil
-  "Whether `project-switch-project' will use the entire `project-prefix-map'.
-If nil, `project-switch-project' will only recognize commands
-listed in `project-switch-commands', and will signal an error
-when other commands are invoked.  If this is non-nil, all the
-keys in `project-prefix-map' are valid even if they aren't
-listed in the dispatch menu produced from `project-switch-commands'."
-  :type 'boolean
-  :group 'project
-  :version "28.1")
+;; OBSOLETE?
+;; (defcustom project-switch-use-entire-map nil
+;;   "Whether `project-switch-project' will use the entire `project-prefix-map'.
+;; If nil, `project-switch-project' will only recognize commands
+;; listed in `project-switch-commands', and will signal an error
+;; when other commands are invoked.  If this is non-nil, all the
+;; keys in `project-prefix-map' are valid even if they aren't
+;; listed in the dispatch menu produced from `project-switch-commands'."
+;;   :type 'boolean
+;;   :group 'project
+;;   :version "28.1")
 
 (defcustom project-key-prompt-style (if (facep 'help-key-binding)
                                         t
@@ -1938,39 +1934,6 @@ project--keymap-prompt
    project-switch-commands
    "  "))
 
-(defun project--switch-project-command ()
-  (let* ((commands-menu
-          (mapcar
-           (lambda (row)
-             (if (characterp (car row))
-                 ;; Deprecated format.
-                 ;; XXX: Add a warning about it?
-                 (reverse row)
-               row))
-           project-switch-commands))
-         (commands-map
-          (let ((temp-map (make-sparse-keymap)))
-            (set-keymap-parent temp-map project-prefix-map)
-            (dolist (row commands-menu temp-map)
-              (when-let ((cmd (nth 0 row))
-                         (keychar (nth 2 row)))
-                (define-key temp-map (vector keychar) cmd)))))
-         command)
-    (while (not command)
-      (let* ((overriding-local-map commands-map)
-             (choice (read-key-sequence (project--keymap-prompt))))
-        (when (setq command (lookup-key commands-map choice))
-          (unless (or project-switch-use-entire-map
-                      (assq command commands-menu))
-            ;; TODO: Add some hint to the prompt, like "key not
-            ;; recognized" or something.
-            (setq command nil)))
-        (let ((global-command (lookup-key (current-global-map) choice)))
-          (when (memq global-command
-                      '(keyboard-quit keyboard-escape-quit))
-            (call-interactively global-command)))))
-    command))
-
 ;;;###autoload
 (defun project-switch-project (dir)
   "\"Switch\" to another project by running an Emacs command.
@@ -1980,11 +1943,18 @@ project-switch-project
 When called in a program, it will use the project corresponding
 to directory DIR."
   (interactive (list (funcall project-prompter)))
-  (let ((command (if (symbolp project-switch-commands)
-                     project-switch-commands
-                   (project--switch-project-command))))
-    (let ((project-current-directory-override dir))
-      (call-interactively command))))
+  (if (symbolp project-switch-commands)
+      (let ((default-directory dir))
+        (call-interactively project-switch-commands))
+    (let* ((echofun (lambda () "[switch-project]"))
+           (postfun (lambda () (remove-hook
+                                'prefix-command-echo-keystrokes-functions
+                                echofun))))
+      (setq next-default-directory dir)
+      (message (project--keymap-prompt))
+      (add-hook 'prefix-command-echo-keystrokes-functions echofun)
+      (prefix-command-preserve-state)
+      (set-transient-map project-prefix-map nil postfun))))
 
 ;;;###autoload
 (defun project-uniquify-dirname-transform (dirname)
diff --git a/test/lisp/progmodes/project-tests.el b/test/lisp/progmodes/project-tests.el
index 5a206b67db1..bc8c0553f40 100644
--- a/test/lisp/progmodes/project-tests.el
+++ b/test/lisp/progmodes/project-tests.el
@@ -41,7 +41,7 @@ project/quoted-directory
   (skip-unless (executable-find "grep"))
   (ert-with-temp-directory directory
     (let ((default-directory directory)
-          (project-current-directory-override t)
+          (next-default-directory directory)
           (project-find-functions nil)
           (project-list-file
            (expand-file-name "projects" directory))

  parent reply	other threads:[~2023-08-30 16:27 UTC|newest]

Thread overview: 109+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-22 16:27 bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands Spencer Baugh
2023-05-22 17:51 ` Juri Linkov
2023-05-24  1:14   ` Dmitry Gutov
2023-05-24  6:20     ` Juri Linkov
2023-05-24 15:46       ` Dmitry Gutov
2023-05-24 16:20         ` Juri Linkov
2023-05-24 17:37           ` Juri Linkov
2023-05-24 17:44             ` Juri Linkov
2023-06-01 16:05               ` Juri Linkov
2023-06-02  1:40                 ` Dmitry Gutov
2023-06-02  6:40                   ` Juri Linkov
2023-06-03  1:30                     ` Dmitry Gutov
2023-08-10 11:56                     ` sbaugh
2023-08-23 13:53                       ` Spencer Baugh
2023-08-23 17:54                         ` Juri Linkov
2023-08-29 20:36                           ` Spencer Baugh
2023-08-29 20:40                           ` Dmitry Gutov
2023-08-29 21:47                             ` Spencer Baugh
2023-08-29 22:32                               ` Dmitry Gutov
2023-08-30 16:27                             ` Juri Linkov [this message]
2023-08-31  2:01                               ` Dmitry Gutov
2023-08-31  6:47                                 ` Juri Linkov
2023-08-31 11:13                                   ` Dmitry Gutov
2023-08-31 16:36                                     ` Juri Linkov
2023-09-01  1:11                                       ` Dmitry Gutov
2023-09-01  6:46                                         ` Juri Linkov
2023-09-01  9:53                                           ` Dmitry Gutov
2023-09-01 15:59                                             ` Spencer Baugh
2023-09-02  1:47                                               ` Dmitry Gutov
2023-09-03 17:11                                               ` Juri Linkov
2023-09-11 20:16                                                 ` Spencer Baugh
2023-09-12  6:55                                                   ` Juri Linkov
2023-09-10 15:30                                             ` Juri Linkov
2023-09-12 23:47                                               ` Dmitry Gutov
2023-09-13  6:47                                                 ` Juri Linkov
2023-09-18  0:12                                                   ` Dmitry Gutov
2023-09-18  6:51                                                     ` Juri Linkov
2023-09-18 11:00                                                       ` Dmitry Gutov
2023-09-18 13:56                                                         ` Dmitry Gutov
2023-09-19 17:57                                                           ` Juri Linkov
2023-09-20  0:39                                                             ` Dmitry Gutov
2023-09-20 17:10                                                               ` Juri Linkov
2023-09-21  1:16                                                                 ` Dmitry Gutov
2023-09-21  6:58                                                                   ` Juri Linkov
2023-09-22 15:52                                                                     ` Juri Linkov
2023-10-19  0:42                                                                       ` Dmitry Gutov
2023-10-19  4:46                                                                         ` Eli Zaretskii
2023-10-19  6:43                                                                           ` Juri Linkov
2023-10-19  7:51                                                                             ` Eli Zaretskii
2023-10-19  9:46                                                                           ` Dmitry Gutov
2023-10-19 11:05                                                                             ` Eli Zaretskii
2023-10-19 11:34                                                                               ` Dmitry Gutov
2023-10-19 12:22                                                                         ` sbaugh
2023-10-19 12:49                                                                           ` Dmitry Gutov
2023-10-19 14:00                                                                             ` Spencer Baugh
2023-10-19 17:17                                                                               ` Dmitry Gutov
2023-10-19 19:30                                                                                 ` Spencer Baugh
2023-10-19 23:25                                                                                   ` Dmitry Gutov
2023-10-21 16:09                                                                                     ` Spencer Baugh
2023-10-21 18:43                                                                                       ` Dmitry Gutov
2023-10-19 18:03                                                                               ` Juri Linkov
2023-10-19 19:38                                                                                 ` Spencer Baugh
2023-10-19 17:56                                                                         ` Juri Linkov
2023-10-19 22:39                                                                           ` Dmitry Gutov
2023-10-20  6:44                                                                             ` Juri Linkov
2023-10-20 19:25                                                                               ` Dmitry Gutov
2023-10-23  6:58                                                                                 ` Juri Linkov
2023-10-23 17:24                                                                                   ` Dmitry Gutov
2023-10-23 17:34                                                                                     ` Juri Linkov
2023-10-23 17:36                                                                                       ` Dmitry Gutov
2023-10-23 18:42                                                                                         ` Juri Linkov
2023-10-23 18:49                                                                                           ` Dmitry Gutov
2023-10-25 16:53                                                                                     ` Juri Linkov
2023-10-25 22:26                                                                                       ` Dmitry Gutov
2023-10-27  6:50                                                                                         ` Juri Linkov
2023-10-27  9:38                                                                                           ` Dmitry Gutov
2023-10-28 16:56                                                                                             ` Juri Linkov
2023-11-01 21:12                                                                                               ` Dmitry Gutov
2023-11-02 17:20                                                                                                 ` Juri Linkov
2023-11-02 21:33                                                                                                   ` Dmitry Gutov
2023-11-04 17:28                                                                                                     ` Juri Linkov
2023-11-05  0:55                                                                                                       ` Dmitry Gutov
2023-11-06  7:16                                                                                                         ` Juri Linkov
2023-11-06 22:49                                                                                                           ` Dmitry Gutov
2023-10-21 13:27                                                                         ` sbaugh
2023-10-21 18:41                                                                           ` Dmitry Gutov
2023-10-21 13:14                                                                       ` sbaugh
2023-08-28 22:44                         ` Dmitry Gutov
2023-08-29 20:34                           ` Spencer Baugh
2023-06-02 12:46                   ` Eli Zaretskii
2023-06-02 16:09                     ` Juri Linkov
2023-06-02  6:32                 ` Eli Zaretskii
2023-06-02  6:55                   ` Juri Linkov
2023-06-02 11:39                     ` Eli Zaretskii
2023-06-02 16:11                       ` Juri Linkov
2023-06-05  6:53                       ` Juri Linkov
2023-06-02 17:07                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-06-05  6:50                   ` Juri Linkov
2023-06-05 14:44                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-06-05 16:31                       ` Juri Linkov
2023-05-24 14:55   ` Spencer Baugh
2023-05-24 16:24     ` Juri Linkov
2023-05-26 15:16       ` Spencer Baugh
2023-05-30 17:48         ` Juri Linkov
2023-06-01 20:31           ` Spencer Baugh
2023-06-01 21:09             ` Drew Adams
2023-06-02  6:33               ` Eli Zaretskii
2023-06-02  6:46             ` Juri Linkov
2023-08-10 11:52               ` sbaugh

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=86y1hs4kkg.fsf@mail.linkov.net \
    --to=juri@linkov.net \
    --cc=63648@debbugs.gnu.org \
    --cc=dmitry@gutov.dev \
    --cc=sbaugh@catern.com \
    --cc=sbaugh@janestreet.com \
    /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).