[-- Attachment #1: Type: text/plain, Size: 1533 bytes --] Hello, Unlike project-shell-command, project-compile first prompts for a command, then binds default-directory and calls compile. Binding default-directory first makes completion work from the project root, which is useful for completing on filenames relative to the root, on targets from the toplevel Makefile, etc. I see three ways to achieve this: (1) Rewrite project-compile with call-interactively, the way project-shell-command is written (see patch #1). (2) Set COMMAND to nil in the interactive spec, then prompt for it after binding default-directory (see patch #2). (3) Let-binding default-directory once in the interactive spec, and again before calling compile. I'm assuming (1) is out of the question, given 2020-06-02 "* lisp/progmodes/project.el (project-vc-dir, project-shell): New commands." (2c1e5b9e77). I'm CC'ing Juri to get his opinion though; project-compile is new in Emacs 28.1, so its argument list is not yet set in stone. I've taken a stab at (2), but my patch changes the semantics of COMMAND for an edge case: for now calling (project-compile nil) from Lisp causes (compile nil) to be called (which errors out); with my patch, (project-compile nil) yields a prompt. This can be solved using called-interactively-p (or using an optional INTERACTIVE argument); I just don't know if it's worth the hassle? I haven't given much thought to (3), so I haven't yet figured out how to avoid prompting twice for the project (on the rare occasions where prompting is needed). Thanks for your time. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Change-default-directory-before-prompting-in-project-1.patch --] [-- Type: text/x-patch, Size: 1666 bytes --] From 801311cef5a825af93a41cc044b4f753b648a866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= <kevin.legouguec@gmail.com> Date: Sun, 10 Jan 2021 10:43:41 +0100 Subject: [PATCH] Change default-directory before prompting in project-compile This causes command completion to work from the project root, letting users complete top-level folders, make targets, etc. * lisp/progmodes/project.el (project-compile): Simplify using call-interactively, as done with project(-aysnc)-shell-command. --- lisp/progmodes/project.el | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 62c3cf44cb..06966f33b7 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -970,20 +970,11 @@ compilation-read-command (declare-function compilation-read-command "compile") ;;;###autoload -(defun project-compile (command &optional comint) - "Run `compile' in the project root. -Arguments the same as in `compile'." - (interactive - (list - (let ((command (eval compile-command))) - (require 'compile) - (if (or compilation-read-command current-prefix-arg) - (compilation-read-command command) - command)) - (consp current-prefix-arg))) - (let* ((pr (project-current t)) - (default-directory (project-root pr))) - (compile command comint))) +(defun project-compile () + "Run `compile' in the project root." + (interactive) + (let ((default-directory (project-root (project-current t)))) + (call-interactively #'compile))) (defun project--read-project-buffer () (let* ((pr (project-current t)) -- 2.29.2 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0001-Change-default-directory-before-prompting-in-project-2.patch --] [-- Type: text/x-patch, Size: 1842 bytes --] From b1b10d01a83b2b07a27ce6bcf12cf000fabaf22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= <kevin.legouguec@gmail.com> Date: Sun, 10 Jan 2021 13:18:07 +0100 Subject: [PATCH] Change default-directory before prompting in project-compile This causes command completion to work from the project root, letting users complete top-level folders, make targets, etc. * lisp/progmodes/project.el (project-compile): Read command after binding default-directory to project root. --- lisp/progmodes/project.el | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 62c3cf44cb..1e7f6d7c06 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -974,15 +974,17 @@ project-compile "Run `compile' in the project root. Arguments the same as in `compile'." (interactive - (list - (let ((command (eval compile-command))) - (require 'compile) - (if (or compilation-read-command current-prefix-arg) - (compilation-read-command command) - command)) - (consp current-prefix-arg))) - (let* ((pr (project-current t)) - (default-directory (project-root pr))) + (list nil + (consp current-prefix-arg))) + ;; Bind `default-directory' before prompting for COMMAND, so that + ;; command completion works from the project root. + (let ((default-directory (project-root (project-current t))) + (command (or command + (let ((command (eval compile-command))) + (require 'compile) + (if (or compilation-read-command current-prefix-arg) + (compilation-read-command command) + command))))) (compile command comint))) (defun project--read-project-buffer () -- 2.29.2 [-- Attachment #4: Type: text/plain, Size: 845 bytes --] In GNU Emacs 28.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.24.24, cairo version 1.16.0) of 2021-01-04 built on my-little-tumbleweed Repository revision: 2c847902522ae74c9b25b2a3fa60565e0187fd0a Repository branch: master Windowing system distributor 'The X.Org Foundation', version 11.0.12010000 System Description: openSUSE Tumbleweed Configured using: 'configure --with-xwidgets --with-cairo' Configured features: XPM JPEG TIFF GIF PNG RSVG CAIRO SOUND GPM DBUS GSETTINGS GLIB NOTIFY INOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE HARFBUZZ M17N_FLT LIBOTF ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 XDBE XIM MODULES THREADS XWIDGETS JSON PDUMPER LCMS2 Important settings: value of $LC_CTYPE: en_US.UTF-8 value of $LC_TIME: en_GB.UTF-8 value of $LANG: en_US.UTF-8 value of $XMODIFIERS: @im=local locale-coding-system: utf-8-unix
Hi Kevin, On 10.01.2021 14:57, Kévin Le Gouguec wrote: > Unlike project-shell-command, project-compile first prompts for a > command, then binds default-directory and calls compile. Binding > default-directory first makes completion work from the project root, > which is useful for completing on filenames relative to the root, on > targets from the toplevel Makefile, etc. Thanks for the report. > I see three ways to achieve this: > > (1) Rewrite project-compile with call-interactively, the way > project-shell-command is written (see patch #1). > > (2) Set COMMAND to nil in the interactive spec, then prompt for it after > binding default-directory (see patch #2). > > (3) Let-binding default-directory once in the interactive spec, and > again before calling compile. > I'm assuming (1) is out of the question, given 2020-06-02 > "* lisp/progmodes/project.el (project-vc-dir, project-shell): New > commands." (2c1e5b9e77). I'm CC'ing Juri to get his opinion though; > project-compile is new in Emacs 28.1, so its argument list is not yet > set in stone. I see no strong reason to avoid (1), this new command has never seen an Emacs release, so we're not bound by compatibility promise yet. Further, any code that would be calling project-compile in a program should inline its definition instead, in most of the cases. Let's see what people think, of course.
> Unlike project-shell-command, project-compile first prompts for a > command, then binds default-directory and calls compile. Binding > default-directory first makes completion work from the project root, > which is useful for completing on filenames relative to the root, on > targets from the toplevel Makefile, etc. > > I see three ways to achieve this: > > (1) Rewrite project-compile with call-interactively, the way > project-shell-command is written (see patch #1). (1) has the obvious advantage of avoiding duplication of the interactive spec of 'compile' in 'project-compile', in addition to your use case of binding default-directory. > I'm assuming (1) is out of the question, given 2020-06-02 > "* lisp/progmodes/project.el (project-vc-dir, project-shell): New > commands." (2c1e5b9e77). I'm CC'ing Juri to get his opinion though; > project-compile is new in Emacs 28.1, so its argument list is not yet > set in stone. Actually, (1) is not out of the question. Quite contrary, (1) is the cleanest solution. But before rewriting with call-interactively, we need to find a way to use project-compile in the init files, i.e. to find a replacement for such configurations: (define-key my-map "m" ;; mnemonics "make" (lambda () (interactive) (project-compile ;; Use previous command from history ;; instead of the default from compile-command (compilation-read-command (car compile-history)) ;; Don't use compilation-shell-minor-mode nil)))
On 11.01.2021 20:35, Juri Linkov wrote:
> But before rewriting with call-interactively,
> we need to find a way to use project-compile in the init files, i.e.
> to find a replacement for such configurations:
>
> (define-key my-map "m" ;; mnemonics "make"
> (lambda ()
> (interactive)
> (project-compile
> ;; Use previous command from history
> ;; instead of the default from compile-command
> (compilation-read-command (car compile-history))
> ;; Don't use compilation-shell-minor-mode
> nil)))
Is it really possible to solve this without making project-compile a
macro of some sort?
For the above code sample not to exhibit the problem from this report,
it should use project-current and project-root directly.
[-- Attachment #1: Type: text/plain, Size: 391 bytes --] Dmitry Gutov <dgutov@yandex.ru> writes: > On 11.01.2021 20:35, Juri Linkov wrote: >> But before rewriting with call-interactively, >> we need to find a way to use project-compile in the init files, i.e. >> to find a replacement for such configurations: >> <snip> > > Is it really possible to solve this without making project-compile a > macro of some sort? Something like this maybe? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Change-default-directory-before-prompting-in-project.patch --] [-- Type: text/x-patch, Size: 1918 bytes --] From 7d3ffd7f33276949669414ed4908ad8fee35dd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= <kevin.legouguec@gmail.com> Date: Sun, 10 Jan 2021 10:43:41 +0100 Subject: [PATCH] Change default-directory before prompting in project-compile This causes command completion to work from the project root, letting users complete top-level folders, make targets, etc. * lisp/progmodes/project.el (project-compile): Simplify using call-interactively, as done with project(-aysnc)-shell-command. --- lisp/progmodes/project.el | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 62c3cf44cb..dade8b4f1c 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -970,20 +970,16 @@ compilation-read-command (declare-function compilation-read-command "compile") ;;;###autoload -(defun project-compile (command &optional comint) +(defun project-compile (command &optional comint interactive) "Run `compile' in the project root. -Arguments the same as in `compile'." - (interactive - (list - (let ((command (eval compile-command))) - (require 'compile) - (if (or compilation-read-command current-prefix-arg) - (compilation-read-command command) - command)) - (consp current-prefix-arg))) - (let* ((pr (project-current t)) - (default-directory (project-root pr))) - (compile command comint))) +COMMAND and COMINT work as with `compile'. When calling this +function from Lisp, you can pretend that it was called +interactively by passing a non-nil INTERACTIVE argument." + (interactive (list nil nil t)) + (let ((default-directory (project-root (project-current t)))) + (if interactive + (call-interactively #'compile) + (compile command comint)))) (defun project--read-project-buffer () (let* ((pr (project-current t)) -- 2.29.2 [-- Attachment #3: Type: text/plain, Size: 205 bytes --] (Apologies if I misunderstood what Juri asked, or if my suggestion is buggy) We can also stick a "\(fn COMMAND &optional COMINT)" in the docstring if we don't want to advertise the INTERACTIVE argument.
> Something like this maybe?
>
> +(defun project-compile (command &optional comint interactive)
> +COMMAND and COMINT work as with `compile'. When calling this
> +function from Lisp, you can pretend that it was called
> +interactively by passing a non-nil INTERACTIVE argument."
> + (interactive (list nil nil t))
> + (let ((default-directory (project-root (project-current t))))
> + (if interactive
> + (call-interactively #'compile)
> + (compile command comint))))
>
> (Apologies if I misunderstood what Juri asked, or if my suggestion is
> buggy)
Perfect, thank you for finding the middle ground for different needs.
Hi Juri,
On 12.01.2021 20:46, Juri Linkov wrote:
>> Something like this maybe?
>>
>> +(defun project-compile (command &optional comint interactive)
>> +COMMAND and COMINT work as with `compile'. When calling this
>> +function from Lisp, you can pretend that it was called
>> +interactively by passing a non-nil INTERACTIVE argument."
>> + (interactive (list nil nil t))
>> + (let ((default-directory (project-root (project-current t))))
>> + (if interactive
>> + (call-interactively #'compile)
>> + (compile command comint))))
>>
>> (Apologies if I misunderstood what Juri asked, or if my suggestion is
>> buggy)
> Perfect, thank you for finding the middle ground for different needs.
So you're not worried about compilation-read-command in your code being
called in the wrong directory (exhibiting what the current bug report
aims to fix)?
I think you might as well inline the definition, it's almost as short:
(define-key my-map "m" ;; mnemonics "make"
(lambda ()
(interactive)
(let ((default-directory (project-root (project-current t))))
(compile
;; Use previous command from history
;; instead of the default from compile-command
(compilation-read-command (car compile-history))
;; Don't use compilation-shell-minor-mode
nil))))
But if you really like the new version of project-compile, OK.
I'm not a big fan of the 'interactive' argument. It could be replaced by
using (called-interactively-p 'interactive), though I'm not sure how
idiomatic that is.
> So you're not worried about compilation-read-command in your code being
> called in the wrong directory (exhibiting what the current bug report aims
> to fix)?
>
> I think you might as well inline the definition, it's almost as short:
>
> (define-key my-map "m" ;; mnemonics "make"
> (lambda ()
> (interactive)
> (let ((default-directory (project-root (project-current t))))
> (compile
> ;; Use previous command from history
> ;; instead of the default from compile-command
> (compilation-read-command (car compile-history))
> ;; Don't use compilation-shell-minor-mode
> nil))))
Indeed, this means that let-binding default-directory to
(project-root (project-current t))) is unavoidable in the init file.
So it's easier to just replace 'project-compile' with 'compile'.
This means Kévin's first patch is the way to go.
Dmitry Gutov <dgutov@yandex.ru> writes: > I'm not a big fan of the 'interactive' argument. It could be replaced > by using (called-interactively-p 'interactive), though I'm not sure > how idiomatic that is. Not necessarily a fan either, but my takeaway from recent discussions on emacs-devel is that the argument is preferred to called-interactively-p, which should only be used when a function's arglist is set in stone. <E1k7A3J-0005gG-4K@fencepost.gnu.org> https://lists.gnu.org/archive/html/emacs-devel/2020-08/msg00463.html <jwvzh6ubtbe.fsf-monnier+emacs@gnu.org> https://lists.gnu.org/archive/html/emacs-devel/2020-08/msg00472.html I see a few dozen hits for "&optional \([\w-]+ \)*interactive)" under lisp/, so it seems to be an established practice. PS: I've just seen Juri's reponse in bug#45765#26; I'm glad there is a consensus on the first patch, because after looking at more in-tree examples of optional INTERACTIVE arguments, I found myself agonizing over spelling the spec (list nil nil t), '(nil nil t), or "i\ni\np".
On 13.01.2021 21:46, Kévin Le Gouguec wrote: > Dmitry Gutov <dgutov@yandex.ru> writes: > >> I'm not a big fan of the 'interactive' argument. It could be replaced >> by using (called-interactively-p 'interactive), though I'm not sure >> how idiomatic that is. > > Not necessarily a fan either, but my takeaway from recent discussions on > emacs-devel is that the argument is preferred to called-interactively-p, > which should only be used when a function's arglist is set in stone. > > <E1k7A3J-0005gG-4K@fencepost.gnu.org> > https://lists.gnu.org/archive/html/emacs-devel/2020-08/msg00463.html > > <jwvzh6ubtbe.fsf-monnier+emacs@gnu.org> > https://lists.gnu.org/archive/html/emacs-devel/2020-08/msg00472.html > > I see a few dozen hits for "&optional \([\w-]+ \)*interactive)" under > lisp/, so it seems to be an established practice. All right, that makes sense. It will help the next time such question comes up. > PS: I've just seen Juri's reponse in bug#45765#26; I'm glad there is a > consensus on the first patch, because after looking at more in-tree > examples of optional INTERACTIVE arguments, I found myself agonizing > over spelling the spec (list nil nil t), '(nil nil t), or "i\ni\np". I know the feeling ;-) Patch installed, closing. Thanks again.
>> PS: I've just seen Juri's reponse in bug#45765#26; I'm glad there is a
>> consensus on the first patch, because after looking at more in-tree
>> examples of optional INTERACTIVE arguments, I found myself agonizing
>> over spelling the spec (list nil nil t), '(nil nil t), or "i\ni\np".
>
> I know the feeling ;-)
>
> Patch installed, closing. Thanks again.
Thanks for installing the patch. I noticed that the similar command
project-execute-extended-command has such line:
(declare (interactive-only command-execute))
Should other interactive-only project commands like project-compile
and project(-async)-shell-command have the same?
On 19.01.2021 19:38, Juri Linkov wrote:
> Should other interactive-only project commands like project-compile
> and project(-async)-shell-command have the same?
Makes sense, added, thank you.