3 votes

Comment modifier la ligne de commande dans un éditeur externe ?

tl;dr

Je souhaite trouver une version Powershell de la fonction bash edit-and-execute-command ou le widget zsh edit-command-line widget.

Contexte

Les commandes courtes sont exécutées directement sur la ligne de commande, les commandes longues et compliquées sont exécutées à partir de scripts. Cependant, avant qu'elles ne deviennent "longues", il est utile de pouvoir tester des commandes de longueur moyenne sur la ligne de commande. Pour ce faire, il est très utile d'éditer la commande dans un éditeur externe. AFAIK Powershell ne supporte pas cela nativement comme par exemple bash y zsh faire.

Ma tentative actuelle

Je suis novice en matière de Powershell, je vais donc faire beaucoup d'erreurs, mais j'ai avoir proposer une solution opérationnelle en utilisant les fonctionnalités de l'application [Microsoft.Powershell.PSConsoleReadLine] classe. Je suis capable de copier la ligne de commande actuelle dans un fichier, de modifier le fichier, puis de réinjecter la version modifiée dans la ligne de commande :

Set-PSReadLineKeyHandler -Chord "Alt+e" -ScriptBlock {
  $CurrentInput = $null

  # Copy current command-line input, save it to a file and clear it
  [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref] $CurrentInput, [ref] $null)
  Set-Content -Path "C:\Temp\ps_${PID}.txt" -Value "$CurrentInput"
  [Microsoft.PowerShell.PSConsoleReadLine]::KillRegion()

  # Edit the command with gvim
  Start-Job -Name EditCMD -ScriptBlock { gvim "C:\Temp\ps_${Using:PID}.txt" }
  Wait-Job  -Name EditCMD

  # Get command back from file the temporary file and insert it into the command-line
  $NewInput  = (Get-Content -Path "C:\Temp\ps_${PID}.txt") -join "`n"
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert($NewInput)
}

Questions

La solution que j'ai trouvée jusqu'à présent me semble lourde et quelque peu fragile. Existe-t-il d'autres solutions ? La solution actuelle peut-elle être améliorée ?

Environnement

  • OS Windows 10.0.19043.0
  • Powershell version 5.1.19041.1320
  • PSReadLine version 2.0.0

La solution que j'ai choisie

Créer un exécutable "cuit" similaire à ce que l'on trouve dans mklement0 a montré. Je préfère vim au lieu de `gvim, car il s'exécute directement dans la console :

'@vim -f %*' > psvim.cmd

$env:EDITOR = "psvim"
Set-PSReadLineKeyHandler -Chord "Alt+e" -Function ViEditVisually

4voto

zett42 Points 6849

Ce code pose quelques problèmes :

  • Le chemin Temp est codé en dur, il devrait utiliser $env:temp ou mieux encore [IO.Path]::GetTempPath() (pour une compatibilité multiplateforme).
  • Après avoir modifié la ligne, il ne remplace pas toute la ligne, mais seulement le texte à gauche du curseur. Comme l'a fait remarquer mklement0 nous pouvons simplement remplacer le tampon existant au lieu de l'effacer, ce qui résout le problème.
  • En utilisant les bons paramètres pour l'éditeur, il n'est pas nécessaire de créer une tâche pour l'attendre. Pour VSCode, il s'agit de --wait ( -w ) et pour gvim c'est --nofork ( -f ) qui empêche ces processus de se détacher du processus de la console, de sorte que le code PowerShell attend que l'utilisateur ait fermé l'éditeur.
  • Le fichier temporaire n'est pas supprimé après la fermeture de l'éditeur.

Voici ma tentative de correction du code. Je n'utilise pas gvim Je l'ai donc testé avec VSCode code.exe . Le code ci-dessous contient une ligne commentée pour gvim (confirmé par l'OP).

Set-PSReadLineKeyHandler -Chord "Alt+e" -ScriptBlock {
    $CurrentInput = $null

    # Copy current console line
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref] $CurrentInput, [ref] $null)

    # Save current console line to temp file
    $tempFilePath = Join-Path ([IO.Path]::GetTempPath()) "ps_$PID.ps1"
    Set-Content $tempFilePath -Value $CurrentInput -Encoding utf8

    # Edit the console line using VSCode
    code --new-window --wait $tempFilePath

    # Uncomment for using gvim editor instead
    # gvim -f $tempFilePath

    # The console doesn't like the CR character, so rejoin lines using LF only. 
    $editedInput = ((Get-Content -LiteralPath $tempFilePath) -join "`n").Trim()

    # Replace current console line with the content of the temp file
    [Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $currentInput.Length, $editedInput)

    Remove-Item $tempFilePath
}

Mise à jour :

Le présent GitHub Gist comprend une version actualisée du code. Les nouvelles fonctionnalités comprennent la sauvegarde/restauration de la position du curseur, le passage de la position du curseur à VSCode et l'affichage d'un message lorsque la console est bloquée.

