Problem of Calling Windows cmd.exe in Emacs Lisp

By Xah Lee. Date: .

problem of calling Microsoft Windows shell in emacs lisp

Faaking nasty problem. Here's the deal. You want a emacs command that opens current file in vscode. This is easy, the elisp is just:

(shell-command (format "Code.exe %s" (shell-quote-argument $path)))

However, if you have installed gnu findutils, it install a program also named Code.exe, and it is installed in choco path C:\ProgramData\chocolatey\bin\code.exe and choco path comes in front of the vscode path in Microsoft Windows PATH environment variable. Switching path order in environment variable is not what you want to do, because you don't want random user app's bin override choco's bin.

So, simple solution one'd thought is call vscode with full path. C:\Users\xah\AppData\Local\Programs\Microsoft VS Code\Code.exe But you need to change the user name part. So, basically you want window's HOMEPATH. So in emacs lisp you call (getenv "HOMEPATH"), which returns "\\Users\\xah" then concat it with emacs lisp string "\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe".

But when you call shell, the space in the path stops it. So you need to quote the whole thing, but that becomes a inert string. Shell thinks you are trying to call a string. Ok. So, perhaps we just escape the space char... ... Anyway, it's quite fucked. Then you try & in front or Invoke-Expression "something", but you got error because emacs is actually calling cmd.exe not powershell so it doesn't know wtf is invoke-expression.

Then you spend one hundred hours to dig to see what Microsoft Windows shell is emacs lisp's shell-command is actually calling and spend two hundred hours to see if Window's cmd.exe can or cannot run commands from powershell or vice versa.

the solution is probably something like this but am tired:

(shell-command
       (format
        "pwsh -Command Invoke-Expression \"%s\\%s\" %s"
        (getenv "HOMEPATH")
        "AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe"
        (shell-quote-argument $path)))

cmd.exe can call pwsh or powershell to start PowerShell. But otherwise it doesn't know PowerShell's commands. So, you can probably do pwsh -Command Invoke-Expression "something" to solve the problem. However, the nested quoting in expression will become impossible to escape. You need to quote in elisp and quote in cmd.exe then that quotes for PowerShell. PowerShell supports block expression {...} to avoid the nested quoting but since cmd.exe is running it, so that won't work...