-
Notifications
You must be signed in to change notification settings - Fork 0
/
sh-prompt.sh
436 lines (415 loc) · 18.1 KB
/
sh-prompt.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# Copyright (C) 2015 Craig E. Shea
# Distributed under the GNU General Public License, version 2.0.
#
# This script allows you to customize your bash prompt in much the same way
# as you can customize the git prompt using __git_ps1 as defined in git-prompt.sh.
# Furthermore, if __git_ps1 is available, your git repository status will also be
# shown when the PWD contains a git repository.
#
# NOTE: This does not yet work on Zsh!! Submit a pull request or wait until I
# finally get around to it.
#
# To enable:
#
# 1) Copy this file to somewhere (e.g. ~/.bash-prompt.sh).
# 2) Add the following line to your .bashrc/.zshrc:
# source ~/.bash-prompt.sh
# 3) If you also have git installed, add the following line to
# your ./bashrc/.zshrc:
# source ~/.git-prompt.sh
#
# Be sure to use the correct path to the git-prompt.sh file.
# Also, source git-prompt.sh before bash-prompt.sh since
# this script calls __git_ps1 directly--so __git_ps1 needs
# to be defined before __bash_ps1.
#
# 4a) Change your PS1 to call __bash_ps1 as
# command-substitution:
# Bash: PS1='$(__bash_ps1 "${BASH_PS1_FORMAT_STRING-}")'
# the optional argument will be used as the bash prompt format
# string.
# 4b) Alternatively, for a slightly faster prompt, __bash_ps1 can
# be used for PROMPT_COMMAND in Bash with two parameters,
# <pre> and <post>, which are strings you would put in $PS1
# before and after the prompt string generated by the bash-prompt
# machinery. e.g.
# Bash: PROMPT_COMMAND='__bash_ps1 "Hello " "Ready to accept commands." "${SH_PS1_FORMAT_STRING}"'
# will show:
#
# Hello <username@hostname> ~
# Ready to accept commands.
# $
#
# as your prompt.
#
# Optionally, you can supply a fourth argument with a printf
# format string to finetune the output of the git branch status
#
#
# What follows are the environment variables you can set in your .bashrc
# file prior to sourcing this script to customize the appearance of your
# bash prompt.
#
# SH PROMPT CUSTOMIZATION VARIABLES
#-----------------------------------------------------
#
# SH_PS1_USERNAME
# Sets the string to be used for the username portion of the
# prompt string.
#
# If not declared, null, or empty, then this defaults to the
# username placeholder token for the shell prompt.
#
# Otherwise, the username portion of the shell prompt will contain
# this text. NOTE: if the format string does not contain \u (for bash,
# for example), then the username of the current interactive user
# will not be displayed; however, any other text in this variable
# will still be displayed.
#
# If you don't want to display the username portion of the shell prompt,
# omit the %u format specifier in SH_PS1_FORMAT_STRING.
# See below for more details.
#
# Example:
# SH_PS1_USERNAME="\n$(tput setaf 170)$MSYSTEM \u"
#
# - This results, on MINGW64 system, MINGW64 (displayed in a
# light purple on a 256-color terminal) followed by a space-separated
# followed by the bash username of the current interactive user.
#
# SH_PS1_USER_HOST_SEPARATOR
# Sets the string to be used for separating the username from the hostname.
#
# If not declared, null, or empty, then this defaults to the @ character.
# Otherwise, the value defined is used between the username and hostname
# portions of the shell prompt fromat string.
#
# If for whatever reason you want no separator between the username and
# hostname portions of the shell prompt, then omit the %z format specifier
# in SH_PS1_FORMAT_STRING instead. See below for more details.
#
# SH_PS1_HOSTNAME
# Sets the string to be used for the hostname portion of the
# prompt string.
#
# If not declared, null, or empty, then this defaults to the
# hostname placeholder token for the shell prompt.
#
# Otherwise, the hostname portion of the shell prompt will contain
# this text. NOTE: if the format string does not contain \h (for bash,
# for example), then the hostname will not be displayed; however, any
# other text in this variable will still be displayed.
#
# If you don't want to display the hostname portion of the shell prompt,
# omit the %h format specifier in SH_PS1_FORMAT_STRING.
# See below for more details.
#
# SH_PS1_PWD
# Sets the string to be used for the pwd portion of the
# prompt string.
#
# If not declared, null, or empty, then this defaults to the
# pwd placeholder token for the shell prompt.
#
# Otherwise, the pwd portion of the shell prompt will contain
# this text. NOTE: if the format string does not contain \w (for bash,
# for example), then the pwd will not be displayed; however, any other
# text in this variable will still be displayed.
#
# If you don't want to display the pwd portion of the shell prompt,
# omit the %w format specifier in SH_PS1_FORMAT_STRING.
# See below for more details.
#
# SH_PS1_PROMPT
# Sets the string to be used for the prompt portion of the
# prompt string (i.e. the $ or # that is displayed indicating the
# shell is ready for user input).
#
# If not declared, null, or empty, then this defaults to "\n$ "
# for the shell prompt (e.g. a $ on a new line followed by a space).
#
# Any other text can be used for this variable. But as you may have
# noticed, something must be displayed. There is no way to not
# have some sort of prompt be displayed.
#
# SH_PS1_FORMAT_STRING
# Defines the tokens that define what portions of the bash prompt
# should be displayed, and in what order. The SH_PS1_PROMPT is
# always appended to this string.
#
# If this variable is undeclared, null, or empty, it defaults to
# "%u%z%h%w%v". By default, this results in the following prompt:
#
# username@host pwd [git_repository_info]
# $
#
# If you are not inside a git repository (or __git_ps1 is not defined),
# then the [git_repository_info] is not displayed.
#
# The meanings of the format specifier tokens are:
#
# %u - Gets replaced with SH_PS1_USERNAME
# %z - Gets replaced with SH_PS1_USER_HOST_SEPARATOR
# %h - Gets replaced with SH_PS1_HOSTNAME
# %w - Gets replaced with SH_PS1_PWD
# %v - If __git_ps1 is defined, and you are in a directory
# that houses a git repository, displays the git
# repository information.
#
# Some notes regarding the use of this variable:
#
# 1. You can place these tokens in any order.
# 2. All whitespace between tokens is stripped out.
# 3. This variable should only contain these tokens and no
# other text. Any other text included in this variable
# may result in unpredictable and unsupported behavior.
# 4. Any spacing and formatting should occur within the
# individual format string variables (e.g. SH_PS1_*
# variables discussed above).
#
# SH_PS1_DONT_COLORIZE_PROMPT
# If set to 1, the bash prompt will not be colorized (unless any
# format strings contain tput commands--but then just that
# particular part of the format string will be colored).
#
# If this variable is not declared or has any value other than 1
# (including null), then the bash prompt will be colorized.
#
# SH_PS1_USERNAME_COLOR
# Set the color the username portion of the shell prompt.
# If this variable is not declared and SH_PS1_DONT_COLORIZE_PROMPT is not
# set to 1, the default color is green, $(tput setaf 2).
# If this variable is null or empty, it results in $(tput sgr0).
#
# SH_PS1_USER_HOST_SEPARATOR_COLOR
# Set the color for the text which separates the username/hostname portions
# of the shell prompt.
# If this variable is not declared and SH_PS1_DONT_COLORIZE_PROMPT is not
# set to 1, the default color is green, $(tput setaf 2).
# If this variable is null or empty, it results in $(tput sgr0).
#
# SH_PS1_HOSTNAME_COLOR
# Set the color for the hostname portion of the shell prompt.
# If this variable is not declared and SH_PS1_DONT_COLORIZE_PROMPT is not
# set to 1, the default color is green, $(tput setaf 2).
# If this variable is null or empty, it results in $(tput sgr0).
#
# SH_PS1_PWD_COLOR
# Set the color for the present working directory portion of the
# shell prompt.
# If this variable is not declared and SH_PS1_DONT_COLORIZE_PROMPT is not
# set to 1, the default color is dim yellow $(tput setaf 3) (or
# brown, as I think it was called for 8/16-color mode)
# If this variable is null or empty, it results in $(tput sgr0).
#
# SH_PROMPT_COLOR
# Set the color for the prompt character portion of the shell
# prompt (e.g. the $ or # that appears indicating the shell is
# awaiting user input).
# If this variable is not declared, is null, or empty, then the
# prompt string's resulting color is $(tput sgr0). Otherwise, its
# the specified color.
#
# NOTE: There's nothing stopping you from placing other text in the
# variables discussed above, but they're intended only to contain
# color information for the various pieces of the prompt string.
# You can experiment with other values other than purely color
# information, but you do so at your own risk. This is unsupported
# behavior.
#
# If the user has .git-prompt.sh or git-prompt.sh in their home directory,
# source these versions of git-prompt (which contains __git_ps1).
#
# Otherwise, I used the code used by Git for Windows located in
# /etc/profile.d/git-prompt.sh that attempts to find the Git for Windows
# supplied version of git-prompt.sh and sources that.
if [[ -e ~/.git-prompt.sh ]]; then
. ~/.git-prompt.sh
elif [[ -e ~/git-prompt.sh ]]; then
. ~/git-prompt.sh
elif test -z "$WINELOADERNOEXEC"; then
GIT_EXEC_PATH="$(git --exec-path 2>/dev/null)"
COMPLETION_PATH="${GIT_EXEC_PATH%/libexec/git-core}"
COMPLETION_PATH="${COMPLETION_PATH%/lib/git-core}"
COMPLETION_PATH="$COMPLETION_PATH/share/git/completion"
if test -f "$COMPLETION_PATH/git-prompt.sh"; then
. "$COMPLETION_PATH/git-completion.bash"
. "$COMPLETION_PATH/git-prompt.sh"
fi
fi
function is_function_defined()
{
declare -Ff "$1" >/dev/null && echo "yes" || echo "no"
}
function is_variable_declared()
{
declare | grep -c "^$1=" >/dev/null && echo "yes" || echo "no"
}
function __sh_ps1_colorize_promptstring()
{
local user_host_color="$(tput setaf 2)"
local pwd_color="$(tput setaf 3)"
local prompt_color="$(tput sgr0)"
# If any sh prompt color variable is not declared, then use the default color.
# Else, if it is declared and is null, or it is defined but empty, then use $(tput sgr0), otherwise, use the given color.
#
# Additionally, you'll notice that we're trying to preserve any other colorizing that may be occurring
# within any of the prompt variables. For example, if you specify SH_PS1_USERNAME="$(tput setaf 14)Hello! \u"
# and subsequently also set SH_PS1_USERNAME_COLOR="$(tput setaf 2)", then you would expect that
# Hello! would still by displayed in cyan while the username would be displayed in green.
case "$(is_variable_declared SH_PS1_USERNAME_COLOR)" in
"yes") u="${u//\\u/${SH_PS1_USERNAME_COLOR:-$(tput sgr0)}\\u}" ;;
"no" ) u="${u//\\u/$user_host_color\\u}" ;;
esac
# TL;DR : Don't need to "preserve" color formatting for the username/hostname separator character.
#
# Since this is meant to be a separator character (or characters) between the
# username and hostname, no "color preservation" needs to be done.
# If the user wants a highly customized, colorized username/hostname separator,
# they would simply set SH_PS1_USER_HOST_SEPARATOR to some complex string embedded
# with color info. Additionally, SH_PS1_USER_HOST_SEPARATOR_COLOR provides the overall
# base color for the username/hostname separator.
case "$(is_variable_declared SH_PS1_USER_HOST_SEPARATOR_COLOR)" in
"yes") z="${SH_PS1_USER_HOST_SEPARATOR_COLOR-$(tput sgr0)}$z" ;;
"no" ) z="$user_host_color$z" ;;
esac
case "$(is_variable_declared SH_PS1_HOSTNAME_COLOR)" in
"yes") h="${h//\\h/${SH_PS1_HOSTNAME_COLOR:-$(tput sgr0)}\\h}" ;;
"no" ) h="${h//\\h/$user_host_color\\h}" ;;
esac
case "$(is_variable_declared SH_PS1_PWD_COLOR)" in
"yes") w="${w//\\w/${SH_PS1_PWD_COLOR:-$(tput sgr0)}\\w}" ;;
"no" ) w="${w//\\w/$pwd_color\\w}" ;;
esac
p="${SH_PS1_PROMPT_COLOR-$prompt_color}$p$(tput sgr0)"
}
function __sh_ps1_printf_format_contains()
{
case $(echo "$1" | grep -c $2) in
0) return 1 ;;
*) return 0 ;;
esac
}
# __sh_ps1 accepts 0, 1, 2, or 3 arguments (i.e., format string)
# when called from PS1 using command substitution.
# In this mode it sets the text to use for the bash PS1 prompt.
# The optional third argument sets the title of the bash window.
#
# __sh_ps1 requires 0, 1, 2, 4, or 5 arguments when called from
# PROMPT_COMMAND (pc).
#
# In this case it _sets_ PS1 (either directly, or via __git_ps1, if the
# function is defined). The arguments are parts of a PS1 string.
#
# When no arguments are given, a standard shell prompt is displayed. If
# __git_ps1 is available (via git-prompt.sh being sourced in your .bashrc
# file), then when you are in a directory which contains a git repository,
# the git repository information is appended to the shell prompt.
# An example of the standard shell prompt that would be displayed is shown
# below:
#
# username@hostname pwd [git_repository_information]
# $
#
# When one argument is given, this argument specifies a format string
# that is used to determine the order in which the pieces of a typical
# shell prompt appear. If this argument is the empty string, it
# defaults to "%u%z%h%w%v", which results in the standard shell prompt
# being displayed as shown above.
#
# When two arguments are given, the first argument specifies a format
# string used to determining the order in which the pieces of a
# typical shell prompt appear. The second argument defines a format
# string for displaying git repository information in the prompt when
# inside of a git repository (via __git_ps1, if it is defined).
#
# When four arguments are given, the first two arguments are as defined
# above. The third argument is pre-pended to the shell prompt, while the
# fourth argument is appended to the shell prompt.
#
# If an optional fifth argument is provided, the argument is used to set
# the title of the bash window. NOTE: currently only works for xterm
# based terminals.
#
# Any other arguments provided after the fifth argument are simply
# ignored.
function __sh_ps1()
{
# Preserve exit status.
local exit=$?
local sh_ps1pc_start=""
local sh_ps1pc_end=""
# TODO: Determine if we're running in bash vs. zsh and set this variable appropriately.
# Set the initial sh string, defaulted to "\u@\h \w\n\\\$"
# The "format specifiers" have the following interpretation:
#
# u : Username. Will get substituted to \u or the value provided in SH_PS1_USERNAME
# z : Username/hostname separator. Will get substituted to @ or the value provided in SH_PS1_USER_HOST_SEPARATOR
# h : Hostname. Will get substituted to \h or the value provided in SH_PS1_HOSTNAME
# w : Present working directory. Will get substituted to \w or the value provided in SH_PS1_PWD
# v : Version Control Prompt. Place this format specifier where ever in your bash prompt you want
# your source code version control prompt to be displayed. This specifier will be replaced by,
# executing __git_ps1 from git-prompt.sh (or your local sourced version), for example, when git
# is your source code control management system.
local sh_printf_format="uzhwv"
local title
local git_printf_format
# Process function arguments.
case "$#" in
0|1|2)
sh_printf_format="${1:-$sh_printf_format}"
git_printf_format="${2:-}"
;;
3) title="${3+\033]2;$3\a}"
sh_printf_format="${1:-$sh_printf_format}"
git_printf_format="${2:-}"
;;
4) sh_printf_format="${1:-$sh_printf_format}"
git_printf_format="${2:-}"
sh_ps1pc_start="${3:-$sh_ps1pc_start}"
sh_ps1pc_end="${4:-$sh_ps1pc_end}"
;;
5) sh_printf_format="${1:-$sh_printf_format}"
git_printf_format="${2:-}"
sh_ps1pc_start="${3:-$sh_ps1pc_start}"
sh_ps1pc_end="${4:-$sh_ps1pc_end}"
title="${5+\033]2;$5\a}"
;;
esac
# Setup the default sh_prinf_format format specifier variable substitutions.
# This should result, by default, with a prompt like: "user@host pwd\n$ "
local u="${SH_PS1_USERNAME:-\\u}"
local z="${SH_PS1_USER_HOST_SEPARATOR:-@}"
local h="${SH_PS1_HOSTNAME:-\\h}"
local w="${SH_PS1_PWD:- \\w}"
local p="$sh_ps1pc_end${SH_PS1_PROMPT:-\n\\\$ }"
case "${SH_PS1_DONT_COLORIZE_PROMPT:-0}" in
0) __sh_ps1_colorize_promptstring ;;
esac
# Substitute the "format specifiers" u, h, etc. with $u, $h, etc.
# I couldn't use the exact same method as __git_ps1 because the end user has flexility to
# display their shell prompt components in any order they choose, hence this more awkward
# substitution syntax.
#
# NOTE: %v in the format string will be substituted with your vcs prompt formatter,
# i.e. __git_ps1, so we don't substitute it here.
sh_printf_format="${sh_printf_format//u/$u}"
sh_printf_format="${sh_printf_format//z/$z}"
sh_printf_format="${sh_printf_format//h/$h}"
sh_printf_format="${sh_printf_format//w/$w}"
sh_printf_format="$sh_printf_format$p"
case "$(is_function_defined __git_ps1)" in
"yes")
# Split the sh_printf_format on %v and pass the part before %v to the __git_ps1pc_start param
# and the part after %v to the __git_ps1pc_end param.
local __git_ps1pc_end="${sh_printf_format##*v}"
local __git_ps1pc_start="${sh_ps1pc_start}${sh_printf_format%v*}$(tput sgr0)"
# Call __git_ps1 to set the PS1 variable.
__git_ps1 "$title$__git_ps1pc_start" "$__git_ps1pc_end" ${git_printf_format+"${git_printf_format}"}
;;
"no" )
PS1="${title}${sh_printf_format}"
;;
esac
return $exit
}