liquidprompt 96.3 KB
Newer Older
1
2
################################################################################
# LIQUID PROMPT
3
# An intelligent and non-intrusive prompt for Bash and zsh
4
5
################################################################################

nojhan's avatar
nojhan committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Licensed under the AGPL version 3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

21
22
# See the README.md file for a summary of features.

23
# Issue #161: do not load if not an interactive shell
24
25
# Do not exit if '--no-activate' flag was passed, as it overrides this check
[ "x${-##*i}" = "x$-" ] || [ -z "${TERM-}" ] || [ "x${TERM-}" = xdumb ] && [ "x${1-}" != "x--no-activate" ] && return
26

Mark Vander Stel's avatar
Mark Vander Stel committed
27
if test -n "${BASH_VERSION-}"; then
28
    # Check for recent enough version of bash.
29
30
    if (( ${BASH_VERSINFO[0]:-0} < 3 || ( ${BASH_VERSINFO[0]:-0} == 3 && ${BASH_VERSINFO[1]:-0} < 2 ) )); then
        echo "liquidprompt: Bash version $BASH_VERSION not supported" 2>&1
31
32
        return
    fi
33

34
35
    _LP_SHELL_bash=1
    _LP_SHELL_zsh=0
36
    _LP_OPEN_ESC="\["
37
    _LP_CLOSE_ESC="\]"
38

39
    _LP_MARK_SYMBOL='$'
40

Alex's avatar
Alex committed
41
    _LP_FIRST_INDEX=0
42
    _LP_PERCENT='%'    # must be escaped on zsh
43

44
45
46
47
    # Sed expression using extended regexp to match terminal
    # escape sequences with their wrappers
    _LP_CLEAN_ESC='\\\[([^\]+|\\[^]])*\\\]'

48
49
50
    # Escape the given strings
    # Must be used for all strings injected in PS1 that may comes from remote sources,
    # like $PWD, VCS branch names...
51
    __lp_escape() {
52
53
54
55
56
        ret="${1//\\/\\\\}"
        if shopt -q promptvars ; then
            ret="${ret//\$/\\\$}"
            ret="${ret//\`/\\\`}"
        fi
57
    }
58
elif test -n "${ZSH_VERSION-}" ; then
59
60
61
62
63
64
    # Check for recent enough version of zsh.
    if (( ${ZSH_VERSION:0:1} < 5 )); then
        echo "liquidprompt: Zsh version $ZSH_VERSION not supported" 2>&1
        return
    fi

65
66
    _LP_SHELL_bash=0
    _LP_SHELL_zsh=1
67
    _LP_OPEN_ESC="%{"
68
    _LP_CLOSE_ESC="%}"
69

70
    _LP_MARK_SYMBOL='%%'
71

72
    _LP_FIRST_INDEX=1
Olivier Mengué's avatar
Olivier Mengué committed
73
    _LP_PERCENT='%%'
Olivier Mengué's avatar
Olivier Mengué committed
74

75
76
    _LP_CLEAN_ESC='%\{([^%]+|%[^}])*%\}'

77
    __lp_escape() {
78
79
80
81
82
83
84
85
86
        ret="${1//\\/\\\\}"
        ret="${ret//\%/%%}"
        if [[ -o promptbang ]]; then
            ret="${ret//!/!!}"
        fi
        if [[ -o promptsubst ]]; then
            ret="${ret//\$/\\\$}"
            ret="${ret//\`/\\\`}"
        fi
87
    }
Olivier Mengué's avatar
Olivier Mengué committed
88
else
nojhan's avatar
nojhan committed
89
90
    echo "liquidprompt: shell not supported" >&2
    return
91
92
fi

nojhan's avatar
nojhan committed
93
###############
nojhan's avatar
nojhan committed
94
# OS specific #
nojhan's avatar
nojhan committed
95
96
###############

97
# LP_OS detection, default to Linux
Mark Vander Stel's avatar
Mark Vander Stel committed
98
case "$(uname)" in
Olivier Mengué's avatar
Olivier Mengué committed
99
100
    FreeBSD)   LP_OS=FreeBSD ;;
    DragonFly) LP_OS=FreeBSD ;;
Kim Lidström's avatar
Kim Lidström committed
101
    OpenBSD)   LP_OS=OpenBSD ;;
Ludovic Rousseau's avatar
Ludovic Rousseau committed
102
    Darwin)    LP_OS=Darwin  ;;
Olivier Mengué's avatar
Olivier Mengué committed
103
104
    SunOS)     LP_OS=SunOS   ;;
    *)         LP_OS=Linux   ;;
105
esac
106

107
108
109
110
111
# Extended regexp patterns for sed
# GNU/BSD sed
_LP_SED_EXTENDED=r
[[ "$LP_OS" = Darwin ]] && _LP_SED_EXTENDED=E

nojhan's avatar
nojhan committed
112
113
114
115
#################
# CONFIGURATION #
#################

