[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-proje
From: |
Juri Linkov |
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 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/30.0.50 (x86_64-pc-linux-gnu) |
>> 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'.
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))
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, sbaugh, 2023/08/10
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, sbaugh, 2023/08/10
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Spencer Baugh, 2023/08/23
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Juri Linkov, 2023/08/23
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Spencer Baugh, 2023/08/29
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Dmitry Gutov, 2023/08/29
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Spencer Baugh, 2023/08/29
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Dmitry Gutov, 2023/08/29
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands,
Juri Linkov <=
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Dmitry Gutov, 2023/08/30
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Juri Linkov, 2023/08/31
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Dmitry Gutov, 2023/08/31
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Juri Linkov, 2023/08/31
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Dmitry Gutov, 2023/08/31
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Dmitry Gutov, 2023/08/28
- bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands, Spencer Baugh, 2023/08/29