zsh giustifica a destra in ps1


21

Vorrei un prompt zsh multilinea con una parte allineata a destra, che assomiglierà a questo:

2.nate@host:/current/dir                                               16:00
->

Conosco RPROMPT in zsh, ma ha un prompt allineato a destra di fronte al normale prompt, che si trova sulla stessa riga di testo della digitazione.

C'è un modo per avere una porzione allineata a destra alla prima riga di un prompt dei comandi multilinea? Sto cercando una direttiva nella variabile PS1 che dice "allinea subito adesso" o una variabile che è per PS1 ciò che RPROMPT sta per PROMPT.

Grazie!

Risposte:


12

Troverai una risposta dettagliata e un esempio qui . L'idea è di scrivere la riga prima di PS1 usando il precmdcallback, usare $COLUMNSe un po 'di matematica per calcolare la posizione del testo sul lato destro dello schermo. La conoscenza delle sequenze di escape ti aiuterà anche con il posizionamento e la colorazione del cursore.

Un'altra soluzione può essere quella di utilizzare un tema di Oh My ZSH .


10

Ho cercato anche questo. Per me, il fatto che le precmd()linee disegnate non si ridisegnassero al ridimensionamento o quando ^Lviene utilizzato per cancellare lo schermo è stato qualcosa che mi ha prurito. Quello che sto facendo ora è usare le sequenze di escape ANSI per spostare un po 'il cursore. Anche se sospetto che esista un modo più elegante per emetterli, questo funziona per me:

_newline=$'\n'
_lineup=$'\e[1A'
_linedown=$'\e[1B'

PROMPT=...whatever...${_newline}...whatever...
RPROMPT=%{${_lineup}%}...whatever...%{${_linedown}%}

Tieni presente che il manuale di zsh afferma che% {...%} è per sequenze letterali di escape che non spostano il cursore . Anche così, li sto usando perché permettono di ignorare la lunghezza del suo contenuto (non riuscivo a capire come emettere la fuga che sposta il cursore usando loro però)


Dopo aver giocato con questo per qualche tempo, si incasina di tanto in tanto e posiziona il cursore o la data sulla riga sbagliata. Non è un grosso problema però; puoi semplicemente premere Invio per correggerlo.
Aprire il

3

Ecco come ho configurato questa cosa proprio ora. Questo approccio non richiede manipolazioni della sequenza di escape, ma ti farà avere due diverse variabili per il prompt primario: PS1con colorazione e NPS1senza.

# Here NPS1 stands for "naked PS1" and isn't a built-in shell variable. I've
# defined it myself for PS1-PS2 alignment to operate properly.
PS1='%S%F{red}[%l]%f%s %F{green}%n@%m%f %B%#%b '
NPS1='[%l] %n@%m # '
RPS1='%B%F{green}(%~)%f%b'

# Hook function which gets executed right before shell prints prompt.
function precmd() {
    local expandedPrompt="$(print -P "$NPS1")"
    local promptLength="${#expandedPrompt}"
    PS2="> "
    PS2="$(printf "%${promptLength}s" "$PS2")"
}

