-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathzew-process-buffer
98 lines (80 loc) · 3.27 KB
/
zew-process-buffer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Input:
# $1 - optional buffer to process (default is $BUFFER)
# $2 - optional parameter containing cursor (default is $CURSOR)
#
# Output:
# ZEW_PB_WORDS - split of "$1" into shell words; array
# ZEW_PB_WORDS_BEGINNINGS - indexes of first letters of corresponding words in ZEW_PB_WORDS
# ZEW_PB_SPACES - white spaces before corresponding words in ZEW_PB_WORDS
# ZEW_PB_SELECTED_WORD - index in ZEW_PB_WORDS pointing to word activated by cursor position
# ZEW_PB_LEFT - left part of active word
# ZEW_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}"
ZEW_PB_WORDS=( "${(Z+n+)buf}" )
ZEW_PB_SPACES=( )
ZEW_PB_WORDS_BEGINNINGS=( )
ZEW_PB_SELECTED_WORD="-1"
# (Z+n+) will return 1 element for buf that is empty or only whitespace
if [[ "$buf" = ( |$'\t')# ]]; then
ZEW_PB_WORDS=( )
integer nwords=0
else
integer nwords="${#ZEW_PB_WORDS}"
fi
# Remove ZEW_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
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
ZEW_PB_WORDS[i]="${ZEW_PB_WORDS[i]%% ##}"
word="${ZEW_PB_WORDS[i]}"
# 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
ZEW_PB_WORDS_BEGINNINGS[i]=$(( char_count + 1 ))
# Remember the spaces
ZEW_PB_SPACES[i]="$MATCH"
# Remove the word
MATCH=""
buf="${buf#(#m)$word}"
# If shell word not found, return. This shoudln't happen
[ -z "$MATCH" ] && return 0
# Spaces point to previous shell word
# Visual cursor right after spaces (-ge) -> not enough to select previous word (-gt required)
[[ "$ZEW_PB_SELECTED_WORD" -eq "-1" && "$char_count" -gt "$cursor" ]] && ZEW_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"
[[ "$ZEW_PB_SELECTED_WORD" -eq "-1" && "$char_count" -ge "$cursor" ]] && ZEW_PB_SELECTED_WORD="$i"
done
# What's left in $buf can be only white spaces
char_count=char_count+"$#buf"
ZEW_PB_SPACES[i]="$buf"
# Visual cursor right after spaces (-ge) -> enough to select last word
[[ "$ZEW_PB_SELECTED_WORD" -eq "-1" && "$char_count" -ge "$cursor" ]] && ZEW_PB_SELECTED_WORD=$(( i-1 ))
# Divide active word into two halves
integer diff=$(( cursor - ZEW_PB_WORDS_BEGINNINGS[ZEW_PB_SELECTED_WORD] + 1 ))
word="${ZEW_PB_WORDS[ZEW_PB_SELECTED_WORD]}"
ZEW_PB_LEFT="${word[1,diff]}"
ZEW_PB_RIGHT="${word[diff+1,-1]}"
# vim:ft=zsh