Skip to content
This repository has been archived by the owner on Apr 24, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1335 from dritter/fix-completion-menu
Browse files Browse the repository at this point in the history
[Bugfix] Fix completion menu
  • Loading branch information
dritter authored Sep 23, 2019
2 parents 0dbeefb + 3a1a46e commit 04c5cf9
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 86 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ a prompt segment. As an example you could create a custom segment
You can take a look at [how to create a custom segment
here](segments/custom/README.md).


### Disabling / Enabling Powerlevel9k

You can disable P9k and return to a very basic prompt at any time simply by
Expand Down
8 changes: 4 additions & 4 deletions functions/icons.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function p9k::register_icon() {
p9k::expand "$ICON_USER_VARIABLE"
map="${(P)ICON_USER_VARIABLE}"
else # use the icons that are registered by the segment
case ${P9K_MODE} in
case ${P9K_MODE:-} in
'flat'|'awesome-patched') map=$3 ;;
'awesome-fontconfig') map=$4 ;;
'awesome-mapped-fontconfig') map=$5 ;;
Expand Down Expand Up @@ -122,7 +122,7 @@ function p9k::register_segment() {
__P9K_DATA[${STATEFUL_NAME}_FG]="$(p9k::foreground_color $4)"
fi

p9k::register_icon "${STATEFUL_NAME}" "${5}" "${6}" "${7}" "${8}" "${9}"
p9k::register_icon "${STATEFUL_NAME}" "${5:-}" "${6:-}" "${7:-}" "${8:-}" "${9:-}"

local ICON_COLOR_VARIABLE="P9K_${STATEFUL_NAME}_ICON_COLOR"
if p9k::defined "${ICON_COLOR_VARIABLE}"; then
Expand Down Expand Up @@ -159,10 +159,10 @@ function p9k::register_segment() {

# Overwrite given bold directive by user defined variable for this segment.
local BOLD_USER_VARIABLE="P9K_${STATEFUL_NAME}_BOLD"
local BOLD="${(P)BOLD_USER_VARIABLE}"
local BOLD="${(P)BOLD_USER_VARIABLE:-}"
[[ -z "${BOLD}" ]] || __P9K_DATA[${STATEFUL_NAME}_BD]=true
local BOLD_ICON_USER_VARIABLE="P9K_${STATEFUL_NAME}_ICON_BOLD"
local BOLD_ICON="${(P)BOLD_ICON_USER_VARIABLE}"
local BOLD_ICON="${(P)BOLD_ICON_USER_VARIABLE:-}"
[[ -z "${BOLD_ICON}" ]] || __P9K_DATA[${STATEFUL_NAME}_ICON_BD]=true
}

Expand Down
95 changes: 90 additions & 5 deletions functions/utilities.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,55 @@ function p9k::expand() {
typeset -g $1=${(g::)${(P)1}}
}

###############################################################
# @description
# Determines the width of the rendered prompt used.
##
# @args
# $1 string The prompt string
##
# @returns
# Nothing - Returnvalue is stored in _P9K_RETVAL
##
# @note
# If we execute `print -P $1`, how many characters will be
# printed on the last line?
# Assumes that `%{%}` and `%G` don't lie.
#
# _p9k_prompt_length '' => 0
# _p9k_prompt_length 'abc' => 3
# _p9k_prompt_length $'abc\nxy' => 2
# _p9k_prompt_length $'\t' => 8
# _p9k_prompt_length '%F{red}abc' => 3
# _p9k_prompt_length $'%{a\b%Gb%}' => 1
#
# @see
# [zsh length of a string](https://stackoverflow.com/a/57141646/1095235)
#
##
function p9k::prompt_length() {
emulate -L zsh
local COLUMNS=1024
local -i x y=$#1 m
if (( y )); then
# This tests if each character was printed and counts them.
# The magic is in %$y(l.1.0), which outputs a 1 if the
# character was printed, or 0 if not.
# This is done via a binary search, so there is two loops.
# See https://www.reddit.com/r/zsh/comments/cgbm24/multiline_prompt_the_missing_ingredient/
while (( ${${(%):-$1%$y(l.1.0)}[-1]} )); do
x=y
(( y *= 2 ));
done
local xy
while (( y > x + 1 )); do
m=$(( x + (y - x) / 2 ))
typeset ${${(%):-$1%$m(l.x.y)}[-1]}=$m
done
fi
_P9K_RETVAL=$x
}

###############################################################
# @description
# Converts large memory values into a human-readable unit (e.g., bytes --> GB)
Expand Down Expand Up @@ -413,7 +462,7 @@ function p9k::find_first_defined() {
###############################################################
# @description
# Takes a list of variable names and returns the value of the
# the first non empty one.
# the first non empty one.
# @args
# $1 optional flag '-n' as first argument will make function to
# return variable name instead of it's value.
Expand All @@ -434,10 +483,15 @@ function p9k::find_first_non_empty() {
done
}

# Parse IP address from ifconfig on OSX and from IP on Linux
# Parameters:
# $1 - string The desired Interface
# $2 - string A root prefix for testing purposes
###############################################################
# @description
# Parse IP address from ifconfig on OSX and from IP on Linux
# @args
# $1 - string The desired Interface
# $2 - string A root prefix for testing purposes
# @returns
# The parsed IP address
##
function p9k::parseIp() {
local desiredInterface="${1}"

Expand Down Expand Up @@ -488,3 +542,34 @@ function p9k::parseIp() {

return 1
}

###############################################################
# @description
# Wrap a ZLE widget safely.
# @args
# $1 function name of the widget
# @example
# __p9k_wrap_zle_widget zle-keymap-select _p9k_zle_keymap_select
##
__p9k_wrap_zle_widget() {
local widget=$1
local hook=$2
local orig=p9k-orig-$widget
case $widgets[$widget] in
user:*)
zle -N $orig ${widgets[$widget]#user:}
;;
builtin)
eval "_p9k_orig_${(q)widget}() { zle .${(q)widget} }"
zle -N $orig _p9k_orig_$widget
;;
esac

local wrapper=_p9k_wrapper_$widget_$hook
eval "function ${(q)wrapper}() {
${(q)hook} \"\$@\"
(( \$+widgets[${(q)orig}] )) && zle ${(q)orig} -- \"\$@\"
}"

zle -N -- $widget $wrapper
}
120 changes: 81 additions & 39 deletions generator/default.p9k
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ function __p9k_left_prompt_segment() {
local content
local SEGMENT_ICON
# Support for bold segment
[[ -n "${4}" ]] && [[ $__P9K_DATA[${STATEFUL_NAME}_BD] == true ]] \
[[ -n "${4}" ]] && [[ ${__P9K_DATA[${STATEFUL_NAME}_BD]:-} == true ]] \
&& content="%B${4}%b" \
|| content="${4}"
[[ -n "${5}" ]] && [[ $__P9K_DATA[${STATEFUL_NAME}_ICON_BD] == true ]] \
[[ -n "${5}" ]] && [[ ${__P9K_DATA[${STATEFUL_NAME}_ICON_BD]:-} == true ]] \
&& SEGMENT_ICON="%B${5}%b" \
|| SEGMENT_ICON="${5}"

Expand Down Expand Up @@ -92,7 +92,7 @@ function __p9k_left_prompt_segment() {
# custom white space that follows it
local first_symbol=""
local first_ws="$__P9K_DATA[FIRST_WHITESPACE]"
if [[ -n "$P9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL" ]]; then
if [[ -n "${P9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL:-}" ]]; then
first_symbol="%K{${CURRENT_BG}}%F${bg#%K}$P9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL"
fi

Expand Down Expand Up @@ -235,22 +235,22 @@ function p9k::prepare_segment() {
[[ -n "${2}" ]] && STATEFUL_NAME="${STATEFUL_NAME}_${(U)2}"

# Precompile condition.
if __p9k_segment_should_be_printed "${STATEFUL_NAME}" "${7}" "${6}"; then
if __p9k_segment_should_be_printed "${STATEFUL_NAME}" "${7:-true}" "${6}"; then
local SEGMENT_ICON
if [[ -z "${8}" ]]; then
if [[ -z "${8:-}" ]]; then
SEGMENT_ICON=${__P9K_ICONS[${STATEFUL_NAME}]}
else
# check if it is a named icon
SEGMENT_ICON=${__P9K_ICONS[${8}]}
SEGMENT_ICON=${__P9K_ICONS[${8:-}]}
# otherwise use it literally
[[ -z "${SEGMENT_ICON}" ]] && SEGMENT_ICON=$(echo ${8})
fi

# Background overide
[[ -n "${9}" ]] && __P9K_DATA[${STATEFUL_NAME}_BG]="${9}"
[[ -n "${9:-}" ]] && __P9K_DATA[${STATEFUL_NAME}_BG]="${9}"

# Foreground overide
[[ -n "${10}" ]] && __P9K_DATA[${STATEFUL_NAME}_FG]="${10}"
[[ -n "${10:-}" ]] && __P9K_DATA[${STATEFUL_NAME}_FG]="${10}"

"__p9k_${3}_prompt_segment" "${STATEFUL_NAME}" "${4}" "${5}" "${6}" "${SEGMENT_ICON}"
fi
Expand Down Expand Up @@ -360,6 +360,13 @@ function __p9k_build_right_prompt() {
fi

echo -n "${__P9K_DATA[LAST_WHITESPACE]}${last_symbol}"

if ! p9k::defined ZLE_RPROMPT_INDENT; then
# Extend the RPROMPT to the end (with %E).
echo -n "%E"
fi

echo -n "%f%k%b"
}

###############################################################
Expand Down Expand Up @@ -402,52 +409,74 @@ p9k::set_default P9K_PROMPT_ADD_NEWLINE false
# @noargs
##
function __p9k_prepare_prompts() {
local RPROMPT_PREFIX RPROMPT_SUFFIX

_P9K_COMMAND_DURATION=$((EPOCHREALTIME - _P9K_TIMER_START))

# Reset start time
_P9K_TIMER_START=0x7FFFFFFF

local LC_ALL="" LC_CTYPE="en_US.UTF-8" # Set the right locale to protect special characters

local NEWLINE=$'\n'

local left

if [[ ${ZLE_RPROMPT_INDENT:-} -eq 0 ]]; then
unset ZLE_RPROMPT_INDENT
fi
if [[ "${P9K_PROMPT_ADD_NEWLINE:-}" == true ]]; then
NEWLINES=""
repeat ${P9K_PROMPT_ADD_NEWLINE_COUNT:-1} { NEWLINES+=${NEWLINE} }
left="${NEWLINES}"
fi

left+="%f%b%k"
if [[ "${P9K_PROMPT_ON_NEWLINE:-}" == true ]]; then
PROMPT="${__P9K_ICONS[MULTILINE_FIRST_PROMPT_PREFIX]}%f%b%k$(__p9k_build_left_prompt)
${__P9K_ICONS[MULTILINE_LAST_PROMPT_PREFIX]}"
if [[ "$P9K_RPROMPT_ON_NEWLINE" != true ]]; then
# The right prompt should be on the same line as the first line of the left
# prompt. To do so, there is just a quite ugly workaround: Before zsh draws
# the RPROMPT, we advise it, to go one line up. At the end of RPROMPT, we
# advise it to go one line down. See:
# http://superuser.com/questions/357107/zsh-right-justify-in-ps1
RPROMPT_PREFIX='%{'$'\e[1A'${P9K_RPROMPT_PREFIX:-}'%}' # one line up
RPROMPT_SUFFIX='%{'${P9K_RPROMPT_SUFFIX:-}$'\e[1B''%}' # one line down
left+="${__P9K_ICONS[MULTILINE_FIRST_PROMPT_PREFIX]}"
fi

left+="$(__p9k_build_left_prompt)"
if [[ ${P9K_DISABLE_RPROMPT:-} != true ]]; then
local right="${P9K_RPROMPT_PREFIX:-}%f%b%k$(__p9k_build_right_prompt)${P9K_RPROMPT_SUFFIX:-}"
if [[ ${P9K_PROMPT_ON_NEWLINE:-} != true || ${P9K_RPROMPT_ON_NEWLINE:-} == true ]]; then
RPROMPT="${right}"
else
RPROMPT_PREFIX='%{'${P9K_RPROMPT_PREFIX:-}'%}'
RPROMPT_SUFFIX='%{'${P9K_RPROMPT_SUFFIX:-}'%}'
__P9K_PROMPT="${(e)left}"
__P9K_RPROMPT="${(e)right}"
p9k::prompt_length "${__P9K_PROMPT}"
local leftPromptWidth=${_P9K_RETVAL}
p9k::prompt_length "${__P9K_RPROMPT}"
local rightPromptWidth=${_P9K_RETVAL}
local spacerWidth=$(( COLUMNS - (leftPromptWidth + rightPromptWidth + ZLE_RPROMPT_INDENT) ))
if (( spacerWidth > 0 )); then
local spacerChar=' '
[[ "$spacerChar" == '.' ]] && local padSeparator=',' || local padSeparator='.'
# We left pad the spacer here (flag "l") and the syntax for that is
# ${(l:<length>::<char>:)}, where colons are here the separators
# that need to differ from the char.
left+='${(pl'${padSeparator}$((spacerWidth - 1))${padSeparator}${padSeparator}${spacerChar}${padSeparator}')}'
# _P9K_RPROMPT_OVERRIDE is for removing the RPROMPT
# in older prompts. This mimics the TRANSIENT_RPROMPT
# setting from ZSH. The variable is set to an empty
# value in a ZLE widget (_p9k_zle_line_finish), which
# leads to the right prompt not being printed. As this
# is written as variable in our PROMPT, we remove the
# old right prompts.
[[ -o TRANSIENT_RPROMPT ]] && left+='${_P9K_RPROMPT_OVERRIDE-${__P9K_RPROMPT}}' || left+='${__P9K_RPROMPT}'
fi

fi
else
PROMPT="%f%b%k$(__p9k_build_left_prompt)"
RPROMPT_PREFIX='%{'${P9K_RPROMPT_PREFIX:-}'%}'
RPROMPT_SUFFIX='%{'${P9K_RPROMPT_SUFFIX:-}'%}'
fi

if [[ "${P9K_DISABLE_RPROMPT:-}" != true ]]; then
RPROMPT="${RPROMPT_PREFIX}%f%b%k$(__p9k_build_right_prompt)%{${reset_color}%}${RPROMPT_SUFFIX}"
if [[ "${P9K_PROMPT_ON_NEWLINE:-}" == true ]]; then
left+="${NEWLINE}${__P9K_ICONS[MULTILINE_LAST_PROMPT_PREFIX]}"
fi

# Allow iTerm integration to work
[[ "${ITERM_SHELL_INTEGRATION_INSTALLED:-}" == "Yes" ]] \
&& PROMPT="%{$(iterm2_prompt_mark)%}${PROMPT}"
PROMPT="${left}"

local NEWLINE='
'
unset _P9K_RPROMPT_OVERRIDE

if [[ "${P9K_PROMPT_ADD_NEWLINE:-}" == true ]]; then
NEWLINES=""
repeat ${P9K_PROMPT_ADD_NEWLINE_COUNT:-1} { NEWLINES+=${NEWLINE} }
PROMPT="${NEWLINES}${PROMPT}"
fi
# Allow iTerm integration to work
[[ "${ITERM_SHELL_INTEGRATION_INSTALLED:-}" == "Yes" ]] \
&& PROMPT="$(iterm2_prompt_mark)${PROMPT}"
}

p9k::set_default P9K_IGNORE_TERM_COLORS false
Expand Down Expand Up @@ -522,6 +551,19 @@ function prompt_powerlevel9k_setup() {
P9K_RIGHT_PROMPT_ELEMENTS=(status root_indicator background_jobs history time)
fi

if [[ $P9K_PROMPT_ON_NEWLINE == true ]]; then
if [[ ${P9K_RPROMPT_ON_NEWLINE} != true && -o TRANSIENT_RPROMPT ]]; then
if is-at-least 5.3; then
function _p9k_zle_line_finish() {
[[ -o TRANSIENT_RPROMPT ]] || return
_P9K_RPROMPT_OVERRIDE=
zle && zle .reset-prompt && zle -R
}
__p9k_wrap_zle_widget zle-line-finish _p9k_zle_line_finish
fi
fi
fi

# initialize colors
autoload -U colors && colors

Expand Down
2 changes: 1 addition & 1 deletion powerlevel9k.zsh-theme
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
readonly P9K_VERSION="0.7.0"

## Turn on for Debugging
# PS4='%s%f%b%k%F{blue}%{λ%}%L %F{240}%N:%i%(?.. %F{red}%?) %1(_.%F{yellow}%-1_ .)%s%f%b%k '
# PS4='%s%f%b%k%F{blue}λ%L %F{240}%N:%i%(?.. %F{red}%?) %1(_.%F{yellow}%-1_ .)%s%f%b%k '
# zstyle ':vcs_info:*+*:*' debug true
# set -o xtrace

Expand Down
26 changes: 25 additions & 1 deletion segments/status/status.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,30 @@ function setUp() {
# Resets if someone has set these in his/hers env
unset P9K_STATUS_VERBOSE
unset P9K_STATUS_OK_IN_NON_VERBOSE
}

function oneTimeSetUp() {
function stripEsc() {
local clean_string="" escape_found=false
for (( i = 1; i <= ${#1}; i++ )); do
case ${1[i]}; in
"") clean_string+="<Esc>"; escape_found=true ;; # escape character
"[") if [[ ${escape_found} == true ]]; then
escape_found=false
else
clean_string+="${1[i]}"
fi
;;
*) clean_string+="${1[i]}" ;;
esac
done
echo "${clean_string}"
}
}

function oneTimeTearDown() {
unfunction stripEsc
}

function testStatusPrintsNothingIfReturnCodeIsZeroAndVerboseIsUnset() {
local P9K_CUSTOM_WORLD='echo world'
Expand Down Expand Up @@ -82,7 +105,8 @@ function testStatusSegmentIntegrated() {

false; __p9k_save_retvals; __p9k_prepare_prompts

assertEquals "%f%b%k%K{000} %F{001}✘ %k%F{000}%f " "${(e)PROMPT}"
local _actual=$(stripEsc "${(e)PROMPT}")
assertEquals "%f%b%k%K{000} %F{001}✘ %k%F{000}%f " "${_actual}"
}

source shunit2/shunit2
Loading

0 comments on commit 04c5cf9

Please sign in to comment.