Package: emacs;
Reported by: Siyuan Chen <chansey97 <at> gmail.com>
Date: Tue, 1 Apr 2025 13:43:06 UTC
Severity: normal
Done: Eli Zaretskii <eliz <at> gnu.org>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Siyuan Chen <chansey97 <at> gmail.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 77430 <at> debbugs.gnu.org Subject: bug#77430: compilation-start should remember shell-file-name Date: Fri, 4 Apr 2025 16:15:06 +0800
[Message part 1 (text/plain, inline)]
> Sorry, I don't understand: are you saying that you cannot arrange for the buffer-local value of shell-file-name to point to Bash and stay that way for the subsequent commands? If you need to use with-current-buffer or something similar, it should be easy no? The original problem is not about `compile' but `recompile', i.e. press 'g' in the *compilation* buffer. The *compilation* buffer doesn't know anything about the last shell-file-name, so it uses cmdproxy by default. Anyway, this is no longer a problem now, see below. > I think this is the cleanest solution for problems like this on Windows, since you don't really want to override shell-file-name, you just want to invoke the commands via Bash. Your method really inspired me. Thank you so much! Based on it, I've redesigned my compilation workflow. Basically, whenever users invoke `sc-haskell-projectile-stack-compile' (a tailored compile command integrated with projectile), it firstly generates two files in the Haskell project folder: .emacs_stack_launch.bat ``` set MSYSTEM=MINGW32 "c:/Users/Chansey/AppData/Local/Programs/stack/x86_64-windows/msys2-20230526/usr/bin/bash" --login "e:/my-haskell-project/.emacs_stack_launch_script.sh" %* ``` .emacs_stack_launch_script.sh ``` export STACK_ROOT=/c/sr export PATH=/c/env/haskell/stack/v2.15.1:/c/Users/Chansey/AppData/Roaming/local/bin:/c/PROGRA~1/Git/cmd:$PATH $* ``` then it calls (compile ".emacs_stack_launch.bat stack build"). This method is working great so far. Plus, the file generation brings several benefits: 1. We can set local variables in .dir-locals (e.g. msys2-path, environment-variables) per project for fine-grained control over compilation. 2. No need to tailored `recompile'. It just uses the last generated files. So it works pretty well when users press 'g' in the *compilation* buffer. 3. Support all the compile commands and opts, like stack build, stack run, stack build --test, etc. 4. Easy debugging with .emacs_stack_launch.bat and .emacs_stack_launch_script.sh. The code is something like this: ``` (defun sc-haskell-projectile-stack--run-project-cmd (command) (let* ((default-directory (projectile-compilation-dir)) (command (projectile-read-command "Compile command: " (or projectile-project-compilation-cmd command)))) (sc-haskell-projectile-stack--gen-launch-file) (sc-haskell-projectile-stack--gen-launch-script-file) (compile (format "%s %s" ".emacs_stack_launch.bat" command) projectile-compile-use-comint-mode))) (defun sc-haskell-projectile-stack-compile () (sc-haskell-projectile-stack--run-project-cmd "stack build")) (defun sc-haskell-projectile-stack-test () (sc-haskell-projectile-stack--run-project-cmd "stack build --test")) (defun sc-haskell-projectile-stack-run () (sc-haskell-projectile-stack--run-project-cmd "stack run")) ``` Additionally, I also created a projectile-based shell command, which has to be different from projectile-based compile command. ``` (defun sc-haskell-projectile-stack-shell () (interactive) (let ((current-prefix-arg 4) (explicit-shell-file-name (expand-file-name "usr/bin/bash" sc-haskell-projectile-stack-msys2-path)) (explicit-bash-args '("--login" "--noediting" "-i"))) (sc-haskell-projectile-stack--gen-msys2-bashrc-init-file) (with-environment-variables (("MSYSTEM" "MINGW32")) (call-interactively 'projectile-run-shell)))) ``` Unlike the previous method, this one still rebinds explicit-shell-file-name, otherwise we have to call "bash --login --noediting -i" in the .emacs_stack_launch_script.sh, which would invoke bash twice — something I'd rather avoid (it still can work though). My solution is to add a hook in .bashrc ``` if [ -f $HOME/.bashrc_init.sh ]; then . $HOME/.bashrc_init.sh rm $HOME/.bashrc_init.sh fi ``` Basically, whenever users invoke `sc-haskell-projectile-stack-shell, it generates .bashrc_init.sh in the msys2 home USER folder. The commands in .bashrc_init.sh are similar to those in emacs_stack_launch_script and can, of course, be configured via .dir-locals.el. It might seem a bit unusual, but it works well so far. Just like to share my current design here — any suggestions would be greatly appreciated. Thank you! On Tue, Apr 1, 2025 at 11:57 PM Eli Zaretskii <eliz <at> gnu.org> wrote: > > Cc: 77430 <at> debbugs.gnu.org > > Date: Tue, 01 Apr 2025 18:50:36 +0300 > > From: Eli Zaretskii <eliz <at> gnu.org> > > > > > From: Siyuan Chen <chansey97 <at> gmail.com> > > > Date: Tue, 1 Apr 2025 23:13:46 +0800 > > > Cc: 77430 <at> debbugs.gnu.org > > > > > > > Why cannot your my/compile function do this: > > > > > > > > (setq-local shell-file-name "C:/msys64/usr/bin/bash") > > > > > > > > instead of let-binding it? > > > > > > This is only for the current file buffer. > > > > > > For example, if you focus on a project file buffer (e.g. test.hs) and > M-x my/compile, it only sets > > > `shell-file-name' for that file buffer. However, the `compile` > actually using the `shell-file-name' belongs to the > > > *compilation* buffer. > > > > > > ``` > > > (defun compilation-start (command &optional mode name-function > highlight-regexp > > > continue) > > > ... > > > (with-current-buffer outbuf ; <--- The `outbuf' is the *compilation* > buffer > > > ... > > > (comint-exec > > > outbuf (compilation--downcase-mode-name mode-name) > > > shell-file-name ; <--- use the buffer local variable > shell-file-name in the *compilation* buffer > > > nil `(,shell-command-switch ,command)) > > > ... > > > ) > > > ... > > > ) > > > ``` > > > > > > So the following code doesn't work: > > > > > > ``` > > > (defun my/compile () > > > (interactive) > > > (let ( > > > (compilation-environment > > > > "PATH=/mingw64/bin:/usr/local/bin:/usr/bin:/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl") > > > > > > ) > > > (setq-local shell-file-name "C:/msys64/usr/bin/bash") > > > (compile "ls") > > > )) > > > ``` > > > > > > M-x my/compile > > > > > > Compilation exited abnormally. > > > > Sorry, I don't understand: are you saying that you cannot arrange for > > the buffer-local value of shell-file-name to point to Bash and stay > > that way for the subsequent commands? If you need to use > > with-current-buffer or something similar, it should be easy no? > > Alternatively, how about making a Windows batch file, which would > invoke the compilation command via Bash. So you compile command would > look like this: > > M-x compile RET mycomp ls RET > > where mycomp.bat is a batch file which does > > @echo off > C:\msys64\usr\bin\bash --login -c %* > > I think this is the cleanest solution for problems like this on > Windows, since you don't really want to override shell-file-name, you > just want to invoke the commands via Bash. >
[Message part 2 (text/html, inline)]
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.