liquidprompt 105 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
# Do not exit if '--no-activate' flag was passed, as it overrides this check
Simon Chopin's avatar
Simon Chopin committed
25
[ "x${-##*i}" = "x$-" ] || [ -z "${TERM-}" ] || [ "x${TERM-}" = xdumb ] && [ "x${TERM-}" = xunknown ] && [ "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

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
__lp_use_bash_preexec() {
    # If https://github.com/rcaloras/bash-preexec is present, we can (and should, because it interferes with
    # PROMPT_COMMAND and DEBUG) use the zsh-hook like behavior it provides.
    [[ "${__bp_imported-}" == "defined" ]]
}

__lp_array_contains() {
    local target="$1"
    shift

    for element; do
        if [[ $element == "$target" ]]; then
            return 0
        fi
    done
    return 1
}

nojhan's avatar
nojhan committed
111
###############
nojhan's avatar
nojhan committed
112
# OS specific #
nojhan's avatar
nojhan committed
113
114
###############

115
# LP_OS detection, default to Linux
Mark Vander Stel's avatar
Mark Vander Stel committed
116
case "$(uname)" in
Olivier Mengué's avatar
Olivier Mengué committed
117
118
    FreeBSD)   LP_OS=FreeBSD ;;
    DragonFly) LP_OS=FreeBSD ;;
Kim Lidström's avatar
Kim Lidström committed
119
    OpenBSD)   LP_OS=OpenBSD ;;
Ludovic Rousseau's avatar
Ludovic Rousseau committed
120
    Darwin)    LP_OS=Darwin  ;;
Olivier Mengué's avatar
Olivier Mengué committed
121
122
    SunOS)     LP_OS=SunOS   ;;
    *)         LP_OS=Linux   ;;
123
esac
124

125
126
127
128
129
# Extended regexp patterns for sed
# GNU/BSD sed
_LP_SED_EXTENDED=r
[[ "$LP_OS" = Darwin ]] && _LP_SED_EXTENDED=E

nojhan's avatar
nojhan committed
130
131
132
133
#################
# CONFIGURATION #
#################

134
# Load the user configuration and setup defaults.
135
__lp_source_config() {
136

137
    local lp_terminal_format af_color= ab_color=
138

139
140
141
    # 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.
142
    local BOLD="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${_LP_CLOSE_ESC}"
143

nojhan's avatar
nojhan committed
144
    # Foreground colors
145
    __lp_foreground_color 0
146
    local BLACK="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
147
    local BOLD_GRAY="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
148

149
    __lp_foreground_color 1
150
    local RED="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
151
152
153
    local BOLD_RED="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
    __lp_foreground_color 0
    __lp_background_color 1
154
    local WARN_RED="${_LP_OPEN_ESC}${af_color}${ab_color}${_LP_CLOSE_ESC}"
155
156
157
158
    __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}"
159

160
    __lp_foreground_color 2
161
    local GREEN="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
162
    local BOLD_GREEN="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
163

164
    __lp_foreground_color 3
165
    local YELLOW="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
166
    local BOLD_YELLOW="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
167

168
    __lp_foreground_color 4
169
    local BLUE="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
170
    local BOLD_BLUE="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
171

172
    __lp_foreground_color 5
173
    local PURPLE="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
nojhan's avatar
nojhan committed
174
    local MAGENTA="${PURPLE}"
175
    local PINK="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
nojhan's avatar
nojhan committed
176
177
    local BOLD_PURPLE="${PINK}"
    local BOLD_MAGENTA="${PINK}"
178

179
    __lp_foreground_color 6
180
    local CYAN="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
181
    local BOLD_CYAN="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
182

183
    __lp_foreground_color 7
184
    local WHITE="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
185
    local BOLD_WHITE="${_LP_OPEN_ESC}${_LP_TI_BOLD-}${af_color}${_LP_CLOSE_ESC}"
186

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

190
191
192
193
194
    # 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 ))"
195
    LP_COLOR_HOST_HASH="${_LP_OPEN_ESC}${af_color}${_LP_CLOSE_ESC}"
196

197

Olivier Mengué's avatar
Olivier Mengué committed
198
    # Default values (globals)
199
    LP_TIME_FORMAT=${LP_TIME_FORMAT:-"%H:%M:%S"}
200
    LP_BATTERY_THRESHOLD=${LP_BATTERY_THRESHOLD:-75}
201
    LP_LOAD_THRESHOLD=${LP_LOAD_THRESHOLD:-0.60}
