zsh benar-benar dalam ps1

21

Saya ingin multi-line zsh prompt dengan bagian alined yang tepat, yang akan terlihat seperti ini:

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

Saya tahu tentang RPROMPT di zsh, tapi itu memiliki prompt rata kanan berlawanan dengan prompt normal Anda, yang berada di baris teks yang sama dengan mengetik Anda.

Apakah ada cara untuk memiliki bagian rata kanan ke baris pertama dari command prompt multi-baris? Saya sedang mencari arahan dalam variabel PS1 yang mengatakan 'benar menyelaraskan sekarang' atau variabel yang untuk PS1 apa RPROMPT adalah untuk PROMPT.

Terima kasih!

So8res
sumber

Jawaban:

12

Anda akan menemukan jawaban terperinci dan contoh di sini . Idenya adalah untuk menulis baris sebelum PS1 menggunakan precmdcallback, gunakan $COLUMNS, dan sedikit matematika untuk menghitung posisi teks di sisi kanan layar. Pengetahuan tentang urutan pelarian juga akan membantu Anda dengan posisi kursor dan pewarnaan.

Solusi lain dapat menggunakan tema dari Oh My ZSH .

Pablo Castellazzi
sumber
10

Saya sudah mencari ini juga. Bagi saya, fakta bahwa precmd()garis yang ditarik tidak menggambar ulang pada ukuran atau ketika ^Ldigunakan untuk menghapus layar adalah sesuatu yang membuat saya gatal. Yang saya lakukan sekarang adalah menggunakan urutan pelarian ANSI untuk memindahkan kursor sedikit. Meskipun saya curiga ada cara yang lebih elegan untuk mengeluarkannya, ini bekerja untuk saya:

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

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

Ingatlah bahwa manual zsh menyatakan bahwa% {...%} adalah untuk urutan pelepasan literal yang tidak menggerakkan kursor . Meski begitu, saya menggunakan mereka karena mereka memungkinkan untuk mengabaikan panjang kontennya (tidak bisa menemukan cara untuk mengeluarkan pelarian yang menggerakkan kursor menggunakan mereka meskipun)

ferhtgoldaraz
sumber
Setelah bermain-main dengan ini selama beberapa waktu, itu kadang-kadang kacau dan menempatkan kursor atau tanggal pada baris yang salah. Bukan masalah besar; cukup tekan enter untuk memperbaikinya.
mpen
3

Inilah cara saya mengkonfigurasi hal ini sekarang. Pendekatan ini tidak memerlukan manipulasi escape-sequence, tetapi akan membuat Anda memiliki dua variabel berbeda untuk prompt primer: PS1dengan pewarnaan dan NPS1tanpa.

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

Perhatikan penggunaan print -Puntuk ekspansi cepat, ${#variable}untuk mendapatkan panjang string yang disimpan dalam variabel, dan printf "%Nd"untuk bantalan kiri dengan Nspasi. Keduanya printdan printfmerupakan perintah bawaan, jadi seharusnya tidak ada kinerja yang hit.

firegurafiku
sumber
1

Mari kita tentukan prompt dengan tata letak ini:

top_left              top_right
bottom_left        bottom_right

Untuk melakukan ini, kita akan memerlukan fungsi yang memberitahu kita berapa banyak karakter yang diberikan string ketika dicetak.

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

Kita akan membutuhkan fungsi lain yang mengambil dua argumen dan mencetak denda penuh dengan argumen ini di sisi yang berlawanan dari layar.

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

Akhirnya kita dapat mendefinisikan fungsi yang mengatur PROMPTdan RPROMPT, memerintahkan ZSH untuk memanggilnya sebelum setiap prompt, dan mengatur opsi ekspansi prompt yang sesuai:

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

Ini menghasilkan prompt berikut:

~/foo/bar                     master
%                             10:51
  • Kiri atas: Direktori saat ini biru.
  • Kanan atas: Cabang Green Git.
  • Kiri bawah: #jika root, %jika tidak; hijau saat sukses, merah kesalahan.
  • Kanan bawah: Waktu saat kuning.

Anda dapat menemukan detail tambahan di Multi-line prompt: Bahan yang hilang dan kode lengkap dalam inti ini .

Roman Perepelitsa
sumber
1
Selamat Datang di Pengguna Super! Sementara ini secara teoritis dapat menjawab pertanyaan, akan lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini, dan menyediakan tautan untuk referensi.
CaldeiraG
1
@ CaldeiraG Saya menulis ulang jawaban saya mengikuti saran Anda. FWIW, bentuk jawaban asli saya diinformasikan oleh jawaban yang paling banyak dipilih dan diterima pada pertanyaan ini.
Roman Perepelitsa
Terlihat jauh lebih baik! : p Nikmati masa tinggal Anda di sini
CaldeiraG