Nota l'uso di print -Pper l'espansione rapida, ${#variable}per ottenere la lunghezza della stringa memorizzata in variabile e printf "%Nd"per il riempimento a sinistra con Nspazi. Entrambi printe printfsono comandi integrati, quindi non dovrebbe esserci alcun impatto sulle prestazioni.


1

Definiamo il prompt con questo layout:

top_left              top_right
bottom_left        bottom_right

Per fare ciò, avremo bisogno di una funzione che ci dice quanti caratteri assume una determinata stringa quando viene stampata.

# Usage: prompt-length TEXT [COLUMNS]
#
# If you run `print -P TEXT`, how many characters will be printed
# on the last line?
#
# Or, equivalently, if you set PROMPT=TEXT with prompt_subst
# option unset, on which column will the cursor be?
#
# The second argument specifies terminal width. Defaults to the
# real terminal width.
#
# Assumes that `%{%}` and `%G` don't lie.
#
# Examples:
#
#   prompt-length ''            => 0
#   prompt-length 'abc'         => 3
#   prompt-length $'abc\nxy'    => 2
#   prompt-length '❎'          => 2
#   prompt-length $'\t'         => 8
#   prompt-length $'\u274E'     => 2
#   prompt-length '%F{red}abc'  => 3
#   prompt-length $'%{a\b%Gb%}' => 1
#   prompt-length '%D'          => 8
#   prompt-length '%1(l..ab)'   => 2
#   prompt-length '%(!.a.)'     => 1 if root, 0 if not
function prompt-length() {
  emulate -L zsh
  local COLUMNS=${2:-$COLUMNS}
  local -i x y=$#1 m
  if (( y )); then
    while (( ${${(%):-$1%$y(l.1.0)}[-1]} )); do
      x=y
      (( y *= 2 ));
    done
    local xy
    while (( y > x + 1 )); do
      m=$(( x + (y - x) / 2 ))
      typeset ${${(%):-$1%$m(l.x.y)}[-1]}=$m
    done
  fi
  echo $x
}

Avremo bisogno di un'altra funzione che accetta due argomenti e stampa una multa completa con questi argomenti sui lati opposti dello schermo.

# Usage: fill-line LEFT RIGHT
#
# Prints LEFT<spaces>RIGHT with enough spaces in the middle
# to fill a terminal line.
function fill-line() {
  emulate -L zsh
  local left_len=$(prompt-length $1)
  local right_len=$(prompt-length $2 9999)
  local pad_len=$((COLUMNS - left_len - right_len - ${ZLE_RPROMPT_INDENT:-1}))
  if (( pad_len < 1 )); then
    # Not enough space for the right part. Drop it.
    echo -E - ${1}
  else
    local pad=${(pl.$pad_len.. .)}  # pad_len spaces
    echo -E - ${1}${pad}${2}
  fi
}

Finalmente possiamo definire una funzione che imposta PROMPTe RPROMPT, incarica ZSH di chiamarla prima di ogni prompt e impostare le opzioni di espansione dei prompt appropriate:

# Sets PROMPT and RPROMPT.
#
# Requires: prompt_percent and no_prompt_subst.
function set-prompt() {
  emulate -L zsh
  local git_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
  git_branch=${${git_branch//\%/%%}/\\/\\\\\\}  # escape '%' and '\'

  local top_left='%F{blue}%~%f'
  local top_right="%F{green}${git_branch}%f"
  local bottom_left='%B%F{%(?.green.red)}%#%f%b '
  local bottom_right='%F{yellow}%T%f'

  PROMPT="$(fill-line "$top_left" "$top_right")"$'\n'$bottom_left
  RPROMPT=$bottom_right
}

autoload -Uz add-zsh-hook
add-zsh-hook precmd set-prompt
setopt noprompt{bang,subst} prompt{cr,percent,sp}

Questo produce il seguente prompt:

~/foo/bar                     master
%                             10:51
  • In alto a sinistra: directory corrente blu.
  • In alto a destra: ramo Green Git.
  • In basso a sinistra: #se root, in %caso contrario; verde in caso di successo, rosso in caso di errore.
  • In basso a destra: ora corrente gialla.

Puoi trovare ulteriori dettagli nel prompt Multi-line: l'ingrediente mancante e il codice completo in questa sintesi .


1
Benvenuto in Super User! Sebbene ciò possa teoricamente rispondere alla domanda, sarebbe preferibile includere qui le parti essenziali della risposta e fornire il collegamento come riferimento.
CaldeiraG

1
@CaldeiraG Ho riscritto la mia risposta seguendo il tuo suggerimento. FWIW, la forma della mia risposta originale è stata informata dalla risposta più votata e accettata su questa domanda.
Roman Perepelitsa,

Sembra molto meglio! : p Goditi il ​​tuo soggiorno qui
CaldeiraG
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.