202
    LP_LOAD_CAP=${LP_LOAD_CAP:-2.0}
203
    LP_TEMP_THRESHOLD=${LP_TEMP_THRESHOLD:-60}
Markus Dreseler's avatar
Markus Dreseler committed
204
    LP_RUNTIME_THRESHOLD=${LP_RUNTIME_THRESHOLD:-2}
205
    LP_RUNTIME_BELL_THRESHOLD=${LP_RUNTIME_BELL_THRESHOLD:-10}
206
207
    LP_PATH_LENGTH=${LP_PATH_LENGTH:-35}
    LP_PATH_KEEP=${LP_PATH_KEEP:-2}
208
    LP_PATH_CHARACTER_KEEP=${LP_PATH_CHARACTER_KEEP:-3}
209
    LP_PATH_METHOD=${LP_PATH_METHOD:-truncate_chars_from_path_left}
210
    LP_PATH_VCS_ROOT=${LP_PATH_VCS_ROOT:-1}
211
    LP_HOSTNAME_ALWAYS=${LP_HOSTNAME_ALWAYS:-0}
212
    LP_USER_ALWAYS=${LP_USER_ALWAYS:-1}
213
    LP_PERCENTS_ALWAYS=${LP_PERCENTS_ALWAYS:-1}
214
    LP_PS1=${LP_PS1:-""}
nojhan's avatar
nojhan committed
215
    LP_PS1_PREFIX=${LP_PS1_PREFIX:-""}
Brendan Fahy's avatar
Brendan Fahy committed
216
    LP_PS1_POSTFIX=${LP_PS1_POSTFIX:-""}
217
    LP_MARK_KUBECONTEXT=${LP_MARK_KUBECONTEXT:-"⎈"}
218
219
    LP_DELIMITER_KUBECONTEXT_SUFFIX=${LP_DELIMITER_KUBECONTEXT_SUFFIX:-""}
    LP_DELIMITER_KUBECONTEXT_PREFIX=${LP_DELIMITER_KUBECONTEXT_PREFIX:-""}
220
221
222
223

    LP_ENABLE_PERM=${LP_ENABLE_PERM:-1}
    LP_ENABLE_SHORTEN_PATH=${LP_ENABLE_SHORTEN_PATH:-1}
    LP_ENABLE_PROXY=${LP_ENABLE_PROXY:-1}
224
    LP_ENABLE_TEMP=${LP_ENABLE_TEMP:-1}
225
    LP_ENABLE_JOBS=${LP_ENABLE_JOBS:-1}
226
    LP_ENABLE_DETACHED_SESSIONS=${LP_ENABLE_DETACHED_SESSIONS:-1}
227
228
229
230
    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
231
    LP_ENABLE_FOSSIL=${LP_ENABLE_FOSSIL:-1}
232
    LP_ENABLE_HG=${LP_ENABLE_HG:-1}
233
    LP_HG_COMMAND=${LP_HG_COMMAND:-hg}
Clément MATHIEU's avatar
Clément MATHIEU committed
234
    LP_ENABLE_BZR=${LP_ENABLE_BZR:-1}
235
    LP_ENABLE_TIME=${LP_ENABLE_TIME:-0}
236
    LP_TIME_ANALOG=${LP_TIME_ANALOG:-0}
Austen Adler's avatar
Austen Adler committed
237
    LP_ENABLE_RUNTIME=${LP_ENABLE_RUNTIME:-1}
238
    LP_ENABLE_RUNTIME_BELL=${LP_ENABLE_RUNTIME_BELL:-0}
239
    LP_ENABLE_VIRTUALENV=${LP_ENABLE_VIRTUALENV:-1}
240
241
242
    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
243
    LP_ENABLE_TERRAFORM=${LP_ENABLE_TERRAFORM:-0}
244
    LP_ENABLE_SCLS=${LP_ENABLE_SCLS:-1}
245
    LP_ENABLE_AWS_PROFILE=${LP_ENABLE_AWS_PROFILE:-1}
246
    LP_ENABLE_VCS_ROOT=${LP_ENABLE_VCS_ROOT:-0}
nojhan's avatar
nojhan committed
247
    LP_ENABLE_TITLE=${LP_ENABLE_TITLE:-0}
248
    LP_ENABLE_SCREEN_TITLE=${LP_ENABLE_SCREEN_TITLE:-0}
Mark Vander Stel's avatar
Mark Vander Stel committed
249
    LP_ENABLE_TITLE_COMMAND=${LP_ENABLE_TITLE_COMMAND:-1}
