Custom Oh My Zsh theme: long prompts disappear / cut off - shell

I had a go at making my own Oh My Zsh theme earlier. All is well, except when I type long lines in the prompt (any longer than the line seen below), the line disappears. The line re-appears if I resize the window, however.
Is there something in my theme that is causing this to happen?
If I type an additional character and then erase one, the cursor appears at the edge of the window.
You can view the code for the theme here. Here’s the bit I think we are concerned with:
# Build the prompt
PROMPT='
' # Newline
PROMPT+='${style_user}%n' # Username
PROMPT+='${style_chars}#' # #
PROMPT+='${style_host}%m' # Host
PROMPT+='${style_chars}: ' # :
PROMPT+='${style_path}%c ' # Working directory
PROMPT+='$(git_custom_status)' # Git details
PROMPT+='
' # Newline
PROMPT+='${style_chars}\$${RESET} '

Incidentally, your link is broken, highlighting one of the issues with posting a link to code instead of code itself - any future viewers of your question can't get a full picture.
I think your problem is that the 'color' characters you use should be escaped in a pair of %{...%}:
%{...%}
Include a string as a literal escape sequence. The string within the braces
should not change the cursor position. Brace pairs can nest.
Using your latest commit on github, I don't see this issue - did you fix it? However, I'm seeing some issues with cursor placement and line-drawing, particularly with TAB. When pressing TAB, the cursor is moved up one line:
Pressed TAB here.
Pressed TAB here.
The PROMPT is being re-drawn 'up' one line every time. This is fixed by encapsulating the color codes within the %{...%}:
# Solarized Dark colour scheme
BOLD="%{$(tput bold)%}"
RESET="%{$(tput sgr0)%}"
SOLAR_YELLOW="%{$(tput setaf 136)%}"
SOLAR_ORANGE="%{$(tput setaf 166)%}"
SOLAR_RED="%{$(tput setaf 124)%}"
SOLAR_MAGENTA="%{$(tput setaf 125)%}"
SOLAR_VIOLET="%{$(tput setaf 61)%}"
SOLAR_BLUE="%{$(tput setaf 33)%}"
SOLAR_CYAN="%{$(tput setaf 37)%}"
SOLAR_GREEN="%{$(tput setaf 64)%}"
SOLAR_WHITE="%{$(tput setaf 254)%}"
I'm not 100% sure without the original ~/.zshrc, but this should improve your prompt a little. :)
Apart from the orange, you can also use a terminal-based Solarized profile and the zsh colors, which might be more portable. I couldn't get the orange right without tput, though.
#autoload colors && colors
#SOLAR_YELLOW="%{$fg[yellow]%}"
#SOLAR_ORANGE="%{$(tput setaf 166)%}"
#SOLAR_RED="%{$fg[red]%}"
#SOLAR_MAGENTA="%{$fg[magenta]%}"
#SOLAR_VIOLET="%{$fg_bold[magenta]%}"
#SOLAR_BLUE="%{$fg[blue]%}"
#SOLAR_CYAN="%{$fg[cyan]%}"
#SOLAR_GREEN="%{$fg[green]%}"
#SOLAR_WHITE="%{$fg[white]%}"

Related

How Do I Display My Git Branch In My Terminal & Have It Automatically Update?