Notes :

  • Une installation par défaut de VSCode ajoute le répertoire des binaires de VSCode à $env:PATH ce qui nous permet d'écrire seulement code pour lancer l'éditeur.
  • Alors que UTF-8 est l'encodage par défaut pour les cmdlets comme Set-Content en PowerShell Core , pour Windows PowerShell le paramètre -Encoding utf8 est nécessaire pour enregistrer correctement les commandes contenant des caractères Unicode. Pour les Get-Content Il n'est pas nécessaire de spécifier l'encodage, car Windows PowerShell ajoute une nomenclature qui Get-Content est détecté et PowerShell Core revient par défaut à UTF-8.
  • Pour avoir Alt+E toujours disponible lorsque vous ouvrez une console, il suffit d'ajouter ce code à votre $profile archivo . Il permet de tester et d'éditer rapidement de petits échantillons de code.
  • Paramètres VSCode - pour une expérience simplifiée, activez "Auto Save : onWindowChange". Permet de fermer l'éditeur et d'enregistrer le fichier (mise à jour de la ligne de console) d'une simple pression sur la touche Ctrl+W .

4voto

mklement0 Points 12597

tl;dr

  • PSReadLine est doté de la fonction que vous recherchez , à savoir le ViEditVisually et, sur les plates-formes de type Unix, elle dispose même d'une combinaison de touches par défaut.

  • Pour que cette fonction fonctionne, vous devez définir les paramètres suivants $env:VISUAL o $env:EDITOR au nom / chemin de l'exécutable de votre éditeur.

  • Depuis PSReadLine v2.1, si vous devez également inclure les éléments suivants options pour votre éditeur - par exemple -f para gvim - vous devez créer un exécutable d'aide qui a les options "intégrées".

    • Comme la création d'un exécutable d'aide est fastidieuse, une émulation personnalisée de la fonction, comme vous l'avez tenté et comme vous l'avez affiné dans le document Réponse utile de zett42 La réponse de zett42 contient également un lien vers une Gist qui améliore la fonctionnalité originale en préservant les positions du curseur.

    • Problème GitHub #3214 propose d'ajouter un support pour la reconnaissance des exécutables et leurs options dans ces variables d'environnement.

Détails ci-dessous.


  • En PSReadLine module navires avec une telle caractéristique , à savoir le ViEditVisually fonction .

  • Son liaisons de touches par défaut le cas échéant, dépendent de l'état d'avancement de PSReadLine. mode édition que vous pouvez définir à l'aide de Set-PSReadLineOption -EditMode <mode> :

    • Windows (par défaut sous Windows) : non lié
    • Emacs (par défaut sur macOS et Linux) : Ctrl-xCtrl-e
    • Vi mode : v en mode commande (appuyer sur Esc pour y accéder)
  • Utilisation Set-PSReadLineKeyHandler d'établir une Liaison de touches personnalisées , analogue à l'approche retenue dans la question ; par exemple, pour lier Alt-e :

    • Set-PSReadLineKeyHandler -Chord Alt+e -Function ViEditVisually
  • Pour que la fonction fonctionne, vous devez définir l'exécutable de l'éditeur à utiliser via l'une des variables d'environnement suivantes, par ordre de priorité : $env:VISUAL o $env:EDITOR ; si aucun éditeur (valide) n'est défini, un signal sonore d'avertissement est émis et aucune action n'est entreprise lorsque la fonction est invoquée.

    • Par exemple, pour utiliser le nano sur macOS : $env:VISUAL = 'nano'

    • En doit faire référence à un fichier exécutable - soit par le chemin d'accès complet, soit, plus généralement, par le nom seulement, auquel cas il doit être situé dans un répertoire répertorié dans la rubrique $env:PATH

      • Remarque : .ps1 scripts do pas sont considérés comme des fichiers exécutables, mais fichiers de lots sous Windows et sur les lignes shebang shell scripts sur les plates-formes de type Unix.
    • Depuis PSReadLine 2.1, y compris options pour l'exécutable - par exemple --newindow --wait para code (Visual Studio Code) est pas soutenu .

      • C'est pourquoi, pour l'instant, si votre éditeur de choix nécessite des options vous devez créer un exécutable d'aide qui intègre ces options voir les exemples ci-dessous.

      • Problème GitHub #3214 a proposé d'ajouter un support permettant de spécifier l'exécutable de l'éditeur plus des options comme valeur de la variable d'environnement, ce que Git (qui reconnaît les mêmes variables) prend déjà en charge ; par exemple, vous pourriez alors définir :
        $env:VISUAL = 'code --new-window --wait'


Exemple de configuration avec un exécutable d'aide para code (Visual Studio Code) :

  • Dans cet exemple, créez un exécutable d'aide dans le répertoire personnel de l'utilisateur :

    • Sous Windows :

      '@code --new-window --wait %*' > "$HOME\codewait.cmd"
    • Sur les plates-formes de type Unix :

      "#!/bin/sh`ncode --new-window --wait `"$@`"" > "$HOME/codewait"; chmod a+x "$HOME/codewait"
  • Ajouter une définition de $env:VISUAL pointant vers l'exécutable d'aide dans votre $PROFILE ainsi que la définition d'une clé de liaison personnalisée, le cas échéant :

    $env:VISUAL = "$HOME/codewait"

    Custom key binding

    Set-PSReadLineKeyHandler -Chord Alt+e -Function ViEditVisually

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X