250
    LP_ENABLE_SSH_COLORS=${LP_ENABLE_SSH_COLORS:-0}
Erik M Jacobs's avatar
Erik M Jacobs committed
251
    LP_ENABLE_FQDN=${LP_ENABLE_FQDN:-0}
252
    LP_DISABLED_VCS_PATHS=( ${LP_DISABLED_VCS_PATHS[@]+"${LP_DISABLED_VCS_PATHS[@]}"} )
253
    LP_ENABLE_SUDO=${LP_ENABLE_SUDO:-0}
254
    LP_ENABLE_COLOR=${LP_ENABLE_COLOR:-1}
255
    LP_ENABLE_ERROR=${LP_ENABLE_ERROR:-1}
256
    LP_ENABLE_DIRSTACK=${LP_ENABLE_DIRSTACK:-0}
257
    LP_ENABLE_KUBECONTEXT=${LP_ENABLE_KUBECONTEXT:-0}
258
    LP_ENABLE_KUBE_NAMESPACE=${LP_ENABLE_KUBE_NAMESPACE:-0}
259

260
    LP_MARK_DEFAULT="${LP_MARK_DEFAULT:-$_LP_MARK_SYMBOL}"
261
262
263
264
265
266
267
268
    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
269
    LP_MARK_VCSH="${LP_MARK_VCSH:-"|"}"
270
271
272
273
274
275
276
277
    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
278
    LP_MARK_PREFIX="${LP_MARK_PREFIX:-" "}"
279
    LP_MARK_PERM="${LP_MARK_PERM:-":"}"
280
    LP_MARK_DIRSTACK="${LP_MARK_DIRSTACK:-"⚞"}"
281

282
283
    LP_COLOR_PATH=${LP_COLOR_PATH:-$NO_COL}
    lp_terminal_format 8 -1 0 0 -1
284
285
    LP_COLOR_PATH_SEPARATOR=${LP_COLOR_PATH_SEPARATOR:-$lp_terminal_format}
    LP_COLOR_PATH_SHORTENED=${LP_COLOR_PATH_SHORTENED:-$lp_terminal_format}
286
    lp_terminal_format -1 -1 1 0
287
288
    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}
289
290
291
292
293
294
    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}
295
    LP_COLOR_MARK=${LP_COLOR_MARK:-$BOLD}
296
    LP_COLOR_MARK_ROOT=${LP_COLOR_MARK_ROOT:-$BOLD_RED}
Olivier Mengué's avatar
Olivier Mengué committed
297
    LP_COLOR_MARK_SUDO=${LP_COLOR_MARK_SUDO:-$LP_COLOR_MARK_ROOT}
298
299
    LP_COLOR_USER_LOGGED=${LP_COLOR_USER_LOGGED:-""}
    LP_COLOR_USER_ALT=${LP_COLOR_USER_ALT:-$BOLD}
300
    LP_COLOR_USER_ROOT=${LP_COLOR_USER_ROOT:-$BOLD_YELLOW}
301
    LP_COLOR_HOST=${LP_COLOR_HOST:-""}
nojhan's avatar
nojhan committed
302
    LP_COLOR_SSH=${LP_COLOR_SSH:-$BLUE}
303
    LP_COLOR_SU=${LP_COLOR_SU:-$BOLD_YELLOW}
304
    LP_COLOR_TELNET=${LP_COLOR_TELNET:-$WARN_RED}
305
306
    LP_COLOR_X11_ON=${LP_COLOR_X11_ON:-$GREEN}
    LP_COLOR_X11_OFF=${LP_COLOR_X11_OFF:-$YELLOW}
307
308
309
310
    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
311
    LP_COLOR_COMMITS_BEHIND=${LP_COLOR_COMMITS_BEHIND:-$BOLD_RED}
312
313
314
315
316
317
318
    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}
319
    LP_COLOR_IN_MULTIPLEXER=${LP_COLOR_IN_MULTIPLEXER:-$BOLD_BLUE}
Markus Dreseler's avatar
Markus Dreseler committed
320
    LP_COLOR_RUNTIME=${LP_COLOR_RUNTIME:-$YELLOW}
321
    LP_COLOR_VIRTUALENV=${LP_COLOR_VIRTUALENV:-$CYAN}
Ken Crowell's avatar
Ken Crowell committed
322
    LP_COLOR_TERRAFORM=${LP_COLOR_TERRAFORM:-$PINK}
