Partager via


Intégration de l’interpréteur de commandes

À compter de la préversion du Terminal 1.15, le Terminal Windows a commencé à prendre en charge expérimentalement certaines fonctionnalités d’« intégration de l’interpréteur de commandes ». Ces fonctionnalités facilitent l’utilisation de la ligne de commande. Dans les versions antérieures, nous avons activé l’interpréteur de commandes pour indiquer au Terminal le répertoire de travail actuel. Nous avons désormais ajouté la prise en charge d’autres séquences pour permettre à l’interpréteur de commandes de décrire sémantiquement des parties de la sortie du terminal sous la forme d’« invite », de « commande » ou de « sortie ». L’interpréteur de commandes peut également indiquer au terminal si une commande a réussi ou échoué.

Il s’agit d’un guide de certaines fonctionnalités d’intégration de l’interpréteur de commandes déployées à partir du Terminal v1.18. Nous prévoyons de créer des fonctionnalités supplémentaires à l’avenir. Nous aimerions donc obtenir des commentaires supplémentaires sur la façon dont les utilisateurs les utilisent.

Remarque: à partir de Terminal 1.21, les marques sont désormais une fonctionnalité stable. Avant la version 1.21, les marques étaient uniquement activées pour les builds en préversion du terminal. Si vous utilisez une version de Terminal antérieure à la version 1.21, le paramètre showMarksOnScrollbar a été nommé experimental.showMarksOnScrollbar et autoMarkPrompts a été nommé experimental.autoMarkPrompts.

Comment cela fonctionne ?

L’intégration de l’interpréteur de commandes fonctionne ainsi : l’interpréteur de commandes (ou à toute application en ligne de commande) écrit des « séquences d’échappement » spéciales dans le terminal. Ces séquences d’échappement ne sont pas imprimées dans le terminal. Elles fournissent à la place des métadonnées que le terminal peut utiliser pour en savoir plus sur ce qui se passe dans l’application. En collant ces séquences dans l’invite de votre interpréteur de commandes, vous pouvez demander à l’interpréteur de commandes de fournir en continu des informations au terminal que seul l’interpréteur de commandes connaît.

Pour les séquences suivantes :

  • OSC est la chaîne "\x1b]" : un caractère d’échappement, suivi de ]
  • ST est le « terminateur de chaîne ». Il peut être \x1b\ (un caractère d’échappement, suivi de \) ou \x7 (le caractère d’appel)
  • Les espaces sont simplement illustratifs.
  • Les chaînes dans <> sont des paramètres qui doivent être remplacés par une autre valeur.

Voici les séquences pertinentes d’intégration d’interpréteur de commandes prises en charge à partir de Terminal v1.18 :

  • OSC 133 ; A ST ("FTCS_PROMPT") : début d’une invite.
  • OSC 133 ; B ST ("FTCS_COMMAND_START") : début d’une ligne de commande (READ : fin de l’invite).
  • OSC 133 ; C ST ("FTCS_COMMAND_EXECUTED") : début de la sortie de la commande/fin de la ligne de commande.
  • OSC 133 ; D ; <ExitCode> ST ("FTCS_COMMAND_FINISHED") : fin d’une commande. ExitCode Si ExitCode est fourni, le terminal traite 0 comme une « réussite » et tout autre résultat comme une erreur. En cas d’omission, le terminal laisse simplement la marque avec la couleur par défaut.

Guide pratique pour activer les marques d’intégration de l’interpréteur de commandes

La prise en charge de ces fonctionnalités nécessite une coopération entre votre interpréteur de commandes et le terminal. Vous devez à la fois activer les paramètres dans le terminal pour utiliser ces nouvelles fonctionnalités et modifier l’invite de votre interpréteur de commandes.

Pour activer ces fonctionnalités dans le terminal, vous devez ajouter les éléments suivants à vos paramètres :

