bash-git-prompt icon indicating copy to clipboard operation
bash-git-prompt copied to clipboard

RFE: highlight directory component of git root

Open jlebon opened this issue 9 years ago • 6 comments

It would be great if when inside a git repository, instead of just printing the current directory, it also highlights the part of the path corresponding to the repository's root directory. For example,

14:46 $ cd tmp ✔ /tmp/tmp 14:46 $ git init myrepo Initialized empty Git repository in /tmp/myrepo/.git/ ✔ /tmp 14:47 $ cd myrepo/ ✔ /tmp/myrepo [master|✔] 14:47 $ mkdir subdir ✔ /tmp/myrepo [master|✔] 14:47 $ cd subdir/ ✔ /tmp/myrepo/subdir [master|✔] 14:47 $

(Notice the bolding). That way, we can quickly know (1) which repository we're in, and (2) how deep we are (useful when typing relative paths).

jlebon avatar Sep 14 '15 18:09 jlebon

Should be possible to generate with a custom theme.

If you look at my custom theme from issue #161 you should be able to change the truncated pwd function with something that uses

#Get name of git root
current=$(basename $(git rev-parse --show-toplevel))
#Use sed to highlight first occurrence of git root:
echo $(PWD) |sed "s/${current}/$(tput bold)${current}$(tput sgr0)/g1"

ogr3 avatar Sep 15 '15 11:09 ogr3

A little test theme that does what you want. It might be slow - if there is a way to determine if we are inside a repo we should't do that check again here for instance, but it might be a way forward.

override_git_prompt_colors() {
  GIT_PROMPT_THEME_NAME="Custom"

 #Overrides the prompt_callback function used by bash-git-prompt
 function prompt_callback {
    local repo=$(git rev-parse --show-toplevel 2> /dev/null)
    if [[ -n "$repo" ]]; then
      #Get name of git root
      local current=$(basename $repo)
      #Use sed to highlight first occurrence of git root:
      echo -n ${PWD} |sed "s/${current}/$(tput bold)${current}$(tput sgr0)$(tput setaf 3)/1"
    else
      echo -n ${PWD}
    fi
}

  Time12a="\$(date +%H:%M)"

  GIT_PROMPT_START_USER="_LAST_COMMAND_INDICATOR_ ${Yellow}"
  GIT_PROMPT_START_ROOT="${GIT_PROMPT_START_USER}"
  GIT_PROMPT_END_USER="\n${White}${Time12a}${ResetColor} $ "
  GIT_PROMPT_END_ROOT="\n${White}${Time12a}${ResetColor} # "
}

reload_git_prompt_colors "Custom"

ogr3 avatar Sep 15 '15 18:09 ogr3

@ogr3 Awesome, that works great, thanks!

jlebon avatar Sep 16 '15 01:09 jlebon

But nice idea anyway, I'll integrate this into the default theme

magicmonty avatar Sep 18 '15 08:09 magicmonty

Here is a tweaked prompt_callback which will work also in the case where the repo name appears twice in the path (e.g. for a path like /code/myrepo/myrepo/subdir would highlight the first myrepo, even if the real git root was the second one), and also in the case where the current directory was arrived through a symbolic link:

function prompt_callback {

    # Get the real path to the repo's root                                          
    local repo_realpath=$(git rev-parse --show-toplevel 2> /dev/null)               

    # Are we even in a repo?                                                        
    if [[ -n "$repo_realpath" ]]; then                                              

      # OK, get the real path to the current dir                                    
      local cur_realpath=$(realpath .)                                              

      # Get the name of the repo                                                    
      local repo_name=$(basename $repo_realpath)                                    

      # Calculate the paths before and after the repo name                          
      local diff=$((${#cur_realpath} - ${#repo_realpath}))                          
      local head=${PWD:0:$((${#PWD} - $diff - ${#repo_name}))}
      if [ $diff -gt 0 ]; then
        local tail=${PWD:$((-$diff))}                                                 
      fi

      # Print the full path                                                         
      echo -n "$head$(tput setaf 2)$repo_name$(tput setaf 3)$tail$(tput setaf 0)"
    else                                                                            
      echo -n "\w$(tput setaf 0)"                                                   
    fi                                                                              
}

This is meant to work with my custom theme only (hence the hardcoded tputs), but hopefully you get the idea.

jlebon avatar Sep 24 '15 20:09 jlebon

@jlebon this doesn't work when there is a symlink between git root and current path. For example root is ~/repo and we are at ~/repo/.build/release which is a symlink to ~/repo/.build/x86_64-apple-macosx/release

prompt_dir() {
    # From gitstatus plugin
    local repo_realpath="$VCS_STATUS_WORKDIR"
    if [[ -n "$repo_realpath" ]]; then
      local candidate="$PWD"
      while [[ ! -d "$candidate/.git" && "$candidate" != "/" ]]; do
        candidate="$(dirname "$candidate")"
      done
      if [[ "$(realpath "$candidate")" != "$repo_realpath" ]]; then
        # PWD contains symlink and repository root is not inside PWD
        prompt_segment blue $CURRENT_FG '%~'
        return
      fi
      local repo_name="$(basename "$candidate")"

      local diff=$((${#PWD} - ${#candidate}))
      local head=${PWD:0:$((${#PWD} - $diff - ${#repo_name}))}
      if [ $diff -gt 0 ]; then
        local tail=${PWD:$((-$diff))}
      fi

      local formatted_path="$head%B$repo_name%b$tail"
      # If $HOME is git dir, we want to keep the username bold instead of replacing with tilde,
      # so matching exactly $HOME is never needed here
      prompt_segment blue $CURRENT_FG "${formatted_path/#$HOME\//~/}"
    else
      prompt_segment blue $CURRENT_FG '%~'
    fi
}

If you have any improvement ideas, please let me know

Cyberbeni avatar Oct 27 '20 20:10 Cyberbeni