web-dev-qa-db-ja.com

zshはps1で右寄せします

右に並んだ部分がある複数行のzshプロンプトが欲しいのですが、次のようになります:

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

私はzshのRPROMPTについて知っていますが、通常のプロンプトとは逆に右揃えのプロンプトがあります。これは、入力と同じテキスト行にあります。

複数行のコマンドプロンプトの最初の行に右揃えの部分を配置する方法はありますか? PS1変数で「今すぐ整列」と表示されているディレクティブか、PS1に対してRPROMPTがプロンプトを表示する変数を探しています。

ありがとう!

21
So8res

詳細な回答と例 here があります。アイデアは、precmdコールバックを使用して、PS1の前に行を書き込み、$COLUMNSを使用し、少し計算して、画面の右側のテキストの位置を計算することです。 エスケープシーケンス の知識も、カーソルの配置と色付けに役立ちます。

別の解決策は、 Oh My ZSH のテーマを使用することです。

13

私もこれを探していました。私にとって、precmd()で描画された線がサイズ変更時に再描画されない、または^Lを使用して画面をクリアすると、かゆみが続いた。私が今していることは、 ANSIエスケープシーケンス を使用してカーソルを少し動かしています。それらを発行するよりエレガントな方法があると思いますが、これは私のために働いています:

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

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

zsh manual は、%{...%}はカーソルを動かさないリテラルエスケープシーケンス用であると述べていることに注意してください。それでも、コンテンツの長さを無視できるので、私はそれらを使用しています(ただし、それらを使用してカーソルを移動するエスケープを発行する方法を理解できませんでした)

10
ferhtgoldaraz

これが私が今このことをどのように構成したかです。このアプローチでは、エスケープシーケンスの操作は必要ありませんが、プライマリプロンプトに2つの異なる変数があります。色付きの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}Nスペースを使用した左側のパディングにはprintf "%Nd"を使用していることに注意してください。 printprintfはどちらも組み込みコマンドであるため、パフォーマンスに影響はありません。

3
firegurafiku

このレイアウトでプロンプトを定義しましょう:

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
}

2つの引数を取り、画面の反対側にこれらの引数を使用して完全な罰金を出力する別の関数が必要になります。

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

最後に、PromptRPROMPTを設定する関数を定義し、すべてのプロンプトの前にそれを呼び出すように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
  • 左上:青い現在のディレクトリ。
  • 右上:Green Gitブランチ。
  • 左下: #ルートの場合、%そうでない場合;成功した場合は緑、エラーの場合は赤。
  • 右下:黄色の現在時刻。

追加の詳細は 複数行のプロンプト:不足している成分 にあり、完全なコードは この要点 にあります。

1