equ*_*all 5 vim powershell windows-subsystem-for-linux
我正在尝试创建一个 Powershell 函数,充当 WSL 中 Vim 的包装器。我希望这个包装器能够接受来自管道的输入。
在 WSL 中,可以执行以下操作:
$ cat manylines.txt | vim -
Run Code Online (Sandbox Code Playgroud)
指示-
Vim 应该从 stdin 读取输入,然后通过管道重定向该输入。这将打开 vim,命令输出已在缓冲区中,但没有任何关联的文件。(您也可以简单地使用 打开文件vim manylines.txt
,但这通常不适用于其他命令或可执行文件的输出)。
在 Powershell 和 Windows 原生 Vim 中也可以实现同样的效果:
Get-Content manylines.txt | vim -
Run Code Online (Sandbox Code Playgroud)
可以更进一步,在另一个 Powershell 或 cmd 实例中执行 Vim:
Get-Content manylines.txt | powershell -Command vim -
Get-Content manylines.txt | cmd /c vim -
Run Code Online (Sandbox Code Playgroud)
但是,这不适用于 WSL Vim。
# doesn't work, Vim freezes
Get-Content manylines.txt | wsl vim -
Get-Content manylines.txt | wsl bash -c "vim -"
# doesn't work, Vim quits reporting "Error reading Input"
Get-Content manylines.txt | wsl bash -c vim -
Run Code Online (Sandbox Code Playgroud)
在前两种情况下,Vim 正确打开,缓冲区中包含 Manylines.txt 的内容...然后拒绝接受任何键盘输入。无法使用 进行导航、编辑甚至退出:q!
。
使用临时 powershell 变量似乎可以解决问题,但仅当输入由单行组成时
# "works as long as the file only has a single line of text"
# "$tmpvar has type System.String (not an array)"
$tmpvar = Get-Content singleline.txt
wsl bash -c "echo $tmp | vim -"
Run Code Online (Sandbox Code Playgroud)
但是当 $tmpvar 变成 String[] 数组或带有任何换行符的 String 时,就会中断
# sort of works, but newlines are converted to a single space
$tmpvar = [string[]] Get-Content manylines.txt
wsl bash -c "echo $tmp | vim -"
# combines the strings in the array, inserts a newline between each pair of elements
$tmpvar = ([string[]] Get-Content manylines.txt) -join "`n"
# doesn't work, bash interprets the newline as the start of the next command
wsl bash -c "echo $tmp | vim -"
Run Code Online (Sandbox Code Playgroud)
如何让 WSL Vim 接受来自 Powershell 的管道输入?
其他注意事项:
事实上,管道输入到vim
viawsl
似乎破坏了光标移动的vim
键盘界面(例如,我仍然能够输入退出)。:q!
解决方法是改进您发现的方法,即提供输入作为传递给的 shell 命令的一部分,wsl
而不是使用管道:
这样做需要仔细的转义和转换,如以下包装函数所示:
# PowerShell wrapper function for invoking vim via WSL
function vim {
if ($MyInvocation.ExpectingInput) { # pipeline input present
$allInput = ($input | Out-String) -replace '\r?\n', "`n" -replace "'", "'\''" -replace '"', '\"'
wsl -e sh -c "printf %s '$allInput' | vim $args -"
}
elseif ($args) { # no pipeline input, arguments that may include file paths given
wsl -e vim ($args.ToLower() -replace '^([a-z]):', '/mnt/$1' -replace '\\', '/')
} else { # no pipeline input, no pass-through arguments
wsl -e vim
}
}
Run Code Online (Sandbox Code Playgroud)
注意事项:
定义此函数后,您可以调用(+
作为示例选项,告诉vim
将光标放在输入的末尾):
vim + somefile.txt
Run Code Online (Sandbox Code Playgroud)
或者
Get-ChildItem | vim +
Run Code Online (Sandbox Code Playgroud)