plugins icon indicating copy to clipboard operation
plugins copied to clipboard

feat: powershell and nushell support

Open beskep opened this issue 4 months ago • 2 comments

This PR adds support for Powershell and Nushell of piper.

I haven't worked with Lua before, so there may be some bugs, but please consider expanding shell support.

Thank you!

beskep avatar Sep 16 '25 08:09 beskep

Thank you for your patch!

Is it possible to pass the file path as an argument to PowerShell or Nushell, just like with sh, and then use their respective $args[0] or $env.NU_ARGV[0] instead of replacing all of them with $1? Otherwise, there will be a lot of edge cases to consider, which would require a dedicated parser, which is pretty complicated - for example, the parser for cmd.exe is over 100 lines so that to cover all the cases, https://github.com/sxyazi/yazi/blob/7deeaa4356a0fa1eecd7264998a298866f31cb0a/yazi-scheduler/src/process/shell.rs#L77-L181

Also, based on my tests, PowerShell has poor startup speed and is much slower than cmd.exe, which is especially noticeable in scenarios like previewing, which require low latency. I'm not sure if it makes sense to support it here, maybe we can start by adding basic cmd.exe support first? I haven't used Nushell myself, so it would be nice to see some benchmark data.

sxyazi avatar Sep 16 '25 10:09 sxyazi

My initial code was quite a mess 😅.

I've refactored it to pass the path via a pipeline instead of replacing $1. Unfortunately, I wasn't able to implement this for cmd.exe. (I don't have much experience with programming and have been relying heavily on Gemini and ChatGPT.)

Here are some simple performance test from my PC (Win11, Ryzen 5 9600X). Please let me know if there's a more appropriate benchmarking method.

local start_time = ya.time()
local child, err = Command(cmd)
	:arg(args)
	:env("w", job.area.w)
	:env("h", job.area.h)
	:stdout(Command.PIPED)
	:stderr(Command.PIPED)
	:spawn()
local elapsed_time = (ya.time() - start_time) * 1000
ya.notify({ title = "elapsed time", content = string.format("%.1f ms", elapsed_time), timeout = 1 })})

results:

shell (yazi) require("piper"):
setup(shell = )
plugin.prepend_
previewers.run
try elapsed time (ms)
pwsh (powershell 7.5.3) pwsh piper -- echo $_ 1 96.4
pwsh (powershell 7.5.3) pwsh piper -- echo $_ 2 52.4
pwsh (powershell 7.5.3) pwsh piper -- echo $_ 3 50.3
pwsh (powershell 7.5.3) pwsh piper -- echo $_ 4 50.4
pwsh (powershell 7.5.3) pwsh piper -- echo $_ 5 50.7
powershell (powershell 5) powershell piper -- echo $_ 1 5.0
powershell (powershell 5) powershell piper -- echo $_ 2 5.5
powershell (powershell 5) powershell piper -- echo $_ 3 6.0
powershell (powershell 5) powershell piper -- echo $_ 4 5.6
powershell (powershell 5) powershell piper -- echo $_ 5 5.2
nushell nushell piper -- echo $in 1 2.8
nushell nushell piper -- echo $in 2 3.4
nushell nushell piper -- echo $in 3 2.8
nushell nushell piper -- echo $in 4 2.8
nushell nushell piper -- echo $in 5 3.0
git bash sh piper -- echo %1 1 10.6
git bash sh piper -- echo %1 2 2.6
git bash sh piper -- echo %1 3 3.1
git bash sh piper -- echo %1 4 3.0
git bash sh piper -- echo %1 5 2.5
nushell pwsh piper -- echo $_ 1 98.8
nushell pwsh piper -- echo $_ 2 52.2
nushell pwsh piper -- echo $_ 3 52.4
nushell pwsh piper -- echo $_ 4 51.0
nushell pwsh piper -- echo $_ 5 50.1
pwsh (powershell 7.5.3) nushell piper -- echo $in 1 2.7
pwsh (powershell 7.5.3) nushell piper -- echo $in 2 3.0
pwsh (powershell 7.5.3) nushell piper -- echo $in 3 2.6
pwsh (powershell 7.5.3) nushell piper -- echo $in 4 2.5
pwsh (powershell 7.5.3) nushell piper -- echo $in 5 3.0

beskep avatar Sep 17 '25 07:09 beskep