"profiles":
{
    "defaults":
    {
        // Enable marks on the scrollbar
        "showMarksOnScrollbar": true,

        // Needed for both pwsh, CMD and bash shell integration
        "autoMarkPrompts": true,

        // Add support for a right-click context menu
        // You can also just bind the `showContextMenu` action
        "experimental.rightClickContextMenu": true,
    },
}
"actions":
[
    // Scroll between prompts
    { "keys": "ctrl+up",   "command": { "action": "scrollToMark", "direction": "previous" }, },
    { "keys": "ctrl+down", "command": { "action": "scrollToMark", "direction": "next" }, },

    // Add the ability to select a whole command (or its output)
    { "command": { "action": "selectOutput", "direction": "prev" }, },
    { "command": { "action": "selectOutput", "direction": "next" }, },

    { "command": { "action": "selectCommand", "direction": "prev" }, },
    { "command": { "action": "selectCommand", "direction": "next" }, },
]

La procédure pour activer ces marques dans votre interpréteur de commandes varie d’un interpréteur de commandes à l’autre. Vous trouverez ci-dessous des didacticiels pour CMD, PowerShell et Zsh.

PowerShell (pwsh.exe)

Si vous n’avez jamais changé votre invite PowerShell auparavant, vous devez d’abord consulter about_Prompts.

Nous devons modifier votre prompt pour nous assurer que nous informons le Terminal du CWD et appliquons les marques appropriées à l’invite. PowerShell permet également d’inclure le code d’erreur de la commande précédente dans la séquence 133;D, ce qui permet au terminal de coloriser automatiquement la marque selon une commande ayant réussi ou échoué.

Ajoutez ce qui suit à votre profil PowerShell :

$Global:__LastHistoryId = -1

function Global:__Terminal-Get-LastExitCode {
  if ($? -eq $True) {
    return 0
  }
  $LastHistoryEntry = $(Get-History -Count 1)
  $IsPowerShellError = $Error[0].InvocationInfo.HistoryId -eq $LastHistoryEntry.Id
  if ($IsPowerShellError) {
    return -1
  }
  return $LastExitCode
}

function prompt {

  # First, emit a mark for the _end_ of the previous command.

  $gle = $(__Terminal-Get-LastExitCode);
  $LastHistoryEntry = $(Get-History -Count 1)
  # Skip finishing the command if the first command has not yet started
  if ($Global:__LastHistoryId -ne -1) {
    if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
      # Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command)
      $out += "`e]133;D`a"
    } else {
      $out += "`e]133;D;$gle`a"
    }
  }


  $loc = $($executionContext.SessionState.Path.CurrentLocation);

  # Prompt started
  $out += "`e]133;A$([char]07)";

  # CWD
  $out += "`e]9;9;`"$loc`"$([char]07)";

  # (your prompt here)
  $out += "PWSH $loc$('>' * ($nestedPromptLevel + 1)) ";

  # Prompt ended, Command started
  $out += "`e]133;B$([char]07)";

  $Global:__LastHistoryId = $LastHistoryEntry.Id

  return $out
}

Oh My Posh setup

En utilisant oh-my-posh ? Vous souhaiterez légèrement modifier l’invite d’origine, puis l’ajouter au milieu des séquences d’échappement d’intégration de l’interpréteur de commandes.

# initialize oh-my-posh at the top of your profile.ps1
oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH\gruvbox.omp.json" | Invoke-Expression
# then stash away the prompt() that oh-my-posh sets
$Global:__OriginalPrompt = $function:Prompt

function Global:__Terminal-Get-LastExitCode {
  if ($? -eq $True) { return 0 }
  $LastHistoryEntry = $(Get-History -Count 1)
  $IsPowerShellError = $Error[0].InvocationInfo.HistoryId -eq $LastHistoryEntry.Id
  if ($IsPowerShellError) { return -1 }
  return $LastExitCode
}

