2

I use a custom PS1 to display more relevant information in my terminal, such as if I'm in a git directory and if it's clean or needs to commit changes. However, sometimes when I'm arrowing through commands, part of the terminal line disappears:

@ ~/tests/testing [tests] > grunt
# up arrow, down arrow
@ ~/tests/testing [t

Essentially, the ests] > gets cut off and I'm left with just the [t.

Is there any particular reason why part of the line is getting cut off with this PS1 config?

Here's some additional info:

My TERM env var is xterm-256color. Here's my .bash_profile:

red='\033[0;31m'
yellow='\033[0;32m'
orange='\033[0;33m'
blue='\033[0;34m'
pink='\033[0;35m'
NC='\033[0m'

function is_git {
  if git rev-parse --is-inside-work-tree 2>/dev/null; then
    return 1
  else
    return 0
  fi
}

function stuff {
  if [ $(is_git) ]; then
    git_dir="$(git rev-parse --git-dir 2>/dev/null)"

    if [ -z "$(ls -A ${git_dir}/refs/heads )" ]; then
      echo -en " [${orange}init${NC}]"
      return
    fi

    echo -n " ["
    if [ $(git status --porcelain 2>/dev/null| wc -l | tr -d ' ') -ne 0 ]; then
      echo -en "${red}"
    else
      echo -en "${blue}"
    fi
    echo -en "$(git rev-parse --abbrev-ref HEAD)${NC}]"
  fi
}

export PS1="@ \w\[\$(stuff)\]\[\$(tput sgr0)\] > "
josh
  • 153
  • 5
  • Would you please add your terminal type and `TERM` environment variable? And is `stuff` really exactly what's in your PS1, or is that a placeholder for `pwd` or something else?Thanks! – cxw Jun 10 '15 at 14:29
  • Updated with my `.bash_profile` – josh Jun 10 '15 at 14:33
  • What happens if you remove the `tput`? – cxw Jun 10 '15 at 14:49
  • I removed it but it still gets truncated – josh Jun 10 '15 at 14:51
  • In `stuff`, the stderr of `ls` is not sent to `/dev/null`. Don't see how that's relevant, but maybe give it a shot. – cxw Jun 10 '15 at 14:56
  • Where is `ls` going to `/dev/null`? I send a couple of the git commands to null but not `ls`. Those `/dev/null` are necessary or else the `git` commands will give me an error when they aren't in a git directory – josh Jun 10 '15 at 14:59
  • `if [ -z "$(ls -A ${git_dir}/refs/heads )" ]; then` -> `if [ -z "$(ls -A ${git_dir}/refs/heads 2>/dev/null )" ]; then` – cxw Jun 10 '15 at 15:06

2 Answers2

2

@i_am_root's suggestion to put the \[ and \] inside the definition of red and the like is a good one. However, per this, bash only processes \[ and \] in PS1, not in text included in PS1 by $(). Therefore, use \001 and \002 (or \x01 and \x02) inside red and the like instead of \[ and \].

Note: Per this answer, only the escape codes should be in the \001 and \002. The text that will be visible to the user should be outside the \001 and \002 so that bash knows it takes up space on the screen and can account for that when redrawing.

cxw
  • 1,689
  • 1
  • 16
  • 27
  • Hmm... is there another way to handle it than splitting up the text from the formatting/color? Right now, `[tests]` appears as normal color `[]` and red `tests`, which means I'd have to split up the text to happen before and after the formatting. If I keep all of the text together, the entire text would appear red. – josh Jun 10 '15 at 15:18
  • Using the `\001` and `\002` before and after the color codes fixed it! If you edit your answer to reflect that (since I got the info from that answer you linked, and since I didn't have to edit the `stuff` method) I'll accept your answer. – josh Jun 10 '15 at 15:38
  • Edited - glad it worked! Thanks also to @i_am_root for putting me on the right track! – cxw Jun 10 '15 at 17:47
1

Bash color codes, escaping characters, assignments, and such get confusing quickly.

Try this code sample which replaces the echo commands by adding to the PS1 variable.

red='\[\033[0;31m\]'
yellow='\[\033[0;32m\]'
orange='\[\033[0;33m\]'
blue='\[\033[0;34m\]'
pink='\[\033[0;35m\]'
NC='\[\033[0m\]'

export PS1="@ \w"

function is_git {
  if git rev-parse --is-inside-work-tree 2>/dev/null; then
    return 1
  else
    return 0
  fi
}

function stuff {
  if [ $(is_git) ]; then
    git_dir="$(git rev-parse --git-dir 2>/dev/null)"

    if [ -z "$(ls -A ${git_dir}/refs/heads )" ]; then
      PS1="${PS1} [${orange}init${NC}]"
      return
    fi

    PS1="$PS1 ["
    if [ $(git status --porcelain 2>/dev/null| wc -l | tr -d ' ') -ne 0 ]; then
      PS1="${PS1}${red}"
    else
      PS1="${PS1}${blue}"
    fi
    PS1="${PS1}$(git rev-parse --abbrev-ref HEAD)${NC}]"
  fi
}

stuff
PS1="${PS1}$(tput sgr0) > "
i_am_root
  • 323
  • 3
  • 19
  • That causes my output to become this: `@ ~/tests/testing [\[\]tests\[\]] >` – josh Jun 10 '15 at 14:58
  • I tried removing the `e` from `echo -en` but it doesn't escape the color codes properly, so I end up with `[\033[0;31mtests\033[0m]` – josh Jun 10 '15 at 15:27
  • See edited question. Does removing `echo` and adding to `PS1` do the trick? – i_am_root Jun 10 '15 at 16:09