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))
next prev 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
* 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 external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.