Integrazione della shell

A partire da Terminale 1.15 Anteprima, il Terminale Windows ha iniziato a supportare in modo sperimentale alcune funzionalità di "integrazione della shell". Queste funzionalità semplificano l'uso della riga di comando. Nelle versioni precedenti veniva abilitata la shell per indicare al terminale la directory di lavoro corrente. Ora è stato aggiunto il supporto per altre sequenze per consentire alla shell di descrivere semanticamente parti dell'output del terminale come "prompt", "comando" o "output". La shell può anche indicare al terminale se un comando ha avuto esito positivo o negativo.

Questa è una guida ad alcune delle funzionalità di integrazione della shell implementate a partire da Terminale v1.18. Stiamo pianificando di creare ancora più funzionalità in futuro, quindi ci piacerebbe ottenere un feedback aggiuntivo sul modo in cui le persone le usano.

Nota: a partire dal terminale 1.21, i contrassegni sono ora una funzionalità stabile. Prima della versione 1.21, i contrassegni sono stati abilitati solo per le build di anteprima del terminale. Se si usa una versione di Terminale precedente alla 1.21, l'impostazione showMarksOnScrollbar è denominata experimental.showMarksOnScrollbare autoMarkPrompts è denominata experimental.autoMarkPrompts.

Come funziona?

L'integrazione della shell funziona con la shell (o qualsiasi applicazione della riga di comando) per scrivere "sequenze di escape" speciali nel terminale. Queste sequenze di escape non vengono stampate nel terminale, ma forniscono bit di metadati che il terminale può usare per saperne di più su cosa sta succedendo nell'applicazione. Se si aggiungono queste sequenze al prompt della shell, è possibile che la shell fornisca continuamente informazioni al terminale che solo la shell conosce.

Per le sequenze seguenti:

  • OSC è "\x1b]" per la stringa: un carattere di escape, seguito da ]
  • ST è il carattere di terminazione stringa e può essere \x1b\ (un carattere ESC, seguito da \) o \x7 (il carattere BEL)
  • Gli spazi sono semplicemente illustrativi.
  • Le stringhe in <> sono parametri che devono essere sostituiti da un altro valore.

Le sequenze di integrazione della shell supportate pertinenti a partire da Terminale v1.18 sono:

  • OSC 133 ; A ST ("FTCS_PROMPT") - L'inizio di un prompt.
  • OSC 133 ; B ST ("FTCS_COMMAND_START") - L'inizio di una riga di comando (READ: la fine del prompt).
  • OSC 133 ; C ST ("FTCS_COMMAND_EXECUTED") - L'inizio dell'output del comando/la fine della riga di comando.
  • OSC 133 ; D ; <ExitCode> ST ("FTCS_COMMAND_FINISHED") - La fine di un comando. ExitCode Se ExitCode viene specificato, il terminale considererà 0 come "esito positivo" e qualsiasi altro elemento come errore. Se omesso, il terminale lascerà solo il segno di colore predefinito.

Come abilitare i contrassegni di integrazione della shell

Il supporto di queste funzionalità richiede la cooperazione tra la shell e il terminale. È necessario abilitare entrambe le impostazioni nel terminale per usare queste nuove funzionalità, nonché modificare il prompt della shell.

Per abilitare queste funzionalità nel terminale, è necessario aggiungere quanto segue alle impostazioni:

"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 modalità di abilitazione di questi contrassegni nella shell varia da shell a shell. Di seguito sono riportate le esercitazioni per CMD, PowerShell e Zsh.

PowerShell (pwsh.exe)

Se il prompt di PowerShell non è mai stato modificato in precedenza, è consigliabile consultare prima about_Prompts.

È necessario modificare il file prompt per assicurarsi che il terminale sia in grado di comunicare con la CWD e contrassegnare il prompt con i contrassegni appropriati. PowerShell consente anche di includere il codice di errore del comando precedente nella sequenza 133;D, che consentirà al terminale di colorare automaticamente il contrassegno in base all'esito positivo o negativo del comando.

Aggiungere quanto segue al profilo di 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

Usando oh-my-posh? È consigliabile modificare leggermente il codice precedente per eliminare il prompt originale, quindi aggiungerlo di nuovo al centro delle sequenze di escape di integrazione della shell.

# 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
}

Prompt dei comandi

Le origini del prompt dei comandi vengono richieste dalla variabile di ambiente PROMPT. CMD.exe legge $e come ESC carattere. Sfortunatamente, CMD.exe non ha un modo per ottenere il codice restituito del comando precedente nel prompt, quindi non è possibile fornire informazioni sull'esito positivo/negativi nei prompt CMD.

È possibile modificare il prompt dell'istanza CMD.exe corrente eseguendo:

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

In alternativa, è possibile impostare la variabile dalla riga di comando per tutte le sessioni future:

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

Questi esempi presuppongono che l'oggetto corrente PROMPT sia solo $P$G. È invece possibile scegliere di eseguire il wrapping del prompt corrente con un messaggio simile al seguente:

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

Bash

È possibile aggiungere quanto segue alla fine di per abilitare l'integrazione della ~/.bashrc shell in bash:

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

Verrà eseguito il wrapping dell'esistente $PS1 con le sequenze necessarie per abilitare l'integrazione della shell.

Nota: la shell preferita non è indicata qui? Se lo si scopre, è possibile contribuire a una soluzione per la shell preferita.

Funzionalità di integrazione della shell

Aprire nuove schede nella stessa directory di lavoro

Aprire nuove schede nella stessa directory di lavoro

Mostrare segni per ogni comando nella barra di scorrimento

Mostrare segni per ogni comando nella barra di scorrimento

Passare automaticamente tra i comandi

In questo modo vengono usate le scrollToMark azioni definite in precedenza.

Passare automaticamente tra i comandi

Selezionare l'intero output di un comando

In questa gif viene usata l'azione selectOutput associata a ctrl+g per selezionare l'intero output di un comando. Selezionare l'intero output di un comando

Di seguito viene usata l'impostazione experimental.rightClickContextMenu per abilitare un menu di scelta rapida del pulsante destro del mouse nel terminale. Con l'integrazione di tale e shell abilitata, è possibile fare clic con il pulsante destro del mouse su un comando per selezionare l'intero comando o il relativo output.

Selezionare il comando usando il menu di scelta rapida con il pulsante destro del mouse

Suggerimenti recenti per i comandi

Con l'integrazione della shell abilitata, è possibile configurare l'interfaccia utente dei suggerimenti per visualizzare anche i comandi recenti.

Interfaccia utente dei suggerimenti che mostra i comandi recenti

È possibile aprire questo menu con l'azione seguente:

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

(Per altre info, vedi Documentazione dei suggerimenti)

Risorse aggiuntive