如何在终端右侧显示git状态信息?

时间:2011-10-08 15:44:05

标签: git bash zsh command-prompt

您知道是否可以配置 bash提示以在右侧显示 git status / 分支信息 < em> zsh 可以吗?这个从互联网上随机拍摄的屏幕显示了我的意思。

Screen shot showing git status on the right side

4 个答案:

答案 0 :(得分:10)

尝试以下方法:

PS1='$(printf "%*s\r%s" $(( COLUMNS-1 )) "[$(git branch 2>/dev/null | grep '^*' | sed s/..//)] $(date +%H:%M:%S)" "heipei@wavefront:$PWD$ ")'

请注意,您永远不会获得仅与bash完全匹配的行为。在上面的例子中,我看到以下不同之处:

  1. 在运行命令({z}的accept-line事件)时,不会清除提示的右侧部分。
  2. 如果您输入内容,则会清除提示的右侧部分,然后按<C-u><BS>
  3. 如果在其上键入内容然后删除文本,则不会恢复提示的右侧部分。
  4. 如果您在其上键入内容,则提示的右侧部分不会消失,但此部分中的文字将被覆盖。

答案 1 :(得分:1)

今天我用以下方式构建了类似的东西。还没有进行彻底的测试......

preprompt() {
  rc=$?
  c=31
  [ $rc -eq 0 ] && c=32

  PS1="\[$(color $c)\]$rc\[$(color 0)\] \t \w \$ "
  # right "prompt"
  # We cannot use $COLUMNS here, since in new shells the first prompt
  # will get garbled then. Seems like the correct value of COLUMNS is
  # in the shell init.
  printf "%`tput cols`s`tput cr`" "${USER}@${HOST}"
}

PROMPT_COMMAND=preprompt

答案 2 :(得分:1)

下面的代码将创建一个如下所示的提示:

bash prompt with git status on right

由于:

bash执行此操作是非常重要的
  • Readline mode string takes up characters before the prompt is printed,意味着printf解决方案在某些情况下不起作用。因为这个:
  • 删除所有ANSI CSI codes(例如颜色)以正确计算可打印的右侧提示的长度
  • 需要使用__git_ps1来处理git边缘情况
  • __git_ps1仅在某些情况下输出颜色,仅在$PS1
  • 内输出
  • 在从__git_ps1输出中删除\[\]个字符时不允许使用颜色(<{li}>
  • \[\]中包含整个RHS提示,以确保在浏览/编辑/完成命令时提示不做奇怪的事情
#!/bin/bash
# _options=$(shopt -op); set -exu # Save and set shell options for testing
##################
# Set the prompt #    Sourced from .bashrc
##################

# Select git info displayed, see /usr/lib/git-core/git-sh-prompt for more
export GIT_PS1_SHOWCOLORHINTS=1           # Make pretty colours inside $PS1
export GIT_PS1_SHOWDIRTYSTATE=1           # '*'=unstaged, '+'=staged
export GIT_PS1_SHOWSTASHSTATE=1           # '$'=stashed
export GIT_PS1_SHOWUNTRACKEDFILES=1       # '%'=untracked
export GIT_PS1_SHOWUPSTREAM="verbose"     # 'u='=no difference, 'u+1'=ahead by 1 commit
export GIT_PS1_STATESEPARATOR=''          # No space between branch and index status
export GIT_PS1_DESCRIBE_STYLE="describe"  # Detached HEAD style:
#  describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
#  contains      relative to newer annotated tag (v1.6.3.2~35)
#  branch        relative to newer tag or branch (master~4)
#  default       exactly eatching tag


# Sets prompt like:
# ravi@boxy:~/prj/sample_app[exit]$                   master*% u= | 30 Apr 22:27
_set_bash_prompt() {
  # Set left hand side of the prompt
  PS1="\u@\h:\w\$ "

  #
  # Git status
  #

  # Save current state of user shopt settings promptvars and extglob
  local user_shopt
  user_shopt=$(shopt -p promptvars extglob)
  # __git_ps1 usually returns literal text "${__git_ps1_branch_name}" rather
  # than the contained branch name, eg "master". This prevents calculating
  # the length of the printable characers in the RHS string (used to move the
  # cursor that many columns left from the terminal's right edge.) However if
  # "shopt promptvars" is unset, __git_ps1 it will include the dereferenced
  # branch name instead.
  shopt -qu promptvars
  # extglob is required for the ${variable//@(pattern)/} replacements
  shopt -qs extglob

  # Allow disabling git status and no error if __git_ps1 undefined
  if [[ ! -v _disable_git_prompt && $(type -t __git_ps1 2>/dev/null) == function ]]; then
    # __git_ps1 will only make pretty colours inside $PS1
    local old_PS1=$PS1
    __git_ps1 "" "" "%s" # force colour; no default round bracket (decorations)

    # Strip "\[" and "\[": non-printable character markers. __git_ps1 outputs
    # them however the whole of the RHS prompt needs to be included in these
    # markers, and they can't be nested.
    git=${PS1//@(\\@(\[|\]))/}
    PS1=$old_PS1
  fi

  #
  # Right hand side of prompt
  #
  local rhs="" # String to be printed on the right hand side of terminal

  # Create a string like: "25 Apr 13:15"
  local date_time
  printf -v date_time "%(%e %b %H:%M)T" -1 # -1 is current time

  # Format the RHS prompt
  [[ -n $git ]] && rhs="$git | " #"
  rhs+="\e[0;1;31m${date_time}"

  # Strip ANSI CSI commands (eg colours) to enble counting the length of
  # printable characters, giving offset of cursor from terminal RHS edge (from
  # https://www.commandlinefu.com/commands/view/12043/remove-color-special-escape-ansi-codes-from-text-with-sed)
  # Neither bash not sed support lookbehind zero-length assertions, so it's not
  # possible to ignore "\\e", (ie a literal '\' followed by a literal 'e'), yet
  # still remove "\e" (ie ESC)
  local rhs_printable=${rhs//@(\\@(\[|]|[Ee]\[*([0-9;])[a-zA-Z]))/}
  # or, in using sed (but requires exec):
  # local rhs_printable=$(sed -e 's,\\[][]\|\\[Ee]\[\([0-9;]\)*[A-Za-z],,g' <<< "$rhs")

  # Reference: https://en.wikipedia.org/wiki/ANSI_escape_code
  local Save='\e[s' # Save cursor position
  local Rest='\e[u' # Restore cursor to save point

  # Save cursor position, jump to (right hand edge minus N columns) where N is
  # the length of the printable RHS string. Print the RHS string, then return
  # to the saved position and print the LHS prompt.

  # Note: "\[" and "\]" are used so that bash can calculate the number of
  # printed characters so that the prompt doesn't do strange things when
  # command line editing/browsing/completion. Ensure that these are not nested.
  PS1="\[\e[0m${Save}\e[$((COLUMNS - ${#rhs_printable}))G${rhs}${Rest}\]${PS1}"

  eval "$user_shopt"
}

# eval "$_options"; unset _options # Restore previous shell options from line 2

答案 3 :(得分:0)

一种方法是使用tput来计算终端的,并减去要左右打印的字符数,然后使用该数字作为左右文本之间的空格数。使用printf构建该行。

快速示例:

left="[${status}]\u@\h:\w\$ "
right="$(git symbolic-ref HEAD) $(date +%T)"
spaces="$(( $(tput cols) - ${#left} - ${#right} ))"
export PS1="$(printf "%s%${spaces}s\n" "$left" "$right")"