PS1의 zsh 오른쪽 정렬


21

오른쪽 줄이 그어진 부분을 가진 여러 줄 zsh 프롬프트를 원합니다.

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

zsh의 RPROMPT에 대해 알고 있지만 일반 프롬프트와는 오른쪽으로 정렬 된 프롬프트가 있으며 입력과 동일한 텍스트 줄에 있습니다.

여러 줄 명령 프롬프트의 첫 줄에 오른쪽 정렬 부분이있는 방법이 있습니까? PS1 변수에서 'right align now'라는 지시문이나 RPROMPT가 PROMPT에 대한 PS1에 대한 변수를 찾고 있습니다.

감사!

답변:



10

나도 이것을 찾고 있었다. 나를 위해, precmd()그려진 선이 크기를 조정할 때 다시 그려지지 않거나 ^L화면을 지우는 데 사용될 때 가려움증이 계속되었습니다. 내가 지금하고있는 일은 ANSI 이스케이프 시퀀스 를 사용 하여 커서를 약간 움직입니다. 더 우아한 방법으로 문제를 해결할 수있을 것으로 생각되지만이 방법은 저에게 효과적입니다.

_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하십시오. printprintf내장 명령 모두 이므로 성능 저하가 없어야합니다.


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하고 RPROMPTZSH가 모든 프롬프트 전에 호출하도록 지시하고 적절한 프롬프트 확장 옵션 을 설정하는 함수를 정의 할 수 있습니다.

# 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
  • 왼쪽 위 : 파란색 현재 디렉토리.
  • 오른쪽 상단 : 녹색 힘내 지점.
  • 왼쪽 아래 : #루트 인 %경우 그렇지 않은 경우; 성공시 녹색, 오류시 적색
  • 오른쪽 아래 : 노란색 현재 시간.

멀티 라인 프롬프트 에서 추가 세부 사항을 찾을 수 있습니다 : 이 요점 에서 누락 된 성분 및 완전한 코드 .


1
슈퍼 유저에 오신 것을 환영합니다! 이 이론적으로 질문에 대답 할 수 있습니다 동안, 바람직 할 것이다 여기에 대한 대답의 본질적인 부분을 포함하고 참조 할 수 있도록 링크를 제공합니다.
CaldeiraG

1
@CaldeiraG 나는 당신의 제안에 따라 대답을 다시 썼습니다. FWIW, 내 원래 답변의 형태는이 질문에 대해 가장 많이 투표되고 승인 된 답변으로 알려졌습니다.
로마 Perepelitsa

더 좋아 보인다! : p 여기 머 무르십시오
CaldeiraG
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.