# Input:
# $1 - optional buffer to process (default is $BUFFER)
# $2 - optional parameter containing cursor (default is $CURSOR)
#
# Output:
# ZPLG_PB_WORDS - split of "$1" into shell words; array
# ZPLG_PB_WORDS_BEGINNINGS - indexes of first letters of corresponding words in ZPLG_PB_WORDS
# ZPLG_PB_SPACES - white spaces before corresponding words in ZPLG_PB_WORDS
# ZPLG_PB_SELECTED_WORD - index in ZPLG_PB_WORDS pointing to word activated by cursor position
# ZPLG_PB_LEFT - left part of active word
# ZPLG_PB_RIGHT - right part of active word
#

emulate -LR zsh
setopt typesetsilent extendedglob noshortloops

local MBEGIN MEND MATCH mbegin mend match

local buf="${1:-$BUFFER}"
local cursor="${2:-$CURSOR}"

# All output variables are either overwritten or cleared
ZPLG_PB_WORDS=( "${(Z+cn+)buf}" )
ZPLG_PB_SPACES=( )
ZPLG_PB_WORDS_BEGINNINGS=( )
ZPLG_PB_SELECTED_WORD="-1"
ZPLG_PB_LEFT=""
ZPLG_PB_RIGHT=""

# (Z+n+) will return 1 element for buf that is empty or only whitespace
if [[ "$buf" = ( |$'\t')# ]]; then
    ZPLG_PB_WORDS=( )
    integer nwords=0
else
    integer nwords="${#ZPLG_PB_WORDS}"
fi

# Remove ZPLG_PB_WORDS one by one, counting characters,
# computing beginning of each word, to find
# place to break the word into 2 halves (for
# complete_in_word option)

local i word wordlen tword
integer char_count=0

# (Z) handles spaces nicely, but we need them for the user
# Also compute words beginnings and the selected word
for (( i=1; i<=nwords; i++ )); do
    # Remove spurious space generated by Z-flag when
    # input is an unbound '$(' (happens with zsh < 5.1)
    # and also real spaces gathered by an unbound '$(',
    # to handle them in a way normal to this loop
    ZPLG_PB_WORDS[i]="${ZPLG_PB_WORDS[i]%% ##}"
    word="${ZPLG_PB_WORDS[i]}"
    wordlen="${#word}"

    # In general, $buf can start with white spaces
    # We will not search for them, but instead for
    # leading character of current shell word,
    # negated. This is an ambition to completely
    # avoid character classes

    # Remove white spaces
    buf="${buf##(#m)[^$word[1]]#}"
    # Count them
    char_count=char_count+"${#MATCH}"
    # This is the beginning of current word
    ZPLG_PB_WORDS_BEGINNINGS[i]=$(( char_count + 1 ))
    # Remember the spaces
    ZPLG_PB_SPACES[i]="$MATCH"

    tword="${buf[1,wordlen]}"

    # Remove the word
    [[ "$tword" != "$word" && ${#word} != ${#tword} ]] && { echo "BUG in processing ${buf[1,wordlen]} vs. $word"; return 1; }
    buf="${buf[wordlen+1,-1]}"

    # Spaces point to previous shell word
    # Visual cursor right after spaces (-ge) -> not enough to select previous word (-gt required)
    [[ "$ZPLG_PB_SELECTED_WORD" -eq "-1" && "$char_count" -gt "$cursor" ]] && ZPLG_PB_SELECTED_WORD=$(( i-1 ))

    # Actual characters point to current shell word
    # Visual cursor right after letters (-ge) -> enough to select current word
    char_count=char_count+"$#word"
    [[ "$ZPLG_PB_SELECTED_WORD" -eq "-1" && "$char_count" -ge "$cursor" ]] && ZPLG_PB_SELECTED_WORD="$i"
done 

# What's left in $buf can be only white spaces
char_count=char_count+"$#buf"
ZPLG_PB_SPACES[i]="$buf"

# Visual cursor right after spaces (-ge) -> enough to select last word
[[ "$ZPLG_PB_SELECTED_WORD" -eq "-1" && "$char_count" -ge "$cursor" ]] && ZPLG_PB_SELECTED_WORD=$(( i-1 ))

# Divide active word into two halves
integer diff=$(( cursor - ZPLG_PB_WORDS_BEGINNINGS[ZPLG_PB_SELECTED_WORD] + 1 ))
word="${ZPLG_PB_WORDS[ZPLG_PB_SELECTED_WORD]}"
ZPLG_PB_LEFT="${word[1,diff]}"
ZPLG_PB_RIGHT="${word[diff+1,-1]}"

# This function should be tested
return 0

# vim:ft=zsh
