ps1'de zsh sağa yasla


21

Ben böyle bir şey görünecek, sağ alined bir parçası ile çok satırlı bir zsh istemi istiyorum:

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

RPHMPT'yi zsh olarak biliyorum, ancak normal isteminizin karşısında sağa hizalanmış bir istemi var, bu da yazınızla aynı metin satırında.

Çok satırlı komut isteminin ilk satırına sağa hizalanmış bir bölümün olmasının bir yolu var mı? Ben ya 'şimdi doğru hizala' yazan PS1 değişkeni bir yönerge ya da PS1 için RPROMPT İSTEM ne olduğunu bir değişken arıyorum.

Teşekkürler!

Yanıtlar:


12

Burada ayrıntılı bir cevap ve bir örnek bulacaksınız . Fikir, ekranın sağ tarafındaki metnin konumunu hesaplamak için precmdgeri arama, kullanım $COLUMNSve biraz matematik kullanarak PS1'den önce satırı yazmaktır . Bilgi kaçış dizileri de imleç konumlandırma ve renklendirme ile size yardımcı olacaktır.

Başka bir çözüm Oh My ZSH'den bir tema kullanmak olabilir .


10

Ben de bunu arıyordum. Benim için, precmd()çizilen çizgilerin yeniden boyutlandırmada veya ^Lekranı temizlemek için ne zaman kullanıldıkları bana kaşıntıyı koruyan bir şeydi. Şu anda yaptığım şey , imleci biraz hareket ettirmek için ANSI kaçış dizileri kullanmak . Onları yayınlamanın daha zarif bir yolu olduğundan şüphelenmeme rağmen, bu benim için çalışıyor:

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

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

Unutmayın o zsh manuel % {...%} literal kaçış dizileri için olduğunu devletler imleci hareket etmiyor . Buna rağmen, onları kullanıyorum çünkü içeriğinin uzunluğunu görmezden gelmelerine izin veriyorlar (imleci onları kullanarak hareket ettiren kaçışın nasıl yapılacağını anlayamadılar)


Bir süre bununla oynadıktan sonra, ara sıra karışır ve imleci veya tarihi yanlış satıra koyar. Gerçi böyle büyük bir anlaşma değil; düzeltmek için sadece enter tuşuna basabilirsiniz.
mpen

3

İşte bu şeyi şu anda yapılandırdım. Bu yaklaşım herhangi bir kaçış dizisi manipülasyonu gerektirmez, ancak birincil istem için iki farklı değişkene sahip olmanızı sağlar: PS1renklendirme ve renklendirme NPS1olmadan.

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

Kullanımını Not print -Pistemi genişlemesi için ${#variable}değişkeninde saklanan dize uzunluğunu almak için, ve printf "%Nd"sol taraftaki dolgu için Nboşluklar. Her ikisi de printve printfyerleşik komutlardır, bu yüzden performans isabeti olmamalıdır.


1

Bu düzen ile istem tanımlayalım:

top_left              top_right
bottom_left        bottom_right

Bunu yapmak için, bize belirli bir dizenin yazdırıldığında kaç karakter alacağını söyleyen bir fonksiyona ihtiyacımız olacak.

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

Ekranın karşı taraflarında iki argüman alan ve bu argümanlarla tam para cezası yazan başka bir işleve ihtiyacımız olacak.

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

Sonunda setleri bir işlevi tanımlayabilir PROMPTve RPROMPT, talimat ZSH her istemi, ve set uygun istemi genişleme seçenekleri önce aramak:

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

Bu, aşağıdaki istemi üretir:

~/foo/bar                     master
%                             10:51
  • Sol üst: Mavi geçerli dizin.
  • Sağ üst: Yeşil Git dalı.
  • Sol alttaki: #eğer kökse, %değilse; başarı yeşil, hata kırmızı.
  • Sağ alttaki: Sarı geçerli saat.

Çok satırlı bilgi isteminde ek ayrıntılar bulabilirsiniz : Bu özette eksik bileşen ve tam kod .


1
Süper Kullanıcıya Hoş Geldiniz! Bu teorik olarak soruyu cevaplayabilirken, cevabın temel kısımlarını buraya dahil etmek ve referans için bağlantı sağlamak tercih edilir.
CaldeiraG

1
@CaldeiraG Önerinizi izleyerek cevabımı yeniden yazdım. FWIW, orijinal cevabımın şekli, bu soruya en çok oy verilen ve kabul edilen cevap tarafından bildirildi.
Roman Perepelitsa

Daha iyi görünüyor! : p Burada kaldınız
CaldeiraG
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.