function prompt {
  $gle = $(__Terminal-Get-LastExitCode);
  $LastHistoryEntry = $(Get-History -Count 1)
  if ($Global:__LastHistoryId -ne -1) {
    if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
      $out += "`e]133;D`a"
    } else {
      $out += "`e]133;D;$gle`a"
    }
  }
  $loc = $($executionContext.SessionState.Path.CurrentLocation);
  $out += "`e]133;A$([char]07)";
  $out += "`e]9;9;`"$loc`"$([char]07)";
  
  $out += $Global:__OriginalPrompt.Invoke(); # <-- This line adds the original prompt back

  $out += "`e]133;B$([char]07)";
  $Global:__LastHistoryId = $LastHistoryEntry.Id
  return $out
}

Invite de commandes

L’invite de commandes trouve l’invite dans la variable d’environnement PROMPT. CMD.exe lit $e en tant que caractère ESC. Malheureusement, CMD.exe n’est pas en mesure d’obtenir le code de retour de la commande précédente dans l’invite. Nous ne pouvons donc pas fournir d’informations indiquant une réussite/erreur dans les invites CMD.

Pour modifier l’invite pour l’instance CMD.exe actuelle, exécutez :

PROMPT $e]133;D$e\$e]133;A$e\$e]9;9;$P$e\$P$G$e]133;B$e\

Vous pouvez également définir la variable à partir de la ligne de commande pour toutes les sessions futures :

setx PROMPT $e]133;D$e\$e]133;A$e\$e]9;9;$P$e\$P$G$e]133;B$e\

Ces exemples supposent que votre PROMPT actuel est simplement $P$G. À la place, vous pouvez choisir d’inclure votre invite actuelle dans un wrapper de cette manière :

PROMPT $e]133;D$e\$e]133;A$e\$e]9;9;$P$e\%PROMPT%$e]133;B$e\

Bash

Vous pouvez ajouter les éléments suivants à la fin de votre ~/.bashrc pour activer l’intégration de l’interpréteur de commandes dans bash :

PS1="\[\033]133;D;\007\]\[\033]133;A;\007\]$PS1\[\033]133;B;\007\]"

Cela encapsule votre $PS1 existante avec les séquences nécessaires pour activer l’intégration de l’interpréteur de commandes.

Remarque : vous ne voyez pas votre interpréteur de commandes favori ici ? Dans ce cas, n’hésitez pas à contribuer à l’ajout d’une solution d’une solution pour l’interpréteur de commandes de votre choix !

Fonctionnalités d'intégration de l’interpréteur de commandes

Ouvrir de nouveaux onglets dans le même répertoire de travail

Ouvrir de nouveaux onglets dans le même répertoire de travail

Afficher les marques pour chaque commande dans la barre de défilement

Afficher les marques pour chaque commande dans la barre de défilement

Saut automatique entre les commandes

Cela utilise les actions scrollToMark comme nous les avons définies ci-dessus.

Saut automatique entre les commandes

Sélectionner la sortie entière d’une commande

Dans ce gif, nous utilisons l’action selectOutput liée à ctrl+g pour sélectionner l’intégralité de la sortie d’une commande. Sélectionner la sortie entière d’une commande

Les éléments suivants utilisent le paramètre experimental.rightClickContextMenu pour activer un menu contextuel en cliquant avec le bouton droit dans le Terminal. Lorsque l’intégration de l’interpréteur de commandes est activée, vous pouvez cliquer avec le bouton droit sur une commande pour sélectionner la commande entière ou sa sortie.

Sélectionner la commande à l’aide du menu contextuel par clic droit

Suggestions de commande récentes

Une fois l’intégration de l’interpréteur de commandes activée, l’interface utilisateur Suggestions peut être configurée pour afficher vos commandes récentes.

Interface utilisateur Suggestions montrant les commandes récentes qu’elle contient

Vous pouvez ouvrir ce menu avec l’action suivante :

{
    "command": { "action": "showSuggestions", "source": "recentCommands", "useCommandline": true },
},

(Pour plus d’informations, consultez la documentation Suggestions)

Ressources supplémentaires