323
    LP_COLOR_DIRSTACK=${LP_COLOR_DIRSTACK:-$BOLD_YELLOW}
324
    LP_COLOR_KUBECONTEXT=${LP_COLOR_KUBECONTEXT:-$CYAN}
325
    LP_COLOR_AWS_PROFILE=${LP_COLOR_AWS_PROFILE:-$YELLOW}
326

327
328
    LP_COLORMAP=( ${LP_COLORMAP[@]+"${LP_COLORMAP[@]}"} )
    if [[ ${#LP_COLORMAP[@]} == 0 ]]; then
329
330
331
332
333
334
335
336
337
338
339
340
341
        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
342

343
    _LP_LINUX_POWERSUPPLY_PATH="/sys/class/power_supply"
344

345
346
    # Debugging flags
    LP_DEBUG_TIME=${LP_DEBUG_TIME:-0}
nojhan's avatar
nojhan committed
347

Mark Vander Stel's avatar
Mark Vander Stel committed
348
349
350
    if [[ ${1-} == --no-config ]]; then
        return
    fi
351

352
353
    # Default config file may be the XDG standard ~/.config/liquidpromptrc,
    # but heirloom dotfile has priority.
354
355
    local -a configfiles
    configfiles=("$HOME/.liquidpromptrc" "${XDG_CONFIG_HOME:-"$HOME/.config"}/liquidpromptrc")
Mark Vander Stel's avatar
Mark Vander Stel committed
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371

    # 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
372

373
    # Deprecations and compatibility shims
374

375
376
377
    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

378
        (( _LP_SHELL_zsh )) && setopt local_options && setopt sh_word_split
Mark Vander Stel's avatar
Mark Vander Stel committed
379
380
381
        local _path IFS=:
        for _path in $LP_DISABLED_VCS_PATH; do
            LP_DISABLED_VCS_PATHS+=("$_path")
382
383
384
        done
    fi

385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
    # 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
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

    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
429
430
}

431
# Initialize features based on the user config.
432
lp_activate() {
433
    if (( _LP_SHELL_bash )); then
434
        complete -F __lp_theme_bash_complete lp_theme
435
436
437
    else # zsh
        # For ZSH, autoload required functions
        autoload -Uz add-zsh-hook
Olivier Mengué's avatar
Olivier Mengué committed
438

439
440
        # Enable the autocomplete if the autocomplete system is initialized.
        __lp_is_function compdef && compdef __lp_theme_zsh_complete lp_theme
441
    fi
Olivier Mengué's avatar
Olivier Mengué committed
442

Mark Vander Stel's avatar
Mark Vander Stel committed
443
444
445
    # Disable hooks that we don't need if features will be disabled.
    __lp_disable_hooks

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
    # 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
474
            echo "liquidprompt: terminal '${TERM-}' does not support foreground colors" >&2
475
476
477
478
479
480
481
482
483
484
        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
485
            echo "liquidprompt: terminal '${TERM-}' does not support background colors" >&2
486
487
488
489
490
491
        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
492
    __lp_source_config "$@"
Olivier Mengué's avatar
Olivier Mengué committed
493

494
495
496
    # Disable feature if the tool is not installed
    _lp_require_tool()
    {
Mark Vander Stel's avatar
Mark Vander Stel committed
497
        (( LP_ENABLE_$1 )) && { command -v "$2" >/dev/null || eval LP_ENABLE_$1=0 ; }
498
    }
Olivier Mengué's avatar
Olivier Mengué committed
499

500
501
502
    _lp_require_tool GIT git
    _lp_require_tool SVN svn
    _lp_require_tool FOSSIL fossil
503
    _lp_require_tool HG "$LP_HG_COMMAND"
504
    _lp_require_tool BZR bzr
505

506
507
508
509
510
511
    _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)

512
513
    if [[ "$LP_OS" = Darwin ]]; then
        _lp_require_tool BATT pmset
514
515
    elif (( LP_ENABLE_BATT )); then
        __lp_battery_detect || LP_ENABLE_BATT=0
516
    fi
517

518
    _lp_require_tool KUBECONTEXT kubectl
Ken Crowell's avatar
Ken Crowell committed
519
    _lp_require_tool TERRAFORM terraform
520

521
    unset -f _lp_require_tool
522

523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
    # 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

538
539
540
541
    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
542

543
544
545
    # Use standard path symbols inside Midnight Commander
    [[ -n "${MC_SID-}" ]] && LP_ENABLE_SHORTEN_PATH=0

546
547
    # If we are running in a terminal multiplexer, special title escapes
    if _lp_multiplexer; then
548
        (( LP_ENABLE_TITLE = LP_ENABLE_TITLE && LP_ENABLE_SCREEN_TITLE ))
549
        LP_TITLE_OPEN=$'\Ek'
550
        LP_TITLE_CLOSE=$'\E\\'
551
    else
552
553
        LP_TITLE_OPEN=$'\E]0;'
        LP_TITLE_CLOSE=$'\a'
554
    fi
555

556
    [[ "_${TERM-}" == _linux* ]] && LP_ENABLE_TITLE=0
557

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

561
562
563
564
565
566
567
568
569
570
571
572
    # 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
573

574
575
576
577
    ###############
    # Who are we? #
    ###############

578
    _lp_user
579
    local -i user="$?"
580
581

    if (( user < 2 )); then  # if user is not root
582
        # "sudo -n" is only supported from sudo 1.7.0
583
584
585
586
        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
587
        fi
588
589
590
591
592
593

        if (( user == 1 )); then
            LP_COLOR_USER=$LP_COLOR_USER_ALT
        else
            LP_COLOR_USER=$LP_COLOR_USER_LOGGED
        fi
594
    else # root!
595
        LP_ENABLE_SUDO=0
596
        if (( ! LP_ENABLE_VCS_ROOT )); then
597
            LP_DISABLED_VCS_PATHS=("/")
598
        fi
599

600
601
        LP_MARK_DEFAULT='#'

602
603
604
        LP_COLOR_MARK=$LP_COLOR_MARK_ROOT
        LP_COLOR_PATH=$LP_COLOR_PATH_ROOT
        LP_COLOR_USER=$LP_COLOR_USER_ROOT
605
    fi
606
607
608
609
610
611
612
613

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

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

617
618
619
    if (( LP_ENABLE_LOAD )); then
        # Find and save the number of CPUs
        __lp_cpu_count
620
621
622
623
624
625
626
627
628
629
630
631
632

        # 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
633
634
    fi

635
636
637
638
639
640
641
642
    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
643
}
644

645
646
647
648
649
650
651
652
#####################
# 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
653
    printf '%s' "$1" | sed "-$_LP_SED_EXTENDED" "s,$_LP_CLEAN_ESC,,g"
654
655
656
}

