Как отобразить информацию о состоянии git на правой стороне терминала? - PullRequest
8 голосов
/ 08 октября 2011

Знаете ли вы, можно ли настроить приглашение bash для отображения состояния git / информация о ветке на правой стороне как zsh можно сделать? Этот случайный снимок экрана из интернета показывает, что я имею в виду.

Screen shot showing git status on the right side

Ответы [ 4 ]

10 голосов
/ 09 октября 2011

Попробуйте следующее:

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

Обратите внимание, что вы никогда не получите поведение, точно совпадающее с zsh, только с bash. В приведенном выше случае я вижу следующие различия:

  1. Правая часть приглашения не очищается при запуске команды (событие accept-line в терминах zsh).
  2. Правая часть приглашения будет очищена, если вы введете что-то, а затем нажмите <C-u> или <BS>.
  3. Правая часть подсказки не будет восстановлена, если вы наберете что-то поверх нее, а затем удалите текст.
  4. Правая часть приглашения не исчезнет, ​​если вы наберете что-нибудь поверх него, хотя текст в этой части будет перезаписан.
1 голос
/ 02 мая 2017

Приведенный ниже код создаст подсказку, которая выглядит следующим образом:

bash prompt with git status on right

В bash это нетривиально сделать из-за:

  • Строка режима Readline принимает символы до того, как будет напечатано приглашение , что означает, что решения printf не будут работать в некоторых случаях. Из-за этого:
  • Удаление всех кодов ANSI CSI (например, цветов) для правильного расчета длины печатаемой правой стороны
  • Нужно использовать __git_ps1 для работы с git крайними случаями
  • __git_ps1 только выводит цвет при определенных обстоятельствах и только внутри $PS1
  • Разрешение цвета на выходе __git_ps1 при удалении символов \[ и \] из его вывода (который не может быть вложенным)
  • Завершение всего приглашения 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
1 голос
/ 06 декабря 2011

Сегодня я построил что-то подобное следующим образом.Тщательное тестирование еще не проводилось ...

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
0 голосов
/ 08 октября 2011

Одним из способов будет использование 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")"
...