skywind3000 / asyncrun.vim

:rocket: Run Async Shell Commands in Vim 8.0 / NeoVim and Output to the Quickfix Window !!
https://www.vim.org/scripts/script.php?script_id=5431
MIT License
1.84k stars 109 forks source link

Support powershell with nvim #287

Open Mitch6886 opened 3 months ago

Mitch6886 commented 3 months ago

The purpose of this pull request is to allow changing the shell on windows with nvim.

I am using nvim with windows and my nvim shell is powershell,

I have not to integrated this pluggin with powershell,

However, I could integrate this with cmd by setting

let g:asyncrun_shellflag = '/C'

let g:asyncrun_shell= 'cmd.exe'

And perfoming this code change

shellescape is overwriting s:args meaning the custom shell and flags (e.g. ["cmd.exe", "/C"]) are discarded

Edit

Pull request is now to support powershell as the default shell

skywind3000 commented 3 months ago

This is a regression,

Have you ever considered why I am using args as a single string for nvim while using an array for vim?

Why did I take nvim as a special case?

You just convert the nvim code to the vim code and eliminate that special case.

btw: when args is an array, no need to escape its items.

Mitch6886 commented 3 months ago

@skywind3000 Thanks for your comments, I agree that the previous request was wrong

I have changed the pull request.

The bug that I have identified is powershell will not execute a command wrapped in quotes i.e.,

Bad "C:\myscript.cmd"

Ok C:\myscript.cmd

cmd will execute quoted commands

So I have added an option to not quote the command,

You could use a different approach instead of executing jobstart("\"C:\\myscript.cmd\"")

you could prepend with a cmd.exe command similar to what I was attempting in the first commit, but only when the user selects it jobstart("cmd /C \"C:\\myscript.cmd\"")

pedrohgmacedo commented 3 months ago

@skywind3000 Thanks for your comments, I agree that the previous request was wrong

I have changed the pull request.

The bug that I have identified is powershell will not execute a command wrapped in quotes i.e.,

Bad "C:\myscript.cmd"

Ok C:\myscript.cmd

cmd will execute quoted commands

So I have added an option to not quote the command,

You could use a different approach instead of executing jobstart("\"C:\\myscript.cmd\"")

you could prepend with a cmd.exe command similar to what I was attempting in the first commit, but only when the user selects it jobstart("cmd /C \"C:\\myscript.cmd\"")

Just reset the shell and then restore after the command. Then it will also work with program_msys. I have:

fun! shells#shell_backup(...)
  let l:curr = {}
  if a:0 == 0
    let l:curr['shell']       = &shell
    let l:curr['shellcmdflag']= &shellcmdflag
    let l:curr['shellpipe']   = &shellpipe
    let l:curr['shellquote']  = &shellquote
    let l:curr['shellredir']  = &shellredir
    let l:curr['shellslash']  = &shellslash
    let l:curr['shelltemp']   = &shelltemp
    let l:curr['shellxescape']= &shellxescape
    let l:curr['shellxquote'] = &shellxquote
    return l:curr
  elseif a:0 == 1
    let l:curr = a:1
    let &shell = l:curr['shell']
    let &shellcmdflag = l:curr['shellcmdflag']
    let &shellpipe = l:curr['shellpipe']
    let &shellquote = l:curr['shellquote']
    let &shellredir = l:curr['shellredir']
    let &shellslash = l:curr['shellslash']
    let &shelltemp = l:curr['shelltemp']
    let &shellxescape = l:curr['shellxescape']
    let &shellxquote = l:curr['shellxquote']
  endif
endfun

fun! shells#shell_reset()
  set shell&
  set shellcmdflag&
  set shellpipe&
  set shellquote&
  set shellredir&
  set shellslash&
  set shelltemp&
  set shellxescape&
  set shellxquote&
endfun
diff --git a/plugin/asyncrun.vim b/plugin/asyncrun.vim
index 8e351c7..95912ab 100644
--- a/plugin/asyncrun.vim
+++ b/plugin/asyncrun.vim
@@ -263,7 +263,10 @@ function! s:shellescape(path)
        if s:asyncrun_windows == 0
                return shellescape(a:path)
        endif