116
# Load the user configuration and setup defaults.
117
__lp_source_config() {
118

119
    local lp_terminal_format af_color= ab_color=
120

121
122
123
    # Colors: variables are local so they will have a value only
    # during config loading and will not conflict with other values
    # with the same names defined by the user outside the config.
124
    local BOLD="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${_LP_CLOSE_ESC}"
125

nojhan's avatar
nojhan committed
126
    # Foreground colors
127
    __lp_foreground_color 0
128
    local BLACK="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
129
    local BOLD_GRAY="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
130

131
    __lp_foreground_color 1
132
    local RED="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
133
134
135
    local BOLD_RED="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
    __lp_foreground_color 0
    __lp_background_color 1
136
    local WARN_RED="${_LP_OPEN_ESC}${af_color}${ab_color}${_LP_CLOSE_ESC}"
137
138
139
140
    __lp_foreground_color 7
    local CRIT_RED="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${ab_color}${_LP_CLOSE_ESC}"
    __lp_foreground_color 3
    local DANGER_RED="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${ab_color}${_LP_CLOSE_ESC}"
141

142
    __lp_foreground_color 2
143
    local GREEN="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
144
    local BOLD_GREEN="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
145

146
    __lp_foreground_color 3
147
    local YELLOW="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
148
    local BOLD_YELLOW="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
149

150
    __lp_foreground_color 4
151
    local BLUE="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
152
    local BOLD_BLUE="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
153

154
    __lp_foreground_color 5
155
    local PURPLE="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
nojhan's avatar
nojhan committed
156
    local MAGENTA="${PURPLE}"
157
    local PINK="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
nojhan's avatar
nojhan committed
158
159
    local BOLD_PURPLE="${PINK}"
    local BOLD_MAGENTA="${PINK}"
160

161
    __lp_foreground_color 6
162
    local CYAN="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
163
    local BOLD_CYAN="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
164

165
    __lp_foreground_color 7
166
    local WHITE="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
167
    local BOLD_WHITE="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
168

169
    # NO_COL is special: it will be used at runtime, not just during config loading
170
    NO_COL="${_LP_OPEN_ESC}${_LP_TI_RESET-}${_LP_CLOSE_ESC}"
171

172
173
174
175
176
    # compute the hash of the hostname and get the corresponding number in
    # [1-6] (red,green,yellow,blue,purple or cyan)
    local lp_hostname_hash
    __lp_hostname_hash
    __lp_foreground_color "$(( 1 + lp_hostname_hash % 6 ))"
177
    LP_COLOR_HOST_HASH="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
178

179

Olivier Mengué's avatar
Olivier Mengué committed
180
    # Default values (globals)
181
    LP_TIME_FORMAT=${LP_TIME_FORMAT:-"%H:%M:%S"}
182
    LP_BATTERY_THRESHOLD=${LP_BATTERY_THRESHOLD:-75}
183
    LP_LOAD_THRESHOLD=${LP_LOAD_THRESHOLD:-0.60}
184
    LP_LOAD_CAP=${LP_LOAD_CAP:-2.0}
185
    LP_TEMP_THRESHOLD=${LP_TEMP_THRESHOLD:-60}
Markus Dreseler's avatar
Markus Dreseler committed
186
    LP_RUNTIME_THRESHOLD=${LP_RUNTIME_THRESHOLD:-2}
187
    LP_RUNTIME_BELL_THRESHOLD=${LP_RUNTIME_BELL_THRESHOLD:-10}
188
189
    LP_PATH_LENGTH=${LP_PATH_LENGTH:-35}
    LP_PATH_KEEP=${LP_PATH_KEEP:-2}
190
    LP_PATH_CHARACTER_KEEP=${LP_PATH_CHARACTER_KEEP:-3}
191
    LP_PATH_METHOD=${LP_PATH_METHOD:-truncate_chars_from_path_left}
192
    LP_PATH_VCS_ROOT=${LP_PATH_VCS_ROOT:-1}
193
    LP_HOSTNAME_ALWAYS=${LP_HOSTNAME_ALWAYS:-0}
194
    LP_USER_ALWAYS=${LP_USER_ALWAYS:-1}
195
    LP_PERCENTS_ALWAYS=${LP_PERCENTS_ALWAYS:-1}
196
    LP_PS1=${LP_PS1:-""}
nojhan's avatar
nojhan committed
197
    LP_PS1_PREFIX=${LP_PS1_PREFIX:-""}
Brendan Fahy's avatar
Brendan Fahy committed
198
    LP_PS1_POSTFIX=${LP_PS1_POSTFIX:-""}
199
    LP_MARK_KUBECONTEXT=${LP_MARK_KUBECONTEXT:-"⎈"}
200
201
    LP_DELIMITER_KUBECONTEXT_SUFFIX=${LP_DELIMITER_KUBECONTEXT_SUFFIX:-""}
    LP_DELIMITER_KUBECONTEXT_PREFIX=${LP_DELIMITER_KUBECONTEXT_PREFIX:-""}
202
203
204
205

    LP_ENABLE_PERM=${LP_ENABLE_PERM:-1}
    LP_ENABLE_SHORTEN_PATH=${LP_ENABLE_SHORTEN_PATH:-1}
    LP_ENABLE_PROXY=${LP_ENABLE_PROXY:-1}
206
    LP_ENABLE_TEMP=${LP_ENABLE_TEMP:-1}
207
    LP_ENABLE_JOBS=${LP_ENABLE_JOBS:-1}
208
    LP_ENABLE_DETACHED_SESSIONS=${LP_ENABLE_DETACHED_SESSIONS:-1}
209
210
211
212
    LP_ENABLE_LOAD=${LP_ENABLE_LOAD:-1}
    LP_ENABLE_BATT=${LP_ENABLE_BATT:-1}
    LP_ENABLE_GIT=${LP_ENABLE_GIT:-1}
    LP_ENABLE_SVN=${LP_ENABLE_SVN:-1}
Étienne Deparis's avatar
Étienne Deparis committed
213
    LP_ENABLE_FOSSIL=${LP_ENABLE_FOSSIL:-1}
214
    LP_ENABLE_HG=${LP_ENABLE_HG:-1}
Clément MATHIEU's avatar
Clément MATHIEU committed
215
    LP_ENABLE_BZR=${LP_ENABLE_BZR:-1}
216
    LP_ENABLE_TIME=${LP_ENABLE_TIME:-0}
217
    LP_TIME_ANALOG=${LP_TIME_ANALOG:-0}
Austen Adler's avatar
Austen Adler committed
218
    LP_ENABLE_RUNTIME=${LP_ENABLE_RUNTIME:-1}
219
    LP_ENABLE_RUNTIME_BELL=${LP_ENABLE_RUNTIME_BELL:-0}
220
    LP_ENABLE_VIRTUALENV=${LP_ENABLE_VIRTUALENV:-1}
221
222
223
    LP_ENABLE_RUBY_VENV=${LP_ENABLE_RUBY_VENV:-1}
    LP_RUBY_RVM_PROMPT_OPTIONS=( ${LP_RUBY_RVM_PROMPT_OPTIONS[@]+"${LP_RUBY_RVM_PROMPT_OPTIONS[@]}"} )
    [[ ${#LP_RUBY_RVM_PROMPT_OPTIONS[@]} == 0 ]] && LP_RUBY_RVM_PROMPT_OPTIONS=(i v g s)
Ken Crowell's avatar
Ken Crowell committed
224
    LP_ENABLE_TERRAFORM=${LP_ENABLE_TERRAFORM:-0}
225
    LP_ENABLE_SCLS=${LP_ENABLE_SCLS:-1}
226
    LP_ENABLE_AWS_PROFILE=${LP_ENABLE_AWS_PROFILE:-1}
227
    LP_ENABLE_VCS_ROOT=${LP_ENABLE_VCS_ROOT:-0}
nojhan's avatar
nojhan committed
228
    LP_ENABLE_TITLE=${LP_ENABLE_TITLE:-0}
229
    LP_ENABLE_SCREEN_TITLE=${LP_ENABLE_SCREEN_TITLE:-0}
Mark Vander Stel's avatar
Mark Vander Stel committed
230
    LP_ENABLE_TITLE_COMMAND=${LP_ENABLE_TITLE_COMMAND:-1}
231
    LP_ENABLE_SSH_COLORS=${LP_ENABLE_SSH_COLORS:-0}
Erik M Jacobs's avatar
Erik M Jacobs committed
232
    LP_ENABLE_FQDN=${LP_ENABLE_FQDN:-0}
233
    LP_DISABLED_VCS_PATHS=( ${LP_DISABLED_VCS_PATHS[@]+"${LP_DISABLED_VCS_PATHS[@]}"} )
234
    LP_ENABLE_SUDO=${LP_ENABLE_SUDO:-0}
235
    LP_ENABLE_COLOR=${LP_ENABLE_COLOR:-1}
236
    LP_ENABLE_ERROR=${LP_ENABLE_ERROR:-1}
237
    LP_ENABLE_DIRSTACK=${LP_ENABLE_DIRSTACK:-0}
238
    LP_ENABLE_KUBECONTEXT=${LP_ENABLE_KUBECONTEXT:-0}
239

240
    LP_MARK_DEFAULT="${LP_MARK_DEFAULT:-$_LP_MARK_SYMBOL}"
241
242
243
244
245
246
247
248
    LP_MARK_BATTERY="${LP_MARK_BATTERY:-"⌁"}"
    LP_MARK_ADAPTER="${LP_MARK_ADAPTER:-"⏚"}"
    LP_MARK_LOAD="${LP_MARK_LOAD:-"⌂"}"
    LP_MARK_TEMP="${LP_MARK_TEMP:-"θ"}"
    LP_MARK_PROXY="${LP_MARK_PROXY:-"↥"}"
    LP_MARK_HG="${LP_MARK_HG:-"☿"}"
    LP_MARK_SVN="${LP_MARK_SVN:-"‡"}"
    LP_MARK_GIT="${LP_MARK_GIT:-"±"}"
Cosmin L. Neagu's avatar
Cosmin L. Neagu committed
249
    LP_MARK_VCSH="${LP_MARK_VCSH:-"|"}"
250
251
252
253
254
255
256
257
    LP_MARK_FOSSIL="${LP_MARK_FOSSIL:-"⌘"}"
    LP_MARK_BZR="${LP_MARK_BZR:-"⚯"}"
    LP_MARK_DISABLED="${LP_MARK_DISABLED:-"⌀"}"
    LP_MARK_UNTRACKED="${LP_MARK_UNTRACKED:-"*"}"
    LP_MARK_STASH="${LP_MARK_STASH:-"+"}"
    LP_MARK_BRACKET_OPEN="${LP_MARK_BRACKET_OPEN:-"["}"
    LP_MARK_BRACKET_CLOSE="${LP_MARK_BRACKET_CLOSE:-"]"}"
    LP_MARK_SHORTEN_PATH="${LP_MARK_SHORTEN_PATH:-" … "}"
Panayiotis Kkolos's avatar
Panayiotis Kkolos committed
258
    LP_MARK_PREFIX="${LP_MARK_PREFIX:-" "}"
259
    LP_MARK_PERM="${LP_MARK_PERM:-":"}"
260
    LP_MARK_DIRSTACK="${LP_MARK_DIRSTACK:-"⚞"}"
261

262
263
    LP_COLOR_PATH=${LP_COLOR_PATH:-$NO_COL}
    lp_terminal_format 8 -1 0 0 -1
264
265
    LP_COLOR_PATH_SEPARATOR=${LP_COLOR_PATH_SEPARATOR:-$lp_terminal_format}
    LP_COLOR_PATH_SHORTENED=${LP_COLOR_PATH_SHORTENED:-$lp_terminal_format}
266
    lp_terminal_format -1 -1 1 0
267
268
    LP_COLOR_PATH_VCS_ROOT=${LP_COLOR_PATH_VCS_ROOT:-$lp_terminal_format}
    LP_COLOR_PATH_LAST_DIR=${LP_COLOR_PATH_LAST_DIR:-$lp_terminal_format}
269
270
271
272
273
274
    LP_COLOR_PATH_ROOT=${LP_COLOR_PATH_ROOT:-$BOLD_YELLOW}
    LP_COLOR_PROXY=${LP_COLOR_PROXY:-$BOLD_BLUE}
    LP_COLOR_JOB_D=${LP_COLOR_JOB_D:-$YELLOW}
    LP_COLOR_JOB_R=${LP_COLOR_JOB_R:-$BOLD_YELLOW}
    LP_COLOR_JOB_Z=${LP_COLOR_JOB_Z:-$BOLD_YELLOW}
    LP_COLOR_ERR=${LP_COLOR_ERR:-$PURPLE}
275
    LP_COLOR_MARK=${LP_COLOR_MARK:-$BOLD}
276
    LP_COLOR_MARK_ROOT=${LP_COLOR_MARK_ROOT:-$BOLD_RED}
Olivier Mengué's avatar
Olivier Mengué committed
277
    LP_COLOR_MARK_SUDO=${LP_COLOR_MARK_SUDO:-$LP_COLOR_MARK_ROOT}
278
279
    LP_COLOR_USER_LOGGED=${LP_COLOR_USER_LOGGED:-""}
    LP_COLOR_USER_ALT=${LP_COLOR_USER_ALT:-$BOLD}
280
    LP_COLOR_USER_ROOT=${LP_COLOR_USER_ROOT:-$BOLD_YELLOW}
281
    LP_COLOR_HOST=${LP_COLOR_HOST:-""}
nojhan's avatar
nojhan committed
282
    LP_COLOR_SSH=${LP_COLOR_SSH:-$BLUE}
283
    LP_COLOR_SU=${LP_COLOR_SU:-$BOLD_YELLOW}
284
    LP_COLOR_TELNET=${LP_COLOR_TELNET:-$WARN_RED}
285
286
    LP_COLOR_X11_ON=${LP_COLOR_X11_ON:-$GREEN}
    LP_COLOR_X11_OFF=${LP_COLOR_X11_OFF:-$YELLOW}
287
288
289
290
    LP_COLOR_WRITE=${LP_COLOR_WRITE:-$GREEN}
    LP_COLOR_NOWRITE=${LP_COLOR_NOWRITE:-$RED}
    LP_COLOR_UP=${LP_COLOR_UP:-$GREEN}
    LP_COLOR_COMMITS=${LP_COLOR_COMMITS:-$YELLOW}
François Schmidts's avatar
François Schmidts committed
291
    LP_COLOR_COMMITS_BEHIND=${LP_COLOR_COMMITS_BEHIND:-$BOLD_RED}
292
293
294
295
296
297
298
    LP_COLOR_CHANGES=${LP_COLOR_CHANGES:-$RED}
    LP_COLOR_DIFF=${LP_COLOR_DIFF:-$PURPLE}
    LP_COLOR_CHARGING_ABOVE=${LP_COLOR_CHARGING_ABOVE:-$GREEN}
    LP_COLOR_CHARGING_UNDER=${LP_COLOR_CHARGING_UNDER:-$YELLOW}
    LP_COLOR_DISCHARGING_ABOVE=${LP_COLOR_DISCHARGING_ABOVE:-$YELLOW}
    LP_COLOR_DISCHARGING_UNDER=${LP_COLOR_DISCHARGING_UNDER:-$RED}
    LP_COLOR_TIME=${LP_COLOR_TIME:-$BLUE}
299
    LP_COLOR_IN_MULTIPLEXER=${LP_COLOR_IN_MULTIPLEXER:-$BOLD_BLUE}
Markus Dreseler's avatar
Markus Dreseler committed
300
    LP_COLOR_RUNTIME=${LP_COLOR_RUNTIME:-$YELLOW}
301
    LP_COLOR_VIRTUALENV=${LP_COLOR_VIRTUALENV:-$CYAN}
Ken Crowell's avatar
Ken Crowell committed
302
    LP_COLOR_TERRAFORM=${LP_COLOR_TERRAFORM:-$PINK}
303
    LP_COLOR_DIRSTACK=${LP_COLOR_DIRSTACK:-$BOLD_YELLOW}
304
    LP_COLOR_KUBECONTEXT=${LP_COLOR_KUBECONTEXT:-$CYAN}
305
    LP_COLOR_AWS_PROFILE=${LP_COLOR_AWS_PROFILE:-$YELLOW}
306

307
308
    LP_COLORMAP=( ${LP_COLORMAP[@]+"${LP_COLORMAP[@]}"} )
    if [[ ${#LP_COLORMAP[@]} == 0 ]]; then
309
310
311
312
313
314
315
316
317
318
319
320
321
        LP_COLORMAP=(
            ""               # 0
            "$GREEN"         # 1
            "$BOLD_GREEN"    # 2
            "$YELLOW"        # 3
            "$BOLD_YELLOW"   # 4
            "$RED"           # 5
            "$BOLD_RED"      # 6
            "$WARN_RED"      # 7
            "$CRIT_RED"      # 8
            "$DANGER_RED"    # 9
        )
    fi
nojhan's avatar
nojhan committed
322

323
324
    # Debugging flags
    LP_DEBUG_TIME=${LP_DEBUG_TIME:-0}
nojhan's avatar
nojhan committed
325

Mark Vander Stel's avatar
Mark Vander Stel committed
326
327
328
    if [[ ${1-} == --no-config ]]; then
        return
    fi
329

330
331
    # Default config file may be the XDG standard ~/.config/liquidpromptrc,
    # but heirloom dotfile has priority.
332
333
    local -a configfiles
    configfiles=("$HOME/.liquidpromptrc" "${XDG_CONFIG_HOME:-"$HOME/.config"}/liquidpromptrc")
Mark Vander Stel's avatar
Mark Vander Stel committed
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349

    # trailing ":" is so that ${search#*:} always removes something
    local configfile search="${XDG_CONFIG_DIRS:-/etc/xdg}:"
    while [[ -n "$search" ]]; do
        configfiles+=("${search%%:*}/liquidpromptrc")
        search="${search#*:}"
    done

    configfiles+=("/etc/liquidpromptrc")

    for configfile in "${configfiles[@]}"; do
        if [[ -f "$configfile" ]]; then
            source "$configfile"
            break
        fi
    done
350

351
    # Deprecations and compatibility shims
352

353
354
355
    if [[ -n "${LP_DISABLED_VCS_PATH-}" ]]; then
        echo "liquidprompt: LP_DISABLED_VCS_PATH is deprecated. Update your config to use LP_DISABLED_VCS_PATHS array." >&2

356
        (( _LP_SHELL_zsh )) && setopt local_options && setopt sh_word_split
Mark Vander Stel's avatar
Mark Vander Stel committed
357
358
359
        local _path IFS=:
        for _path in $LP_DISABLED_VCS_PATH; do
            LP_DISABLED_VCS_PATHS+=("$_path")
360
361
362
        done
    fi

363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
    # Delete this code in version 1.11
    if [[ -n "${LP_COLORMAP_1-}" ]]; then
        echo "liquidprompt: LP_COLORMAP_x variables are deprecated. Update your theme to use LP_COLORMAP array." >&2
        LP_COLORMAP=(
            "$LP_COLORMAP_0"
            "$LP_COLORMAP_1"
            "$LP_COLORMAP_2"
            "$LP_COLORMAP_3"
            "$LP_COLORMAP_4"
            "$LP_COLORMAP_5"
            "$LP_COLORMAP_6"
            "$LP_COLORMAP_7"
            "$LP_COLORMAP_8"
            "$LP_COLORMAP_9"
        )
        unset LP_COLORMAP_0 LP_COLORMAP_1 LP_COLORMAP_2 LP_COLORMAP_3 LP_COLORMAP_4 \
              LP_COLORMAP_5 LP_COLORMAP_6 LP_COLORMAP_7 LP_COLORMAP_8 LP_COLORMAP_9
    fi
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

    if [[ -n ${LP_PATH_DEFAULT-} ]]; then
        echo "liquidprompt: LP_PATH_DEFAULT is deprecated. Update your config to set LP_PATH_METHOD." >&2
        if (( ! LP_ENABLE_SHORTEN_PATH )); then
            # There is just no elegant way to handle this. Fallback to the old way with basic formatting support.
            _lp_path_format() {
                lp_path=$LP_PATH_DEFAULT
                lp_path_format="${LP_COLOR_PATH}${lp_path}${NO_COL}"
            }
        fi
    fi

    if [[ -n ${PROMPT_DIRTRIM-} ]] && (( ! LP_ENABLE_SHORTEN_PATH )); then
        echo "liquidprompt: PROMPT_DIRTRIM support is deprecated. Update your config to set
            LP_PATH_METHOD='truncate_chars_from_path_left' instead." >&2
        # This does mostly the same thing, but with our formatting.
        LP_ENABLE_SHORTEN_PATH=1
        LP_PATH_METHOD="truncate_chars_from_path_left"
        LP_PATH_KEEP=1
    fi

    if [[ $LP_PATH_KEEP == "-1" ]]; then
        echo "liquidprompt: LP_PATH_KEEP set to '-1' is deprecated. Update your config to set
              LP_PATH_METHOD='truncate_to_last_dir' instead." >&2
        LP_PATH_METHOD="truncate_to_last_dir"
    fi
nojhan's avatar
nojhan committed
407
408
}

409
# Initialize features based on the user config.
410
lp_activate() {
411
    if (( _LP_SHELL_bash )); then
412
        complete -F __lp_theme_bash_complete lp_theme
413
414
415
    else # zsh
        # For ZSH, autoload required functions
        autoload -Uz add-zsh-hook
Olivier Mengué's avatar
Olivier Mengué committed
416

417
418
        # Enable the autocomplete if the autocomplete system is initialized.
        __lp_is_function compdef && compdef __lp_theme_zsh_complete lp_theme
419
    fi
Olivier Mengué's avatar
Olivier Mengué committed
420

Mark Vander Stel's avatar
Mark Vander Stel committed
421
422
423
    # Disable hooks that we don't need if features will be disabled.
    __lp_disable_hooks

424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
    # TermInfo feature detection
    _lp_af_colors=() _lp_ab_colors=()

    __lp_foreground_color() { return 2 ; }
    __lp_background_color() { return 2 ; }

    # TODO handle this case better. With no colors, no need for any escaping
    if ! command -v tput >/dev/null; then
        echo "liquidprompt: 'tput' not available; will not be able to format terminal" >&2
        LP_ENABLE_COLOR=0
    else
        _LP_TI_RESET="$( { tput sgr0 || tput me ; } 2>/dev/null )"
        _LP_TI_BOLD="$( { tput bold || tput md ; } 2>/dev/null )"
        _LP_TI_UNDERLINE="$( { tput smul || tput us ; } 2>/dev/null )"
        _LP_TI_COLORS="$( tput colors 2>/dev/null )"
        _LP_TI_COLORS=${_LP_TI_COLORS:-8}

        _LP_TI_BELL="$( { tput bel || tput bl ; } 2>/dev/null )"

        if tput setaf 0 >/dev/null 2>&1; then
            __lp_foreground_color() { af_color="${_lp_af_colors[$1+1]:=$(tput setaf "$1")}"; }
        elif tput AF 0 >/dev/null 2>&1; then
            # FreeBSD
            __lp_foreground_color() { af_color="${_lp_af_colors[$1+1]:=$(tput AF "$1")}"; }
        elif tput AF 0 0 0 >/dev/null 2>&1; then
            # OpenBSD
            __lp_foreground_color() { af_color="${_lp_af_colors[$1+1]:=$(tput AF "$1" 0 0)}"; }
        else
452
            echo "liquidprompt: terminal '${TERM-}' does not support foreground colors" >&2
453
454
455
456
457
458
459
460
461
462
        fi
        if tput setab 0 >/dev/null 2>&1; then
            __lp_background_color() { ab_color="${_lp_ab_colors[$1+1]:=$(tput setab "$1")}"; }
        elif tput AB 0 >/dev/null 2>&1; then
            # FreeBSD
            __lp_background_color() { ab_color="${_lp_ab_colors[$1+1]:=$(tput AB "$1")}"; }
        elif tput AB 0 0 0 >/dev/null 2>&1; then
            # OpenBSD
            __lp_background_color() { ab_color="${_lp_ab_colors[$1+1]:=$(tput AB "$1" 0 0)}"; }
        else
463
            echo "liquidprompt: terminal '${TERM-}' does not support background colors" >&2
464
465
466
467
468
469
        fi
    fi

    # If tput doesn't exist or lookup failed, still try to send bell
    _LP_TI_BELL=${_LP_TI_BELL:-$'\a'}

Mark Vander Stel's avatar
Mark Vander Stel committed
470
    __lp_source_config "$@"
Olivier Mengué's avatar
Olivier Mengué committed
471

472
473
474
    # Disable feature if the tool is not installed
    _lp_require_tool()
    {
Mark Vander Stel's avatar
Mark Vander Stel committed
475
        (( LP_ENABLE_$1 )) && { command -v "$2" >/dev/null || eval LP_ENABLE_$1=0 ; }
476
    }
Olivier Mengué's avatar
Olivier Mengué committed
477

478
479
480
481
482
    _lp_require_tool GIT git
    _lp_require_tool SVN svn
    _lp_require_tool FOSSIL fossil
    _lp_require_tool HG hg
    _lp_require_tool BZR bzr
483

484
485
486
487
488
489
    _LP_ENABLED_VCSS=()
    (( LP_ENABLE_GIT )) && _LP_ENABLED_VCSS+=(git)
    (( LP_ENABLE_SVN )) && _LP_ENABLED_VCSS+=(svn)
    (( LP_ENABLE_HG )) && _LP_ENABLED_VCSS+=(hg)
    (( LP_ENABLE_BZR )) && _LP_ENABLED_VCSS+=(bzr)

490
491
492
493
494
    if [[ "$LP_OS" = Darwin ]]; then
        _lp_require_tool BATT pmset
    else
        _lp_require_tool BATT acpi
    fi
495

496
    _lp_require_tool KUBECONTEXT kubectl
Ken Crowell's avatar
Ken Crowell committed
497
    _lp_require_tool TERRAFORM terraform
498

499
    unset -f _lp_require_tool
500

501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
    # LP_ENABLE_RUBY_VENV depends either from rvm or rbenv. Thus we cannot
    # directly use _lp_require_tool for it.
    # Also, to avoid to check twice which is the current ruby virtual env
    # program in use, we set here an internal variable holding its name if we
    # detect one of them.
    if (( LP_ENABLE_RUBY_VENV )) ; then
        if command -v rvm-prompt >/dev/null ; then
            _LP_RUBY_VENV_PROGRAM=rvm
        elif command -v rbenv >/dev/null ; then
            _LP_RUBY_VENV_PROGRAM=rbenv
        else
            LP_ENABLE_RUBY_VENV=0
        fi
    fi

516
517
518
519
    if (( LP_ENABLE_DETACHED_SESSIONS )); then
        command -v screen >/dev/null ; _LP_ENABLE_SCREEN=$(( ! $? ))
        command -v tmux >/dev/null   ; _LP_ENABLE_TMUX=$(( ! $? ))
    fi
Olivier Mengué's avatar
Olivier Mengué committed
520

521
522
523
    # Use standard path symbols inside Midnight Commander
    [[ -n "${MC_SID-}" ]] && LP_ENABLE_SHORTEN_PATH=0

524
525
    # If we are running in a terminal multiplexer, special title escapes
    if _lp_multiplexer; then
526
        (( LP_ENABLE_TITLE = LP_ENABLE_TITLE && LP_ENABLE_SCREEN_TITLE ))
527
        LP_TITLE_OPEN=$'\Ek'
528
        LP_TITLE_CLOSE=$'\E\\'
529
    else
530
531
        LP_TITLE_OPEN=$'\E]0;'
        LP_TITLE_CLOSE=$'\a'
532
    fi
533

534
    [[ "_${TERM-}" == _linux* ]] && LP_ENABLE_TITLE=0
535

Mark Vander Stel's avatar
Mark Vander Stel committed
536
537
538
    # Can not show title command if the title feature is disabled.
    (( LP_ENABLE_TITLE )) || LP_ENABLE_TITLE_COMMAND=0

539
540
541
542
543
544
545
546
547
548
549
550
    # update_terminal_cwd is a shell function available on MacOS X Lion that
    # will update an icon of the directory displayed in the title of the terminal
    # window.
    # See http://hints.macworld.com/article.php?story=20110722211753852
    if [[ "${TERM_PROGRAM-}" == Apple_Terminal ]] && command -v update_terminal_cwd >/dev/null; then
        _LP_TERM_UPDATE_DIR=update_terminal_cwd
        # Remove "update_terminal_cwd; " that has been add by Apple in /et/bashrc.
        # See issue #196
        PROMPT_COMMAND="${PROMPT_COMMAND//update_terminal_cwd; /}"
    else
        _LP_TERM_UPDATE_DIR=:
    fi
551

552
553
554
555
    ###############
    # Who are we? #
    ###############

556
    _lp_user
557
    local -i user="$?"
558
559

    if (( user < 2 )); then  # if user is not root
560
        # "sudo -n" is only supported from sudo 1.7.0
561
562
563
564
        if (( LP_ENABLE_SUDO )); then
            command -v sudo >/dev/null \
            && LC_MESSAGES=C sudo -V | GREP_OPTIONS= \grep -qE '^Sudo version (1(\.([789]\.|[1-9][0-9])|[0-9])|[2-9])' \
            || LP_ENABLE_SUDO=0
565
        fi
566
567
568
569
570
571

        if (( user == 1 )); then
            LP_COLOR_USER=$LP_COLOR_USER_ALT
        else
            LP_COLOR_USER=$LP_COLOR_USER_LOGGED
        fi
572
    else # root!
573
        LP_ENABLE_SUDO=0
574
        if (( ! LP_ENABLE_VCS_ROOT )); then
575
            LP_DISABLED_VCS_PATHS=("/")
576
        fi
577

578
579
        LP_MARK_DEFAULT='#'

580
581
582
        LP_COLOR_MARK=$LP_COLOR_MARK_ROOT
        LP_COLOR_PATH=$LP_COLOR_PATH_ROOT
        LP_COLOR_USER=$LP_COLOR_USER_ROOT
583
    fi
584
585
586
587
588
589
590
591

    #################
    # Where are we? #
    #################

    if (( LP_ENABLE_TEMP )); then
        # Try each _lp_temp method
        # If no function worked, disable the feature
592
        __lp_temp_detect acpi sensors || LP_ENABLE_TEMP=0
593
    fi
Mark Vander Stel's avatar
Mark Vander Stel committed
594

595
596
597
    if (( LP_ENABLE_LOAD )); then
        # Find and save the number of CPUs
        __lp_cpu_count
598
599
600
601
602
603
604
605
606
607
608
609
610

        # Convert load config values into usable integers.
        local ret
        # if load threshold does not have a period in it.
        if [[ -z ${LP_LOAD_THRESHOLD//[!\.]} ]]; then
            # This is an old value, no need to convert
            _LP_LOAD_THRESHOLD=$LP_LOAD_THRESHOLD
        else
            __lp_floating_scale "$LP_LOAD_THRESHOLD" 100
            _LP_LOAD_THRESHOLD=$ret
        fi
        __lp_floating_scale "$LP_LOAD_CAP" 100
        _LP_LOAD_CAP=$ret
611
612
    fi

613
614
615
616
617
618
619
620
    if [[ -n ${_LP_THEME_ACTIVATE_FUNCTION-} ]]; then
        # Reactivate current theme
        "$_LP_THEME_ACTIVATE_FUNCTION"
        prompt_on
    else
        # Set default theme if no theme set
        lp_theme default
    fi
621
}
622

623
624
625
626
627
628
629
630
#####################
# Utility Functions #
#####################

# Remove all colors and escape characters of the given string and return a pure text
_lp_as_text() {
    # Remove all terminal sequences that we wrapped with $_LP_OPEN_ESC and
    # $_LP_CLOSE_ESC.
Mark Vander Stel's avatar
Mark Vander Stel committed
631
    printf '%s' "$1" | sed "-$_LP_SED_EXTENDED" "s,$_LP_CLEAN_ESC,,g"
632
633
634
}

# Store $2 (or $?) as a true/false value in variable named $1
635
# Deprecated since v2.0.
636
_lp_bool() {
637
    local res="${2:-$?}"
638
    if (( res )); then
Mark Vander Stel's avatar
Mark Vander Stel committed
639
        eval "$1=false"
640
    else
Mark Vander Stel's avatar
Mark Vander Stel committed
641
        eval "$1=true"
642
    fi
Mark Vander Stel's avatar
Mark Vander Stel committed
643
    return "$res"
644
645
}

646
647
648
649
650
651
652
653
654
655
656
_lp_color_map() {
    # Default scale: 0..100
    # Custom scale: 0..$2
    local -i scale value
    scale=${2:-100}
    if (( $1 >= scale )); then
      value=scale-1
    elif (( $1 < 0 )); then
      value=0
    else
      value=$1
657
    fi
658
    # Transform the value to a 0..${#COLOR_MAP} scale
659
    ret="${LP_COLORMAP[_LP_FIRST_INDEX+value*${#LP_COLORMAP[*]}/scale]}"
660
661
}

662
# Return true if the input is the name of a function.
663
664
665
666
667
668
669
670
__lp_is_function() {
    if (( _LP_SHELL_bash )); then
        [[ $(LC_ALL=C \type -t "$1") == function ]]
    else
        [[ $(LC_ALL=C \type -w "$1") == *function ]]
    fi
}

671
# Count the number of lines in the input string. A faster substitute for 'wc -l'.
672
673
674
__lp_line_count() {
  local var="${1//[!$'\n']}"
  count=${#var}
675
}
676

677
678
679
680
681
682
__lp_hostname_hash() {
    # cksum is separated with tab on SunOS, space on others
    local cksum="$(hostname | cksum)"
    lp_hostname_hash=${cksum%%[$' \t']*}
}

683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
__lp_floating_scale() {
    local integer decimal=0 scale=$(( ${#2} - 1 ))
    integer=${1%\.*}

    if [[ -n ${1//[!\.]} ]]; then
        decimal=${1#*\.}
        decimal=${decimal:0:$scale}

        while (( ${#decimal} < scale )); do
            decimal+='0'
        done

        while [[ ${decimal:0:1} == '0' ]]; do
            decimal=${decimal:1}
        done
    fi

    ret=$(( integer * $2 + decimal ))
}

703
# Return $PWD with $HOME at the start replaced by "~".
704
__lp_pwd_tilde() {  # [path]
705
706
    # Needs to be in a variable, as different versions of Bash treat '~' in a
    # substitution differently
Mark Vander Stel's avatar
Mark Vander Stel committed
707
    local _path="${1:-$PWD}" tilde="~"
708
    lp_pwd_tilde="${_path/#$HOME/$tilde}"
709
710
}

711
# insert a space on the right
712
# Deprecated since v2.0.
713
714
715
716
717
_lp_sr() {
    [[ -n "$1" ]] && echo -nE "$1 "
}

# insert a space on the left
718
# Deprecated since v2.0.
719
720
721
722
_lp_sl() {
    [[ -n "$1" ]] && echo -nE " $1"
}

723
# insert two spaces, before and after
724
# Deprecated since v2.0.
725
726
727
728
_lp_sb() {
    [[ -n "$1" ]] && echo -nE " $1 "
}

729
730
731
732
733
# Generates a terminal escape sequence to format the terminal.
lp_terminal_format() {  # fg, bg, bold, underline, fallback_fg, fallback_bg
    lp_terminal_format=
    (( LP_ENABLE_COLOR )) || return 2

734
735
736
737
    local af_color ab_color fg bg previous_af_color
    fg=$1
    bg=${2:-"-1"}
    previous_af_color=${_lp_last_af_color-}
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787

    lp_terminal_format=${_LP_OPEN_ESC}${_LP_TI_RESET}

    if (( $fg >= _LP_TI_COLORS )) && [[ -n ${5-} ]]; then
        _lp_last_af_color=$5
    elif (( $fg == -2 )); then
        :  # do nothing, _lp_last_af_color already correct
    elif (( $fg == -3 )); then
        _lp_last_af_color=$_lp_last_ab_color
    elif (( $fg >= 0 )); then
        _lp_last_af_color=$fg
    else  # -1
        _lp_last_af_color=-1
    fi

    if (( ${_lp_last_af_color:-"-1"} >= 0 )); then
        __lp_foreground_color "$_lp_last_af_color" && lp_terminal_format+=$af_color
    fi

    if (( $bg >= _LP_TI_COLORS )) && [[ -n ${6-} ]]; then
        _lp_last_ab_color=$6
    elif (( $bg == -2 )); then
        :  # do nothing, _lp_last_ab_color already correct
    elif (( $bg == -3 )); then
        _lp_last_ab_color=$previous_af_color
    elif (( $bg >= 0 )); then
        _lp_last_ab_color=$bg
    else  # -1
        _lp_last_ab_color=-1
    fi

    if (( ${_lp_last_ab_color:-"-1"} >= 0 )); then
        __lp_background_color "$_lp_last_ab_color" && lp_terminal_format+=$ab_color
    fi

    # It turns out there are sequences to reset bold and underline to normal
    # (\E[22m and \E[24m in xterm), but they aren't universally supported. This
    # means we must reset to all defaults then enable if they are wanted.
    # Explicit is safer anyway.
    if (( ${3:-0} )); then
        lp_terminal_format+=$_LP_TI_BOLD
    fi

    if (( ${4:-0} )); then
        lp_terminal_format+=$_LP_TI_UNDERLINE
    fi

    lp_terminal_format+=$_LP_CLOSE_ESC
}

788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# Get a list of themes currently loaded. Looks for functions matching
# _lp_<theme>_theme_prompt().
__lp_theme_list() {
    lp_theme_list=()

    local -a _functions
    if (( _LP_SHELL_zsh )); then
        _functions=( "${(ko)functions[@]}" )
    else
        local IFS=$'\n'
        _functions=( $(declare -F) )
    fi

    local function
    for function in "${_functions[@]}"; do
        if [[ $function == *_lp_*_theme_prompt ]]; then
            function=${function#*_lp_}
            lp_theme_list+=("${function%_theme_prompt}")
        fi
    done
}

__lp_theme_bash_complete() {
    COMPREPLY=()
    local -a lp_theme_list
813
814
    local theme partial_theme
    partial_theme=${2-}
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829

    __lp_theme_list

    for theme in "${lp_theme_list[@]}"; do
        [[ -n $partial_theme && $theme != "$partial_theme"* ]] && continue
        COMPREPLY+=("$theme")
    done
}

__lp_theme_zsh_complete() {
    local -a lp_theme_list
    __lp_theme_list
    _describe 'theme' lp_theme_list
}

830
831
832
833
##########################
# Working Directory Path #
##########################

834
__lp_get_unique_directory() {
Mark Vander Stel's avatar
Mark Vander Stel committed
835
    local directory="${1##*/}" root="${1%/*}"
836
837
    local -a matching
    local -i i
838
839
    for (( i=1; i < ${#directory}; i++ )); do
        lp_unique_directory=${directory:0:$i}
840
        matching=("${root}/${lp_unique_directory}"*/)
841
        if (( ${#matching[@]} == 1 )); then
842
843
844
845
846
847
            return 0
        fi
    done

    return 1
}
848

849
850
851
852
853
854
855
856
__lp_end_path_left_shortening() {
    if (( is_shortening )); then
        shortened_path_length+=${#separator}
        if (( shortened_path_length < unshortened_path_length )); then
            lp_path_format+="${shortened_directory_format}${LP_MARK_SHORTEN_PATH}"
            # This indescriminate adding of a separator can sometimes mean the path
            # is slightly longer than it should be, but it is more clear.
            lp_path_format+="${separator_format}${separator}"
857
            lp_path+="${LP_MARK_SHORTEN_PATH}/"
Luc Didry's avatar
Luc Didry committed
858
        else
859
860
            lp_path+=$unshortened_path_shorten_string
            lp_path_format+=$unshortened_path_format_shorten_string
861
862
863
864
865
            shortened_path_length=$unshortened_path_length
        fi
        is_shortening=0
    fi
}
866

867
868
869
870
871
# methods:
#   truncate_chars_from_path_left
#   truncate_chars_from_dir_middle
#   truncate_chars_from_dir_right
#   truncate_chars_to_unique_dir
872
#   truncate_to_last_dir
873
_lp_path_format() {
Mark Vander Stel's avatar
Mark Vander Stel committed
874
875
876
877
878
879
    local path_format="${1-$LP_COLOR_PATH}"
    local last_directory_format="${2:-$path_format}"
    local vcs_root_format="${3:-$last_directory_format}"
    local shortened_directory_format="${4:-$path_format}"
    local separator="${5-"/"}"
    local separator_format="${6-}"
880

881
882
    lp_path=
    lp_path_format=
883

884
885
    local ret

886
    local lp_pwd_tilde
887
    __lp_pwd_tilde
Mark Vander Stel's avatar
Mark Vander Stel committed
888
    local display_path="$lp_pwd_tilde"
889

Mark Vander Stel's avatar
Mark Vander Stel committed
890
    local -i path_length="${#display_path}"
891

892
893
894
895
896
    local lp_vcs_root lp_vcs_type
    local vcs_root_directory=
    if (( LP_PATH_VCS_ROOT )) && _lp_find_vcs; then
        __lp_pwd_tilde "$lp_vcs_root"
        vcs_root_directory=$lp_pwd_tilde
897
898
    fi

899
900
901
902
903
904
905
906
    if [[ $path_length == 1 || $LP_PATH_METHOD == "truncate_to_last_dir" ]]; then
        if [[ $path_length > 1 ]]; then
            lp_path=${display_path##*/}
        else
            # only root or home to show
            lp_path=$display_path
        fi

907
908
        __lp_escape "$lp_path"

909
        if [[ $display_path == $vcs_root_directory ]]; then
910
            lp_path_format="${vcs_root_format}${ret}"
911
        else
912
            lp_path_format="${last_directory_format}${ret}"
913
914
915
        fi
        return
    else
916
917
918
919
920
921
922
        if [[ $separator != "/" && ${display_path:0:1} == "/" ]]; then
            # The root directory ('/') becomes a directory name instead of a leading separator
            # Add one to account for the first / needing to be both replaced and shown
            path_length+=1
        fi
        if [[ ${#separator} > 1 ]]; then
            # Add length to account for multichar separators
923
            local slash_count="${display_path//[!\/]}"
924
925
            path_length+=$(( ${#slash_count} * ( ${#separator} - 1 ) ))
        fi
926
    fi
927

928
    local path_to_proccess="${display_path}/" current_path="" current_directory="" lp_unique_directory
929

930
    local -i max_len=$(( ${COLUMNS:-80} * LP_PATH_LENGTH / 100 )) directory_count=0 needed_length
Mark Vander Stel's avatar
Mark Vander Stel committed
931
    local -i shortened_path_length="$path_length" is_shortening=0 unshortened_path_length
932
    local unshortened_path_shorten_string unshortened_path_format_shorten_string shortened_path
933

934
    while [[ -n $path_to_proccess ]]; do
935

936
937
938
939
940
941
942
943
        if [[ ${path_to_proccess:0:1} == "/" ]]; then
            # Start of root
            current_directory="/"
        else
            current_directory=${path_to_proccess%%/*}
            if [[ -n $current_path && $current_path != "/" ]]; then
                current_path+="/"
            fi
Luc Didry's avatar
Luc Didry committed
944
        fi
945

946
        directory_count+=1
947
948
949
950
        current_path+=${current_directory}
        path_to_proccess=${path_to_proccess#*/}

        if [[ $current_path == $vcs_root_directory ]]; then
951
            __lp_end_path_left_shortening
952
            # No shortening
953
            lp_path+=$current_directory
954
955
            __lp_escape "$current_directory"
            lp_path_format+="${vcs_root_format}${ret}"
956
        elif [[ -z $path_to_proccess ]]; then
957
            __lp_end_path_left_shortening
958
            # Last directory
959
            lp_path+=$current_directory
960
961
            __lp_escape "$current_directory"
            lp_path_format+="${last_directory_format}${ret}"
962
963
        elif (( LP_ENABLE_SHORTEN_PATH && directory_count > LP_PATH_KEEP \
            && ( shortened_path_length > max_len || ( shortened_path_length >= max_len && is_shortening ) ) )); then
964
965
966
967

            if [[ $LP_PATH_METHOD == "truncate_chars_to_unique_dir" ]] && \
                __lp_get_unique_directory "$current_path"; then

968
                lp_path+=$lp_unique_directory
969
970
                __lp_escape "$lp_unique_directory"
                lp_path_format+="${shortened_directory_format}${ret}"
971
                shortened_path_length=$(( shortened_path_length - ${#current_directory} + ${#lp_unique_directory} ))
972
973
974
975
976
977
978
            elif [[ $LP_PATH_METHOD == "truncate_chars_from_path_left" ]]; then
                # The only way to know if this consecutive directory shortening
                # will actually shorten the path is to both do it and do not and
                # compare at the end.

                if (( ! is_shortening )); then
                    unshortened_path_shorten_string=
979
                    unshortened_path_format_shorten_string=
980
981
982
983
                    unshortened_path_length=$shortened_path_length
                    shortened_path_length+=${#LP_MARK_SHORTEN_PATH}
                fi
                needed_length=$(( shortened_path_length - max_len ))
984

985
986
                unshortened_path_shorten_string+="${current_directory}/"
                unshortened_path_format_shorten_string+="${path_format}${current_directory}${separator_format}${separator}"
987
988

                if (( needed_length >= ${#current_directory} )); then
989
990
991
992
                    # One directory was not enough, need to shorten more.
                    # Shorten by current directory length plus separator.
                    shortened_path_length=$(( shortened_path_length - ${#current_directory} - ${#separator} ))
                    is_shortening=1
993
                else
994
995
                    # Do not need to check if the shortened version is actually shorter.
                    # If we got to here, it wasn't a forced ending, which means it is.
996
                    shortened_path_length=$(( shortened_path_length - needed_length ))
997

998
999
                    shortened_path="${LP_MARK_SHORTEN_PATH}${current_directory:$needed_length}"
                    lp_path+=$shortened_path
1000
                    __lp_escape "$shortened_path"
For faster browsing, not all history is shown. View entire blame