I am trying to have my terminal display my current/active working branch. Everything works as I intend besides the branch update, It is static. When I call ~/.bashrc or ~/.bash_profile it will update my active branch.
# Pre-set colored text.
orange=$(tput setaf 166); # Orange Text Call
yellow=$(tput setaf 228); # Yellow Text Call
red=$(tput setaf 001); # Red Text Call
blue=$(tput setaf 004); # Blue Text Call
pink=$(tput setaf 005); # Pink Text Call
teal=$(tput setaf 006); # Teal Text Call
green=$(tput setaf 71); # Green Text Call
white=$(tput setaf 15); # White Text Call
bold=$(tput bold); # Bold Text Call
reset=$(tput sgr0); # Reset Call
# Display current git branch in terminal.
git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}
PS1="\[${bold}\]\n"; # Display terminal text in BOLD & fresh line.
PS1+="\[${blue}\] Branch:" # Display "Branch:" text.
PS1+="\[${orange}\]$(git_branch) " # Call git_branch to be displayed.
PS1+="\[${blue}\]User:" # Display "User:" text.
PS1+="\[${orange}\]\u "; # Display active user.
PS1+="\[${blue}\]Host:"; # Display "Host:" text.
PS1+="\[${orange}\]\h "; # Display active host.
PS1+="\[${blue}\]Directory:"; # Display "Directory:" text.
PS1+="\[${orange}\]\W "; # Display working directory path.
PS1+="\n"; # Create a new line to write on.
PS1+="\[${white}\]-> \[${reset}\]"; # Display "$" & Color reset.
export PS1; # Export file to be used in terminal (source ~/.bashrc).
Your mistake is here:
PS1+="\[${orange}\]$(git_branch) " # Call git_branch to be displayed.
Stuff inside double quotes is evaluated immediately, so ${orange} is expanded to whatever the variable orange expands to, and $(git_branch) is expanded to whatever git_branch produces on standard output.
There are many ways to solve this. One is to use single quotes, which prevent evaluation at this time. PS1 will thus contain a literal ${orange} and literal $(git_branch). That will run the git_branch command at the right time, but depends on the variable $orange still being set at that time. Another is to replace $(git_branch) with \$(git_branch): when evaluated inside double quotes, the result is the literal text $(git_branch), and when $PS1 is re-evaluated later, before each command, $(git_branch) gets its chance.
Note that the \[...\] parts of prompts are tricky. Bash internally changes these to $'\001' and $'\002', and depending on where and when you evaluate parts of the prompt string, you may need to use the internal codes. This isn't really documented anywhere and relying on it might not be wise (but I did that in my own PS1 settings).

GNU Screen tab titles all just 'zsh'

