aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md20
-rwxr-xr-xfunctions/icons.zsh2
-rwxr-xr-xfunctions/vcs.zsh60
-rwxr-xr-xpowerlevel9k.zsh-theme12
-rwxr-xr-xtest/functions/icons.spec30
-rwxr-xr-xtest/segments/context.spec18
-rwxr-xr-xtest/segments/vcs-git.spec159
-rwxr-xr-xtest/segments/vcs-hg.spec15
8 files changed, 259 insertions, 57 deletions
diff --git a/README.md b/README.md
index 2b037bd0..33d787bb 100644
--- a/README.md
+++ b/README.md
@@ -124,7 +124,7 @@ The segments that are currently available are:
* [`symfony2_tests`](#symfony2_tests) - Show a ratio of test classes vs code classes for Symfony2.
* `symfony2_version` - Show the current Symfony2 version, if you are in a Symfony2-Project dir.
* **Python Segments:**
- * `virtualenv` - Your Python [VirtualEnv](https://virtualenv.pypa.io/en/latest/).
+ * [`virtualenv`](#virtualenv) - Your Python [VirtualEnv](https://virtualenv.pypa.io/en/latest/).
* [`anaconda`](#anaconda) - Your active [Anaconda](https://www.continuum.io/why-anaconda) environment.
* `pyenv` - Your active python version as reported by the first word of [`pyenv version`](https://github.com/yyuu/pyenv). Note that the segment is not displayed if that word is _system_ i.e. the segment is inactive if you are using system python.
* **Ruby Segments:**
@@ -410,10 +410,10 @@ Customizations available are:
|Default|Truncate whole directories from left. How many is defined by `POWERLEVEL9K_SHORTEN_DIR_LENGTH`|
|`truncate_absolute_chars`|Truncates an absolute number of characters from the left such that the number of characters that your path displays (with or without `POWERLEVEL9K_SHORTEN_DELIMITER`) is no more than `POWERLEVEL9K_SHORTEN_DIR_LENGTH` + the length of `POWERLEVEL9K_SHORTEN_DELIMITER` |
|`truncate_middle`|Truncates the middle part of a folder. E.g. you are in a folder named `~/MySuperProjects/AwesomeFiles/BoringOffice`, then it will truncated to `~/MyS..cts/Awe..les/BoringOffice`, if `POWERLEVEL9K_SHORTEN_DIR_LENGTH=3` is also set (controls the amount of characters to be left).|
-|`truncate_from_right`|Just leaves the beginning of a folder name untouched. E.g. your folders will be truncated like so: "/ro../Pr../office". How many characters will be untouched is controlled by `POWERLEVEL9K_SHORTEN_DIR_LENGTH`.|
-|`truncate_absolute`|Truncates everything exept the last few characters in the path. E.g. if you are in a folder named "~/Projects/powerlevel9k" and you have set `POWERLEVEL9K_SHORTEN_DIR_LENGTH=3`, you will get "..l9k".|
+|`truncate_from_right`|Just leaves the beginning of a folder name untouched. E.g. your folders will be truncated like so: `/ro../Pr../office`. How many characters will be untouched is controlled by `POWERLEVEL9K_SHORTEN_DIR_LENGTH`.|
+|`truncate_absolute`|Truncates everything exept the last few characters in the path. E.g. if you are in a folder named `~/Projects/powerlevel9k` and you have set `POWERLEVEL9K_SHORTEN_DIR_LENGTH=3`, you will get `..l9k`.|
|`truncate_to_last`|Truncates everything before the last folder in the path.|
-|`truncate_to_first_and_last|Truncate middle directories from the path. How many directories will be untouched is controlled by POWERLEVEL9K_SHORTER_DIR_LENGTH. E.g. if you are in a folder named "~/Projects/powerlevel9k" and you have set `POWERLEVEL9K_SHORTEN_DIR_LENGTH=1`, you will get "~/../powerlevel9k".||
+|`truncate_to_first_and_last`|Truncate middle directories from the path. How many directories will be untouched is controlled by `POWERLEVEL9K_SHORTEN_DIR_LENGTH`. E.g. if you are in a folder named `~/Projects/powerlevel9k` and you have set `POWERLEVEL9K_SHORTEN_DIR_LENGTH=1`, you will get `~/../powerlevel9k`.||
|`truncate_to_unique`|Parse all parent path components and truncate them to the shortest unique length. If you copy & paste the result to a shell, after hitting `TAB` it should expand to the original path unambiguously.|
|`truncate_with_package_name`|Search for a `package.json` or `composer.json` and prints the `name` field to abbreviate the directory path. The precedence and/or files could be set by `POWERLEVEL9K_DIR_PACKAGE_FILES=(package.json composer.json)`. If you have [jq](https://stedolan.github.io/jq/) installed, it will dramatically improve the speed of this strategy.|
|`truncate_with_folder_marker`|Search for a file that is specified by `POWERLEVEL9K_SHORTEN_FOLDER_MARKER` and truncate everything before that (if found, otherwise stop on $HOME and ROOT).|
@@ -468,9 +468,9 @@ The `disk_usage` segment will show the usage level of the partition that your cu
| Variable | Default Value | Description |
|----------|---------------|-------------|
-|POWERLEVEL9K_DISK_USAGE_ONLY_WARNING|false|Hide the segment except when usage levels have hit warning or critical levels.|
-|POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL|90|The usage level that triggers a warning state.|
-|POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL|95|The usage level that triggers a critical state.|
+|`POWERLEVEL9K_DISK_USAGE_ONLY_WARNING`|false|Hide the segment except when usage levels have hit warning or critical levels.|
+|`POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL`|90|The usage level that triggers a warning state.|
+|`POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL`|95|The usage level that triggers a critical state.|
##### host
@@ -725,6 +725,12 @@ you are using the [ZSH Line Editor](http://zsh.sourceforge.net/Doc/Release/Zsh-L
To hide the segment entirely when in `INSERT` mode, set `POWERLEVEL9K_VI_INSERT_MODE_STRING=''`
+##### virtualenv
+
+This segment shows your Python [VirtualEnv](https://virtualenv.pypa.io/en/latest/). To avoid
+VirtualEnvs activate command from interfering with Powerlevel9k, you should set
+`VIRTUAL_ENV_DISABLE_PROMPT=1` in your `~/.zshrc`.
+
#### Unit Test Ratios
The `symfony2_tests` and `rspec_stats` segments both show a ratio of "real"
diff --git a/functions/icons.zsh b/functions/icons.zsh
index d8661e6f..28cbb709 100755
--- a/functions/icons.zsh
+++ b/functions/icons.zsh
@@ -13,6 +13,7 @@
# Initialize the icon list according to the user's `POWERLEVEL9K_MODE`.
typeset -gAH icons
+() { # add scope to protect the users locale and not overwrite LC_CTYPE!
case $POWERLEVEL9K_MODE in
'flat'|'awesome-patched')
# Awesome-Patched Font required! See:
@@ -528,6 +529,7 @@ esac
if [[ "$POWERLEVEL9K_HIDE_BRANCH_ICON" == true ]]; then
icons[VCS_BRANCH_ICON]=''
fi
+}
# Safety function for printing icons
# Prints the named icon, or if that icon is undefined, the string name.
diff --git a/functions/vcs.zsh b/functions/vcs.zsh
index b99e7c86..cb53dd3e 100755
--- a/functions/vcs.zsh
+++ b/functions/vcs.zsh
@@ -6,61 +6,61 @@
# https://github.com/bhilburn/powerlevel9k
################################################################
-set_default POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY true
+set_default POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY false
function +vi-git-untracked() {
- # TODO: check git >= 1.7.2 - see function git_compare_version()
- local FLAGS
- FLAGS=('--porcelain')
+ [[ -z "${vcs_comm[gitdir]}" || "${vcs_comm[gitdir]}" == "." ]] && return
- if [[ "$POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY" == "false" ]]; then
- FLAGS+='--ignore-submodules=dirty'
- fi
+ # get the root for the current repo or submodule
+ local repoTopLevel="$(command git rev-parse --show-toplevel 2> /dev/null)"
+ # dump out if we're outside a git repository (which includes being in the .git folder)
+ [[ $? != 0 || -z $repoTopLevel ]] && return
- if [[ $(command git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' && \
- -n $(command git status ${FLAGS} | \grep -E '^\?\?' 2> /dev/null | tail -n1) ]]; then
- hook_com[unstaged]+=" $(print_icon 'VCS_UNTRACKED_ICON')"
- VCS_WORKDIR_HALF_DIRTY=true
- else
- VCS_WORKDIR_HALF_DIRTY=false
- fi
+ local untrackedFiles=$(command git ls-files --others --exclude-standard "${repoTopLevel}")
+
+ if [[ -z $untrackedFiles && "$POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY" == "true" ]]; then
+ untrackedFiles+=$(command git submodule foreach --quiet --recursive 'command git ls-files --others --exclude-standard')
+ fi
+
+ [[ -z $untrackedFiles ]] && return
+
+ hook_com[unstaged]+=" $(print_icon 'VCS_UNTRACKED_ICON')"
+ VCS_WORKDIR_HALF_DIRTY=true
}
function +vi-git-aheadbehind() {
- local ahead behind branch_name
+ local ahead behind
local -a gitstatus
- branch_name=$(command git symbolic-ref --short HEAD 2>/dev/null)
-
# for git prior to 1.7
- # ahead=$(command git rev-list origin/${branch_name}..HEAD | wc -l)
- ahead=$(command git rev-list "${branch_name}"@{upstream}..HEAD 2>/dev/null | wc -l)
+ # ahead=$(command git rev-list origin/${hook_com[branch]}..HEAD | wc -l)
+ ahead=$(command git rev-list --count "${hook_com[branch]}"@{upstream}..HEAD 2>/dev/null)
(( ahead )) && gitstatus+=( " $(print_icon 'VCS_OUTGOING_CHANGES_ICON')${ahead// /}" )
# for git prior to 1.7
- # behind=$(command git rev-list HEAD..origin/${branch_name} | wc -l)
- behind=$(command git rev-list HEAD.."${branch_name}"@{upstream} 2>/dev/null | wc -l)
+ # behind=$(command git rev-list HEAD..origin/${hook_com[branch]} | wc -l)
+ behind=$(command git rev-list --count HEAD.."${hook_com[branch]}"@{upstream} 2>/dev/null)
(( behind )) && gitstatus+=( " $(print_icon 'VCS_INCOMING_CHANGES_ICON')${behind// /}" )
hook_com[misc]+=${(j::)gitstatus}
}
function +vi-git-remotebranch() {
- local remote branch_name
+ local remote
+ local branch_name="${hook_com[branch]}"
# Are we on a remote-tracking branch?
remote=${$(command git rev-parse --verify HEAD@{upstream} --symbolic-full-name 2>/dev/null)/refs\/(remotes|heads)\/}
- branch_name=$(command git symbolic-ref --short HEAD 2>/dev/null)
if [[ -n "$POWERLEVEL9K_VCS_SHORTEN_LENGTH" ]] && [[ -n "$POWERLEVEL9K_VCS_SHORTEN_MIN_LENGTH" ]]; then
set_default POWERLEVEL9K_VCS_SHORTEN_DELIMITER $'\U2026'
- if [ ${#hook_com[branch]} -gt $POWERLEVEL9K_VCS_SHORTEN_MIN_LENGTH ] && [ ${#hook_com[branch]} -gt $POWERLEVEL9K_VCS_SHORTEN_LENGTH ]; then
+ if [ ${#hook_com[branch]} -gt ${POWERLEVEL9K_VCS_SHORTEN_MIN_LENGTH} ] && [ ${#hook_com[branch]} -gt ${POWERLEVEL9K_VCS_SHORTEN_LENGTH} ]; then
case "$POWERLEVEL9K_VCS_SHORTEN_STRATEGY" in
truncate_middle)
- hook_com[branch]="$(echo "${branch_name:0:$POWERLEVEL9K_VCS_SHORTEN_LENGTH}")$POWERLEVEL9K_VCS_SHORTEN_DELIMITER$(echo "${branch_name: -$POWERLEVEL9K_VCS_SHORTEN_LENGTH}")"
+ hook_com[branch]="${branch_name:0:$POWERLEVEL9K_VCS_SHORTEN_LENGTH}${POWERLEVEL9K_VCS_SHORTEN_DELIMITER}${branch_name: -$POWERLEVEL9K_VCS_SHORTEN_LENGTH}"
;;
truncate_from_right)
- hook_com[branch]="$(echo "${branch_name:0:$POWERLEVEL9K_VCS_SHORTEN_LENGTH}")$POWERLEVEL9K_VCS_SHORTEN_DELIMITER"
+ hook_com[branch]="${branch_name:0:$POWERLEVEL9K_VCS_SHORTEN_LENGTH}${POWERLEVEL9K_VCS_SHORTEN_DELIMITER}"
;;
esac
fi
@@ -104,11 +104,9 @@ function +vi-git-tagname() {
# Show count of stashed changes
# Port from https://github.com/whiteinge/dotfiles/blob/5dfd08d30f7f2749cfc60bc55564c6ea239624d9/.zsh_shouse_prompt#L268
function +vi-git-stash() {
- local -a stashes
-
- if [[ -s $(command git rev-parse --git-dir)/refs/stash ]] ; then
- stashes=$(command git stash list 2>/dev/null | wc -l)
- hook_com[misc]+=" $(print_icon 'VCS_STASH_ICON')${stashes// /}"
+ if [[ -s "${vcs_comm[gitdir]}/logs/refs/stash" ]] ; then
+ local -a stashes=( "${(@f)"$(<${vcs_comm[gitdir]}/logs/refs/stash)"}" )
+ hook_com[misc]+=" $(print_icon 'VCS_STASH_ICON')${#stashes}"
fi
}
diff --git a/powerlevel9k.zsh-theme b/powerlevel9k.zsh-theme
index 3c3303fa..383a3b91 100755
--- a/powerlevel9k.zsh-theme
+++ b/powerlevel9k.zsh-theme
@@ -803,7 +803,7 @@ prompt_dir() {
# if we are not in "~" or "/", split the paths into an array and exclude "~"
(( ${#current_path} > 1 )) && paths=(${(s:/:)${current_path//"~\/"/}}) || paths=()
# only run the code if SHORTEN_DIR_LENGTH is set, or we are using the two strategies that don't rely on it.
- if [[ -n "$POWERLEVEL9K_SHORTEN_DIR_LENGTH" || "$POWERLEVEL9K_SHORTEN_STRATEGY" == "truncate_with_folder_marker" || "$POWERLEVEL9K_SHORTEN_STRATEGY" == "truncate_to_last" ]]; then
+ if [[ -n "$POWERLEVEL9K_SHORTEN_DIR_LENGTH" || "$POWERLEVEL9K_SHORTEN_STRATEGY" == "truncate_with_folder_marker" || "$POWERLEVEL9K_SHORTEN_STRATEGY" == "truncate_to_last" || "$POWERLEVEL9K_SHORTEN_STRATEGY" == "truncate_with_package_name" ]]; then
set_default POWERLEVEL9K_SHORTEN_DELIMITER "\u2026"
# convert delimiter from unicode to literal character, so that we can get the correct length later
local delim=$(echo -n $POWERLEVEL9K_SHORTEN_DELIMITER)
@@ -1134,7 +1134,7 @@ prompt_ip() {
set_default POWERLEVEL9K_VPN_IP_INTERFACE "tun"
# prompt if vpn active
prompt_vpn_ip() {
- for vpn_iface in $(/sbin/ifconfig | grep -e ^"$POWERLEVEL9K_VPN_IP_INTERFACE" | cut -d":" -f1)
+ for vpn_iface in $(/sbin/ifconfig | grep -e "^${POWERLEVEL9K_VPN_IP_INTERFACE}" | cut -d":" -f1)
do
ip=$(/sbin/ifconfig "$vpn_iface" | grep -o "inet\s.*" | cut -d' ' -f2)
"$1_prompt_segment" "$0" "$2" "cyan" "$DEFAULT_COLOR" "$ip" 'VPN_ICON'
@@ -1648,9 +1648,11 @@ prompt_vi_mode() {
# https://virtualenv.pypa.io/en/latest/
prompt_virtualenv() {
local virtualenv_path="$VIRTUAL_ENV"
- if [[ -n "$virtualenv_path" && "$VIRTUAL_ENV_DISABLE_PROMPT" != true ]]; then
- "$1_prompt_segment" "$0" "$2" "blue" "$DEFAULT_COLOR" "$(basename "$virtualenv_path")" 'PYTHON_ICON'
- fi
+
+ # Early exit; $virtualenv_path must always be set.
+ [[ -z "$virtualenv_path" ]] && return
+
+ "$1_prompt_segment" "$0" "$2" "blue" "$DEFAULT_COLOR" "${virtualenv_path:t}" 'PYTHON_ICON'
}
################################################################
diff --git a/test/functions/icons.spec b/test/functions/icons.spec
index ec0cb1fa..8083c095 100755
--- a/test/functions/icons.spec
+++ b/test/functions/icons.spec
@@ -17,52 +17,58 @@ function tearDown() {
LC_CTYPE="${_OLD_LC_CTYPE}"
}
-function testLcCtypeIsSetCorrectlyInDefaultMode() {
+function testLcCtypeIsNotOverwrittenInDefaultMode() {
local POWERLEVEL9K_MODE="default"
+ local LC_CTYPE="my-locale"
# Load Powerlevel9k
source functions/icons.zsh
- assertEquals 'en_US.UTF-8' "${LC_CTYPE}"
+ assertEquals 'my-locale' "${LC_CTYPE}"
}
-function testLcCtypeIsSetCorrectlyInAwesomePatchedMode() {
+function testLcCtypeIsNotOverwrittenInAwesomePatchedMode() {
local POWERLEVEL9K_MODE="awesome-patched"
+ local LC_CTYPE="my-locale"
# Load Powerlevel9k
source functions/icons.zsh
- assertEquals 'en_US.UTF-8' "${LC_CTYPE}"
+ assertEquals 'my-locale' "${LC_CTYPE}"
}
-function testLcCtypeIsSetCorrectlyInAwesomeFontconfigMode() {
+function testLcCtypeIsNotOverwrittenInAwesomeFontconfigMode() {
local POWERLEVEL9K_MODE="awesome-fontconfig"
+ local LC_CTYPE="my-locale"
# Load Powerlevel9k
source functions/icons.zsh
- assertEquals 'en_US.UTF-8' "${LC_CTYPE}"
+ assertEquals 'my-locale' "${LC_CTYPE}"
}
-function testLcCtypeIsSetCorrectlyInNerdfontFontconfigMode() {
+function testLcCtypeIsNotOverwrittenInNerdfontFontconfigMode() {
local POWERLEVEL9K_MODE="nerdfont-fontconfig"
+ local LC_CTYPE="my-locale"
# Load Powerlevel9k
source functions/icons.zsh
- assertEquals 'en_US.UTF-8' "${LC_CTYPE}"
+ assertEquals 'my-locale' "${LC_CTYPE}"
}
-function testLcCtypeIsSetCorrectlyInFlatMode() {
+function testLcCtypeIsNotOverwrittenInFlatMode() {
local POWERLEVEL9K_MODE="flat"
+ local LC_CTYPE="my-locale"
# Load Powerlevel9k
source functions/icons.zsh
- assertEquals 'en_US.UTF-8' "${LC_CTYPE}"
+ assertEquals 'my-locale' "${LC_CTYPE}"
}
-function testLcCtypeIsSetCorrectlyInCompatibleMode() {
+function testLcCtypeIsNotOverwrittenInCompatibleMode() {
local POWERLEVEL9K_MODE="compatible"
+ local LC_CTYPE="my-locale"
# Load Powerlevel9k
source functions/icons.zsh
- assertEquals 'en_US.UTF-8' "${LC_CTYPE}"
+ assertEquals 'my-locale' "${LC_CTYPE}"
}
# Go through all icons defined in default mode, and
diff --git a/test/segments/context.spec b/test/segments/context.spec
index 07300370..25c355a7 100755
--- a/test/segments/context.spec
+++ b/test/segments/context.spec
@@ -11,11 +11,29 @@ function setUp() {
# Test specific settings
OLD_DEFAULT_USER=$DEFAULT_USER
unset DEFAULT_USER
+
+ # Fix leaked state for travis
+ OLD_POWERLEVEL9K_CONTEXT_ALWAYS_SHOW=$POWERLEVEL9K_CONTEXT_ALWAYS_SHOW
+ unset POWERLEVEL9K_CONTEXT_ALWAYS_SHOW
+ OLD_SSH_CLIENT=$SSH_CLIENT
+ unset SSH_CLIENT
+ OLD_SSH_TTY=$SSH_TTY
+ unset SSH_TTY
}
function tearDown() {
# Restore old variables
[[ -n "$OLD_DEFAULT_USER" ]] && DEFAULT_USER=$OLD_DEFAULT_USER
+ unset OLD_DEFAULT_USER
+
+ [[ -n "$OLD_POWERLEVEL9K_CONTEXT_ALWAYS_SHOW" ]] && POWERLEVEL9K_CONTEXT_ALWAYS_SHOW=$OLD_POWERLEVEL9K_CONTEXT_ALWAYS_SHOW
+ unset OLD_POWERLEVEL9K_CONTEXT_ALWAYS_SHOW
+
+ [[ -n "$OLD_SSH_CLIENT" ]] && SSH_CLIENT=$OLD_SSH_CLIENT
+ unset OLD_SSH_CLIENT
+
+ [[ -n "$OLD_SSH_TTY" ]] && SSH_TTY=$OLD_SSH_TTY
+ unset OLD_SSH_TTY
return 0
}
diff --git a/test/segments/vcs-git.spec b/test/segments/vcs-git.spec
index bddecf6c..da28b955 100755
--- a/test/segments/vcs-git.spec
+++ b/test/segments/vcs-git.spec
@@ -375,4 +375,161 @@ function testShorteningCommitHashIsNotShownIfShowChangesetIsFalse() {
assertEquals "%K{002} %F{000} master %k%F{002}%f " "$(build_left_prompt)"
}
-source shunit2/shunit2 \ No newline at end of file
+function testDetectingUntrackedFilesInSubmodulesWork() {
+ local -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS
+ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs)
+ local POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY="true"
+ unset POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND
+
+ mkdir ../submodule
+ cd ../submodule
+ git init 1>/dev/null
+ touch "i-am-tracked.txt"
+ git add . 1>/dev/null && git commit -m "Initial Commit" 1>/dev/null
+
+ local submodulePath="${PWD}"
+
+ cd -
+ git submodule add "${submodulePath}" 2>/dev/null
+ git commit -m "Add submodule" 1>/dev/null
+
+ # Go into checked-out submodule path
+ cd submodule
+ # Create untracked file
+ touch "i-am-untracked.txt"
+ cd -
+
+ source ${P9K_HOME}/powerlevel9k.zsh-theme
+
+ assertEquals "%K{002} %F{000} master ? %k%F{002}%f " "$(build_left_prompt)"
+}
+
+function testDetectinUntrackedFilesInMainRepoWithDirtySubmodulesWork() {
+ local -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS
+ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs)
+ local POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY="true"
+ unset POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND
+
+ mkdir ../submodule
+ cd ../submodule
+ git init 1>/dev/null
+ touch "i-am-tracked.txt"
+ git add . 1>/dev/null && git commit -m "Initial Commit" 1>/dev/null
+
+ local submodulePath="${PWD}"
+
+ cd -
+ git submodule add "${submodulePath}" 2>/dev/null
+ git commit -m "Add submodule" 1>/dev/null
+
+ # Create untracked file
+ touch "i-am-untracked.txt"
+
+ source ${P9K_HOME}/powerlevel9k.zsh-theme
+
+ assertEquals "%K{002} %F{000} master ? %k%F{002}%f " "$(build_left_prompt)"
+}
+
+function testDetectingUntrackedFilesInNestedSubmodulesWork() {
+ local -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS
+ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs)
+ local POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY="true"
+ unset POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND
+
+ local mainRepo="${PWD}"
+
+ mkdir ../submodule
+ cd ../submodule
+ git init 1>/dev/null
+ touch "i-am-tracked.txt"
+ git add . 1>/dev/null && git commit -m "Initial Commit" 1>/dev/null
+
+ local submodulePath="${PWD}"
+
+ mkdir ../subsubmodule
+ cd ../subsubmodule
+ git init 1>/dev/null
+ touch "i-am-tracked-too.txt"
+ git add . 1>/dev/null && git commit -m "Initial Commit" 1>/dev/null
+
+ local subsubmodulePath="${PWD}"
+
+ cd "${submodulePath}"
+ git submodule add "${subsubmodulePath}" 2>/dev/null
+ git commit -m "Add subsubmodule" 1>/dev/null
+ cd "${mainRepo}"
+ git submodule add "${submodulePath}" 2>/dev/null
+ git commit -m "Add submodule" 1>/dev/null
+
+ git submodule update --init --recursive 2>/dev/null
+
+ cd submodule/subsubmodule
+ # Create untracked file
+ touch "i-am-untracked.txt"
+ cd -
+
+ source ${P9K_HOME}/powerlevel9k.zsh-theme
+
+ assertEquals "%K{002} %F{000} master ? %k%F{002}%f " "$(build_left_prompt)"
+}
+
+function testDetectingUntrackedFilesInCleanSubdirectoryWorks() {
+ local -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS
+ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs)
+ local POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY="true"
+ unset POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND
+ mkdir clean-folder
+ touch clean-folder/file.txt
+ mkdir dirty-folder
+ touch dirty-folder/file.txt
+ git add . 2>/dev/null
+ git commit -m "Initial commit" >/dev/null
+ touch dirty-folder/new-file.txt
+ cd clean-folder
+ source ${P9K_HOME}/powerlevel9k.zsh-theme
+ assertEquals "%K{002} %F{000} master ? %k%F{002}%f " "$(build_left_prompt)"
+}
+
+function testBranchNameScriptingVulnerability() {
+ local -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS
+ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs)
+ echo "#!/bin/sh\n\necho 'hacked'\n" > evil_script.sh
+ chmod +x evil_script.sh
+
+ git checkout -b '$(./evil_script.sh)' 2>/dev/null
+ git add . 2>/dev/null
+ git commit -m "Initial commit" >/dev/null
+
+ assertEquals '%K{002} %F{000} $(./evil_script.sh) %k%F{002}%f ' "$(build_left_prompt)"
+}
+
+function testGitSubmoduleWorks() {
+ local -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS
+ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs)
+ local POWERLEVEL9K_VCS_SHOW_SUBMODULE_DIRTY="true"
+ unset POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND
+
+ mkdir ../submodule
+ cd ../submodule
+ git init 1>/dev/null
+ touch "i-am-tracked.txt"
+ git add . 1>/dev/null && git commit -m "Initial Commit" 1>/dev/null
+
+ local submodulePath="${PWD}"
+
+ cd -
+ git submodule add "${submodulePath}" 2>/dev/null
+ git commit -m "Add submodule" 1>/dev/null
+
+ cd submodule
+
+ source "${P9K_HOME}/powerlevel9k.zsh-theme"
+
+ local result="$(build_left_prompt)"
+ [[ "$result" =~ ".*(is outside repository)+" ]] && return 1
+
+ assertEquals "%K{002} %F{000} master %k%F{002}%f " "$result"
+}
+
+
+source shunit2/shunit2
diff --git a/test/segments/vcs-hg.spec b/test/segments/vcs-hg.spec
index 2903f544..c4289cef 100755
--- a/test/segments/vcs-hg.spec
+++ b/test/segments/vcs-hg.spec
@@ -204,4 +204,17 @@ function testBookmarkIconWorks() {
assertEquals "%K{002} %F{000} default Binitial %k%F{002}%f " "$(build_left_prompt)"
}
-source shunit2/shunit2 \ No newline at end of file
+function testBranchNameScriptingVulnerability() {
+ local -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS
+ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs)
+ echo "#!/bin/sh\n\necho 'hacked'\n" > evil_script.sh
+ chmod +x evil_script.sh
+
+ hg branch '$(./evil_script.sh)' >/dev/null
+ hg add . >/dev/null
+ hg commit -m "Initial commit" >/dev/null
+
+ assertEquals '%K{002} %F{000} $(./evil_script.sh) %k%F{002}%f ' "$(build_left_prompt)"
+}
+
+source shunit2/shunit2