Powershell CommandLine Editor

Avec NeoVim, GnuVim ou encore les éditeurs VI ou nano qui arrivent avec les installations de Git, l’environnement Windows n’est plus avare en éditeur en mode Console.

Quel rapport avec Powershell ? Aucun…ou alors… Comme vous le savez les release récentes de Powershell sur Windows* arrivent avec le module PSReadLine dont l’un des buts est d’apporter un niveau de fonctionnalité équivalent au bash (et zsh) à powershell. Par exemple, vous pouvez activer un key binding VI ou EMACS (qui utilise encore emacs ?)

Nativement sous Bash, ou en activant un widget sous Zsh, nous pouvons éditer une ligne de commande complexe (comprendre une oneline assez long) dans l’éditeur renseigné dans la variable d’environnement $EDITOR.

Why not Zoidberg ? (Oups… me suis trompé de shell) Why not in Posh ?

Le module PSreadline nous permet de definir des séquences de caractères et de les binder à un scriptblock… Autant dire qu’il devient trivial d’établir cette fonctionnalité. En effet, avec BufferState nous pouvons récupérer le contenu du buffer

[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$Line, [ref]$Curso
       │ r)

avec RevertLine couplé avec InsertLine, nous pouvons réécrire le buffer de ligne de commande

[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.Powershell.PSConsoleReadLine]::Insert( $Line )

Il ne reste plus qu’à utiliser un fichier temporaire pour récupérer le buffer et le job est fait. Petit plus pour les fan de VI, nous pouvons préciser la type de fichier au lancement de l’éditeur. Comme je pars de principe que mes préférences ne sont pas universel, la commande en VIMode peut etre setter au caractère souhaité, je préfère utiliser <Leader> (\) qui ‘a pas de sens hors VIM et l’éditeur neovim, toutefois, ce sont des variables qui peuvent être adapter à vos préférences ($EDITOR, $EditKey)

Voilà le Handler proposé :

Set-PSReadLineKeyHandler -VIMode Command -Key  $(@{$False="\";$True=$EditKey}[$(Test-Path Variable:EditKey)]) -ScriptBlock {
	if( Get-Command $EDITOR){ 
		# Grab BufferLine
		$Line = $Null
		$Cursor = $Null
		[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$Line, [ref]$Cursor)
		# Launch Editor with temporary file
		$File = New-TemporaryFile
		Set-Content -Path $File -Value $Line
		if($EDITOR -match '[ng]?vim?'){
			Start-Process -wait $EDITOR -ArgumentList @($File, '-c ":set ft=ps1"', '-c ":set syntax=ps1"') -NoNewWindow
		}elseif($EDITOR -eq 'nano.exe'){
			Start-Process -wait $EDITOR -ArgumentList $File -NoNewWindow
		}else{
			Start-Process -wait $EDITOR -ArgumentList $File -NoNewWindow
		} 
		$Line = get-content $File
		# Write Command at prompt
		[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
		[Microsoft.Powershell.PSConsoleReadLine]::Insert( $Line ) 
		Remove-Item $File
	}else {
		throw [System.IO.FileNotFoundException] "$Editor not found."
	}
}

Pour suivre ou fournir des évolutions, il y a une gist public https://gist.github.com/belotn/35a77afd4b2e5e9c96c90e5bb6d469eb

Leave a Reply

Your email address will not be published.