# Store $2 (or $?) as a true/false value in variable named $1
657
# Deprecated since v2.0.
658
_lp_bool() {
659
    local res="${2:-$?}"
660
    if (( res )); then
Mark Vander Stel's avatar
Mark Vander Stel committed
661
        eval "$1=false"
662
    else
Mark Vander Stel's avatar
Mark Vander Stel committed
663
        eval "$1=true"
664
    fi
Mark Vander Stel's avatar
Mark Vander Stel committed
665
    return "$res"
666
667
}

668
669
670
671
672
673
674
675
676
677
678
_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
679
    fi
680
    # Transform the value to a 0..${#COLOR_MAP} scale
681
    ret="${LP_COLORMAP[_LP_FIRST_INDEX+value*${#LP_COLORMAP[*]}/scale]}"
682
683
}

684
# Return true if the input is the name of a function.
685
686
687
688
689
690
691
692
__lp_is_function() {
    if (( _LP_SHELL_bash )); then
        [[ $(LC_ALL=C \type -t "$1") == function ]]
    else
        [[ $(LC_ALL=C \type -w "$1") == *function ]]
    fi
}

693
# Count the number of lines in the input string. A faster substitute for 'wc -l'.
694
695
696
__lp_line_count() {
  local var="${1//[!$'\n']}"
  count=${#var}
697
}
698

699
700
701
702
703
704
__lp_hostname_hash() {
    # cksum is separated with tab on SunOS, space on others
    local cksum="$(hostname | cksum)"
    lp_hostname_hash=${cksum%%[$' \t']*}
}

705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
__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 ))
}

725
# Return $PWD with $HOME at the start replaced by "~".
726
__lp_pwd_tilde() {  # [path]
727
728
    # 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
729
    local _path="${1:-$PWD}" tilde="~"
730
    lp_pwd_tilde="${_path/#$HOME/$tilde}"
731
732
}

733
# insert a space on the right
734
# Deprecated since v2.0.
735
736
737
738
739
_lp_sr() {
    [[ -n "$1" ]] && echo -nE "$1 "
}

# insert a space on the left
740
# Deprecated since v2.0.
741
742
743
744
_lp_sl() {
    [[ -n "$1" ]] && echo -nE " $1"
}

