zsh ปรับชิดขวาใน ps1


21

ฉันต้องการพรอมต์ zsh แบบหลายบรรทัดพร้อมส่วนที่ถูกจัดชิดขวาซึ่งจะมีลักษณะดังนี้:

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

ฉันรู้เกี่ยวกับ RPROMPT ใน zsh แต่นั่นมีพรอมต์ที่ถูกจัดชิดตรงข้ามกับพรอมต์ปกติของคุณซึ่งอยู่บนบรรทัดข้อความเดียวกับการพิมพ์ของคุณ

มีวิธีที่จะมีส่วนที่จัดชิดขวาไปที่บรรทัดแรกของพรอมต์คำสั่งหลายบรรทัด? ฉันกำลังมองหาคำสั่งในตัวแปร PS1 ที่ระบุว่า "จัดแนวขวาตอนนี้" หรือตัวแปรที่เป็น PS1 สิ่งที่ RPROMPT คือ PROMPT

ขอบคุณ!

คำตอบ:


12

คุณจะพบคำตอบที่มีรายละเอียดและตัวอย่างที่นี่ แนวคิดคือการเขียนบรรทัดก่อนหน้า PS1 โดยใช้การprecmdโทรกลับการใช้$COLUMNSและคณิตศาสตร์เพื่อคำนวณตำแหน่งของข้อความทางด้านขวาของหน้าจอ ความรู้เกี่ยวกับescape sequencesจะช่วยคุณในการวางตำแหน่งเคอร์เซอร์และการระบายสี

ทางออกก็สามารถที่จะใช้รูปแบบจากOh My ZSH


10

ฉันก็กำลังมองหาสิ่งนี้เช่นกัน สำหรับฉันความจริงที่ว่าprecmd()เส้นที่วาดไม่ได้วาดใหม่เมื่อปรับขนาดหรือเมื่อ^Lใช้ในการล้างหน้าจอเป็นสิ่งที่ทำให้ฉันคัน สิ่งที่ฉันทำตอนนี้คือการใช้ANSI escape sequencesเพื่อเลื่อนเคอร์เซอร์ไปรอบ ๆ แม้ว่าฉันจะสงสัยว่าจะมีวิธีการที่ยอดเยี่ยมกว่าในการเผยแพร่สิ่งเหล่านี้ แต่ก็ใช้ได้กับฉัน:

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

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

เก็บไว้ในใจว่าคู่มือ zshระบุว่า% { ... %} เป็นลำดับหนีตัวอักษรที่ไม่เลื่อนเคอร์เซอร์ ถึงกระนั้นฉันก็ใช้มันเพราะพวกมันยอมเพิกเฉยต่อความยาวของเนื้อหา (ไม่สามารถหาวิธีออกทางหนีที่ย้ายเคอร์เซอร์โดยใช้พวกมัน)


หลังจากเล่นกับมันไปซักพักมันจะเลอะเป็นครั้งคราวและวางเคอร์เซอร์หรือวันที่ผิด ไม่ใช่เรื่องใหญ่อะไรอย่างนั้น สามารถกด Enter เพื่อแก้ไขได้
mpen

3

นี่คือวิธีที่ฉันได้กำหนดค่าสิ่งนี้ในตอนนี้ วิธีนี้ไม่จำเป็นต้องมีการเปลี่ยนลำดับการหลบหนี แต่จะทำให้คุณมีตัวแปรที่แตกต่างกันสองแบบสำหรับการแจ้งเตือนหลัก: PS1ด้วยการระบายสีและการNPS1ไม่มี

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

สังเกตการใช้งานprint -Pสำหรับการขยายพร้อมต์${#variable}สำหรับรับความยาวของสตริงที่จัดเก็บในตัวแปรและprintf "%Nd"สำหรับการเสริมด้านซ้ายด้วยNช่องว่าง ทั้งสองprintและprintfมีในตัวคำสั่งจึงไม่ควรมีการตีประสิทธิภาพ


1

มากำหนดพร้อมท์กับเลย์เอาต์นี้:

top_left              top_right
bottom_left        bottom_right

ในการทำเช่นนี้เราจะต้องมีฟังก์ชั่นที่บอกให้เราทราบถึงจำนวนตัวอักษรของสตริงที่กำหนดเมื่อพิมพ์

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

เราจะต้องใช้ฟังก์ชั่นอื่นที่รับอาร์กิวเมนต์สองตัวและพิมพ์ค่าปรับทั้งหมดด้วยอาร์กิวเมนต์เหล่านี้ที่ด้านตรงข้ามของหน้าจอ

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

ในที่สุดเราสามารถกำหนดฟังก์ชั่นที่ตั้งค่าPROMPTและRPROMPTสั่งให้ ZSH เรียกมันก่อนทุกพรอมต์และตั้งค่าตัวเลือกการขยายพร้อมท์ที่เหมาะสม:

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

สิ่งนี้สร้างพรอมต์ต่อไปนี้:

~/foo/bar                     master
%                             10:51
  • ด้านซ้ายบน: ไดเรกทอรีปัจจุบันสีน้ำเงิน
  • ด้านบนขวา: สาขากรีน Git
  • ด้านล่างซ้าย: #ถ้ารูต%หากไม่ได้; เขียวต่อความสำเร็จ, แดงกับข้อผิดพลาด
  • ด้านล่างขวา: เวลาปัจจุบันสีเหลือง

คุณสามารถค้นหารายละเอียดเพิ่มเติมในการแจ้งเตือนแบบหลายบรรทัด: ส่วนผสมที่ขาดหายไปและรหัสที่สมบูรณ์ในส่วนสำคัญนี้


1
ยินดีต้อนรับสู่ Super User! ในขณะที่สิ่งนี้อาจตอบคำถามในทางทฤษฎีมันก็ควรที่จะรวมส่วนสำคัญของคำตอบที่นี่และให้ลิงค์สำหรับการอ้างอิง
CaldeiraG

1
@CaldeiraG ฉันเขียนคำตอบตามคำแนะนำของคุณอีกครั้ง FWIW รูปร่างของคำตอบเดิมของฉันได้รับแจ้งจากคำตอบที่ได้รับการโหวตสูงสุดและเป็นที่ยอมรับสำหรับคำถามนี้
Roman Perepelitsa

ดูดีขึ้น! : p ขอให้สนุกกับการเข้าพักที่นี่
CaldeiraG
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.