OK, so I want to start by first explaining my setup. I have a windows desktop at home, and I am SSH'ing into an Amazon EC2 instance (via PuTTY) running Amazon Linux. I have zsh as my default shell, and oh-my-zsh installed as well. This "cloud developer desktop" model works well for me, but I am having one problem that I have poured more time into than I care to admit: GNU screen only shows 'zsh' as the title of every tab. This is despite using oh-my-zsh's screen plugin (which I think isn't doing anything). Anyone able to help me out? I'd love to have something more descriptive in the tab, perhaps just the last x characters of the current directory (or an open file name if one is open in vim).
Like many screen users, I've had what I'm asking for before, but on a new rig now and don't fully understand everything in my .screenrc:
# Many settings from https://gist.github.com/azitabh/7427682 and
# https://gist.github.com/joaopizani/2718397 and
# https://gist.github.com/ChrisWills/1337178
# Allow bold colors - necessary for some reason
attrcolor b ".I"
# Tell screen how to set colors. AB = background, AF=foreground
termcapinfo xterm "Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm"
# Erase background with current bg color
defbce "on"
# Cache 30000 lines for scroll back
defscrollback 30000
# add tabs on bottom
caption always "%{= bb}%{+b w}%n %t %h %=%l %H %c"
# Very nice tabbed colored hardstatus line
#hardstatus string '%{= Kd} %{= Kd}%-w%{= Kr}[%{= KW}%n %t%{= Kr}]%{= Kd}%+w %-= %{KG} %H%{KW}|%{KY}%101`%{KW}|%D %M %d %Y%{= Kc} %C%A%{-}'
hardstatus alwayslastline "%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<"
#Remove vim buffer from scrollback history after quitting
altscreen on
# special xterm hardstatus: use the window title.
#termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]2;screen\007'
#termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]1;screen\007'
# Enable 256 color term
term xterm-256color
# Enables use of shift-PgUp and shift-PgDn
termcapinfo xterm|xterms|xs|rxvt ti#:te#
# tell screen that xterm can switch to dark background and has function keys.
termcapinfo xterm 'VR=\E[?5h:VN=\E[?5l'
termcapinfo xterm 'k1=\E[11~:k2=\E[12~:k3=\E[13~:k4=\E[14~'
termcapinfo xterm 'kh=\E[1~:kI=\E[2~:kD=\E[3~:kH=\E[4~:kP=\E[H:kN=\E[6~'
# window numbering starts at 1 not 0
bind c screen 1
bind 0 select 10
screen 1
#allow mouse scrolling in screen
termcapinfo xterm* ti#:te#
# Automatically detach on hangup.
autodetach on
I also tried adding this to my .zshrc, and it helps, but isn't quite what I want, as if you run ls, now your title is ls. Ie, not very informative. But maybe editing here is actually the right way to go:
# So screen tabs receive running process title
# preexec () {
# echo -ne "\ek${1%% *}\e\\"
# }
Thanks in advance for your help!
Answering my own question a bit here:
Replacing the line in the preexec () function above with this helps:
echo -ne "\ek$(pwd)\e\\"
Would still be best to only grab the characters from the x-to-last '/' to the end though, replacing the initial string with '...'

change color of prompt in bash profile

I am trying to change the color of the prompt in my terminal to green text for the user at the start and white ~
Currently my .bash_profile file is configured the following way to provide a yellow color for the user name and a pink color for the ~
PS1='\e[33;1m\u#\h: \e[31m\W\e[0m\$'
Does anyone know how to modify the above to change to the colors to green and white?
Thanks!
PS1='\e[32;1m\u#\h: \e[37m\W\e[0m\$'
The numbers after the [ are the color codes. See this reference.
You are looking to change the ANSI escape sequences, specifically the colors.
\e[...m takes a semicolon-separate list of codes to manipulate how the following text is displayed. 33 represents yellow foreground text, 1 represents bold text, 31 represents red foreground text, and 0 resets all values (foreground and background colors, styles, etc) to their terminal defaults.
# Make text yellow and bold, then make it red (keeping it bold)
# and finally restore the default
PS1='\e[33;1m\u#\h: \e[31m\W\e[0m\$'
To use green/white instead of yellow/red, change 33 to 32 and 31 to 37. Also, be sure to enclose characters that do not take up any space on screen inside \[...\] so that the shell can properly determine the length of your prompt.
PS1='\[\e[32;1m\]\u#\h: \[\e[37m\]\W\[\e[0m\]\$'
This assumes that your terminal understands ANSI escape sequences; a more portable method is to use tput to output the codes your actual terminal uses:
PS1='\[$(tput bold; tput setaf 2)\u#\h: \[$(tput setaf y)\]\W$(tput sgr0)\$ '
zsh, incidentally, makes this much easier; it has built-in escapes for changing the color in a terminal-independent way:
# 1. Everything between %B and %b is in bold
# 2. Everything between %F{x} and %f is in a different color;
# x can be a color name, and you can switch from one
# color to another without using %f
# 3. zsh is smart enough to account for built-in escapes when
# computing the prompt lenght, so no equivalent of \[...\]
# is needed
# 4. %n is the same as \u
# 5. %m is the same as \h
# 6. %~ is roughly the same as \W
# 7. %# is roughly the same as \$
PS1='%B%F{green}%n#%m: %F{white}%~%b%f%# '
This approach has two benefits over the others:
it brackets the escape sequences using \[ and ``]to prevent character count problems withCTRL-A` editing of wrapped lines
it uses tput to change the colors so that it is a little more self-documenting what is being done:
PS1='\[$(tput setaf 2)\]\u#\h: \[$(tput setaf 7)\]\W\[$(tput sgr0)\]\$'
To change color of prompt in each section, try to use this simple repo:
https://github.com/joenmarz/bashrc-alias
You can change the color of each prompt section like:
username
'#' sign
hostname
time
bracket sign '[' and ']'
root indicator (# for root user), ($ for non-root user)
The look of your prompt will be like:
[username#hostname 00:00 AM ~/working/directory $]
Go to line 33 of this file (bashrc-alias/.bashrc) to customize each prompt section color variables:
open_brk_color to change open bracket color
closed_brk_color to change closed bracket color
at_color to change '#' sign color
username_color to change username color
hostname_color to change hostname color
time_color to change time prompt color
wd_color to change working directory prompt color
ri_color to change root indicator color
How To Install
Clone this repository at your home directory
git clone https://github.com/joenmarz/bashrc-alias
Add the file path inside your existing ~/.bash file:
. /home/$USER/bashrc-alias/aliases
refesh your .bashrc source by typing:
source ~/.bashrc
I made it easier by adding some variables to each prompt section.

Bash, Always display colored bar at top of screen

Is there anyway to modify the bash profile scripts to always display a colored bar at top of screen. I have a requirement to show a colored hostname, username, and ipaddress on the screen at all times, but i don't want to overload PS1 as it would make the prompt take up over half of the default console width.
Not perfect, but this shows you how to fix part of your prompt on the first row of the screen:
PS1='\w \[\e[s\e[1;1H\e[42m\]\h \u ipaddress\[\e[0m\e[u\]\$ '
A breakdown:
\e[s - save the current cursor position
\e[1;1H - move the cursor to row 1, column 1 (numbered from the upper left-hand corner
\e[u - restore the cursor to the previously saved position
\e42m - make the background green
\e0m - restore the default foreground/background colors
\[...\] - enclose the various non-printing characters so that bash can correctly compute the length of the prompt.
Wikipedia lists other escape codes. The two things missing from this answer are how to extend the bar all the way across the string and how to set the correct IP address.
Update: I believe this covers the changes that ruckc made:
PS1='\[\e[s\e[1;1H\e[42m\e[K\h \u ipaddress\e[0m\e[u\]\w \$ '
How about add a \n inside your PS1, so that you always use a new line with full width?
if you are looking for something less hacky (but maybe overkill), consider byobu
https://en.wikipedia.org/wiki/Byobu_(software)
Alternatively, if you are using xterms, you could set the xterm title instead:
export PS1="\[\033]0;\u $(host $(hostname))\007\]\u#\h:\w\$ "
This sets your xterm title, and sets your prompt to contain username#host:pwd.
My .bashrc contains something like this so PS1 is set correctly depending on whether we're in an xterm or not:
if [[ -n "$TERM" ]] ; then
if ( echo $TERM | $GREP -q xterm ) ; then
export PS1="\[\033]0;\u#\h:\w\007\]\u#\h:\w\$ "
else
export PS1="\u#\h:\w\$ "
fi
fi

In an xterm, can I turn off bold or underline without resetting the current color?

I'm processing input (from sources like, but limited to, ls -la --color) and underlining certain sections of the text. I don't process these inputs character-by-character, but with lots of regular expressions, which makes it rather difficult to track whether the substring I'm affecting is already colored or in bold. If I have a red block of text, and I want to underline some part of it, I might do something like:
s/(123)/\033[4m\1\033[0m/g
(My expressions are much more complex. In reality, matches extracted, processed on their own, and further broken down and analyzed. This isn't something that can be done by changing the expression I've given here.)
The code above would replace all ocurrences of 123 with [UNDERLINE_START]123[FORMAT_RESET]. Unfortunately, the reset also turns off the coloring of text. It would save me a great deal of headache if I could just turn off the underlining when that is all I want to disable, but I'm pretty sure there's no way to do that. Can anyone tell me that I'm wrong?
EDIT: I could simplify the question by asking: if I want to turn off underlining, can I do that without affecting the current text color, since that color could have been set long before my script even started executing, and I don't have a way to detect what that color is?
Nobody seems to document it, but adding 20 to the decorator codes will turn them off:
echo -e "\\033[34;4m" underlined "\\033[24m" not underlined
echo -e "\\033[34;1m" bold "\\033[2m" not bold
echo -e "\\033[34;2m" dark "\\033[22m" not dark
echo -e "\\033[34;7m" inverse "\\033[27m" not inverse
Instead of those hard-coded escape sequences, use:
tput smul # set underline
tput rmul # remove underline
tput smso # set bold on
tput rmso # remove bold
tput setaf 1 #red
tput setaf 2 #green
...
tput cup 0 0 # move to pos 0,0
Refer to "man terminfo" and "man tput" for complete descriptions of these commands.
Examples :
function f_help
{
c_green=$(tput setaf 2 2>/dev/null)
c_reset=$(tput sgr0 2>/dev/null)
c_bold=$(tput smso 2>/dev/null)
echo "${c_bold}DESCRIPTION${c_reset} : ...."
}
echo "${c_green}GREEN ${c_underline} GREEN AND UNDERLINED${c_nounderline} GREEN AGAIN${c_reset} PLAIN BLACK TEXT"
The ${c_underline} escape sequence doesn't affect the color of the text; it only turns underlining on. ${c_nounderline} only turns underlining off.

Resources