745
# insert two spaces, before and after
746
# Deprecated since v2.0.
747
748
749
750
_lp_sb() {
    [[ -n "$1" ]] && echo -nE " $1 "
}

751
752
753
754
755
# 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

756
757
758
759
    local af_color ab_color fg bg previous_af_color
    fg=$1
    bg=${2:-"-1"}
    previous_af_color=${_lp_last_af_color-}
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
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809

    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
}

810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
# 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
835
836
    local theme partial_theme
    partial_theme=${2-}
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851

    __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
}

852
853
854
855
##########################
# Working Directory Path #
##########################

856
__lp_get_unique_directory() {
Mark Vander Stel's avatar
Mark Vander Stel committed
857
    local directory="${1##*/}" root="${1%/*}"
858
859
    local -a matching
    local -i i
860
861
    for (( i=1; i < ${#directory}; i++ )); do
        lp_unique_directory=${directory:0:$i}
862
        matching=("${root}/${lp_unique_directory}"*/)
863
        if (( ${#matching[@]} == 1 )); then
864
865
866
867
868
869
            return 0
        fi
    done

    return 1
}
870

871
872
873
874
875
876
877
878
__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}"
879
            lp_path+="${LP_MARK_SHORTEN_PATH}/"
Luc Didry's avatar
Luc Didry committed
880
        else
881
882
            lp_path+=$unshortened_path_shorten_string
            lp_path_format+=$unshortened_path_format_shorten_string
883
884
885
886
887
            shortened_path_length=$unshortened_path_length
        fi
        is_shortening=0
    fi
}
888

889
890
891
892
893
# methods:
#   truncate_chars_from_path_left
#   truncate_chars_from_dir_middle
#   truncate_chars_from_dir_right
#   truncate_chars_to_unique_dir
894
#   truncate_to_last_dir
895
_lp_path_format() {
Mark Vander Stel's avatar
Mark Vander Stel committed
896
897
898
899
900
901
    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-}"
902

903
904
    lp_path=
    lp_path_format=
905

906
907
    local ret

908
    local lp_pwd_tilde
909
    __lp_pwd_tilde
Mark Vander Stel's avatar
Mark Vander Stel committed
910
    local display_path="$lp_pwd_tilde"
911

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

914
915
916
917
918
    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
919
920
    fi

921
922
923
924
925
926
927
928
    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

929
930
        __lp_escape "$lp_path"

931
        if [[ $display_path == $vcs_root_directory ]]; then
932
            lp_path_format="${vcs_root_format}${ret}"
933
        else
934
            lp_path_format="${last_directory_format}${ret}"
935
936
937
        fi
        return
    else
938
939
940
941
942
943
944
        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
945
            local slash_count="${display_path//[!\/]}"
946
947
            path_length+=$(( ${#slash_count} * ( ${#separator} - 1 ) ))
        fi
948
    fi
949

950
    local path_to_proccess="${display_path}/" current_path="" current_directory="" lp_unique_directory
951

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

956
    while [[ -n $path_to_proccess ]]; do
957

958
959
960
961
962
963
964
965
        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
966
        fi
967

968
        directory_count+=1
969
970
971
972
        current_path+=${current_directory}
        path_to_proccess=${path_to_proccess#*/}

        if [[ $current_path == $vcs_root_directory ]]; then
973
            __lp_end_path_left_shortening
974
            # No shortening
975
            lp_path+=$current_directory
976
977
            __lp_escape "$current_directory"
            lp_path_format+="${vcs_root_format}${ret}"
978
        elif [[ -z $path_to_proccess ]]; then
979
            __lp_end_path_left_shortening
980
            # Last directory
981
            lp_path+=$current_directory
982
983
            __lp_escape "$current_directory"
            lp_path_format+="${last_directory_format}${ret}"
984
985
        elif (( LP_ENABLE_SHORTEN_PATH && directory_count > LP_PATH_KEEP \
            && ( shortened_path_length > max_len || ( shortened_path_length >= max_len && is_shortening ) ) )); then
986
987
988
989

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

990
                lp_path+=$lp_unique_directory
991
992
                __lp_escape "$lp_unique_directory"
                lp_path_format+="${shortened_directory_format}${ret}"
993
                shortened_path_length=$(( shortened_path_length - ${#current_directory} + ${#lp_unique_directory} ))
994
995
996
997
998
999
1000
            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=
For faster browsing, not all history is shown. View entire blame