+       let s:user_shell = shells#shell_backup()
+       call shells#shell_reset()
        let hr = shellescape(a:path)
+       call shells#shell_backup(s:user_shell)
        if &ssl != 0
                let hr = s:StringReplace(hr, "'", '"')
        endif
skywind3000 commented 3 months ago

Thanks for your patch, I've been thinking about this issue in the past couple of days.

Since the command is written to asyncrun.cmd and it only accept cmd.exe's command.

So I made a new release, which force to use "cmd.exe" as "g:asyncrun_shell" on Windows.

https://github.com/skywind3000/asyncrun.vim/releases/tag/2.12.8

bjjblackbelt commented 3 months ago

Thanks for your patch, I've been thinking about this issue in the past couple of days.

Since the command is written to asyncrun.cmd and it only accept cmd.exe's command.

So I made a new release, which force to use "cmd.exe" as "g:asyncrun_shell" on Windows.

https://github.com/skywind3000/asyncrun.vim/releases/tag/2.12.8

Just tested 2.12.8 and received the following error on Windows using nvim. The same :AsyncRun dir call works with my config on 2.12.6. I have not changed the shell variable from the default.

[dir] The syntax of the command is incorrect. [Finished in 0 seconds with code 1]

I reverted the changes in 2.12.8 and tested the solution suggested by @pedrohgmacedo. This change did not work for me. However, the following solution inspired by @Mitch6886 does work:

asyncrun.vim::AsyncRun_Job_Start()

        if s:asyncrun_windows == 0
            let s:async_job = jobstart(l:args, l:callbacks)
        else
            let s:async_job = jobstart("cmd /C \"" . l:args . "\"", l:callbacks)
        endif

In addition, with these changes I am able to asynchronously run commands in PowerShell by setting asyncrun_wrapper:

let g:asyncrun_wrapper = "pwsh -command"

OR

vim.g.asyncrun_wrapper = "pwsh -command"
pedrohgmacedo commented 3 months ago

I haven't tested on neovim tbh. But the latest version is still working in my config though.

skywind3000 commented 3 months ago

@bjjblackbelt , what is your current setting of shell and shellcmdflag ? and your neovim version please? I can't reproduce your last error.

pedrohgmacedo commented 3 months ago

if s:asyncrun_windows == 0 let s:async_job = jobstart(l:args, l:callbacks) else let s:async_job = jobstart("cmd /C \"" . l:args . "\"", l:callbacks) endif

jobstart is neovim only. job_start is vim only.

bjjblackbelt commented 3 months ago

@bjjblackbelt , what is your current setting of shell and shellcmdflag ? and your neovim version please? I can't reproduce your last error.

shell=cmd.exe
shellcmdflag=/s /c

neovim version = 0.9.5

bjjblackbelt commented 3 months ago

I tested without my config files and just loading the asyncrun plugin. All appears to be working well with 2.12.8. I even tested by changing the following:

set shell=pwsh
set shellcmdflag=-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;
let g:asyncrun_wrapper='pwsh -command'

It appears the issue is on my end, though do not know what it could be. The 'fix' I posted earlier still works with my configs and plugins. Will keep exploring. Thank you for the quick response.

skywind3000 commented 3 months ago

still can't reproduce it, are you sure you were using 2.12.8 (and have your nvim restarted after updating) ?

skywind3000 commented 3 months ago

sorry,

bjjblackbelt commented 3 months ago

I tracked down my problem to having the shellslash option set to true. When I set this to false AsyncRun executes as expected on Windows. My shell option is set to use pwsh as well. Related to issue #184?

skywind3000 commented 3 months ago

please try: https://github.com/skywind3000/asyncrun.vim/releases/tag/2.12.9

bjjblackbelt commented 3 months ago

please try: https://github.com/skywind3000/asyncrun.vim/releases/tag/2.12.9

Version 2.12.9 works on my system with shellslash set to true. Thanks!