summary refs log tree commit diff
path: root/Functions/Zle/select-bracketed
blob: 00f51be2cd78d6c04288396533b716dc159a2c62 (plain) (blame)
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
# Text object for matching characters between matching pairs of brackets
#
# So for example, given (( i+1 )), the vi command ci( will change
# all the text between matching colons.
#
# The following is an example of how to enable this:
#     autoload -U select-bracketed
#     zle -N select-bracketed
#     for m in visual viopp; do
#	for c in {a,i}${(s..)^:-'()[]{}<>bB'}; do
#	  bindkey -M $m $c select-bracketed
#	done
#     done

local style=${${1:-$KEYS}[1]} matching="(){}[]<>bbBB"
local -i find=${NUMERIC:-1} idx=${matching[(I)[${${1:-$KEYS}[2]}]]}%9
(( idx )) || return 1 # no corresponding closing bracket
local lmatch=${matching[1 + (idx-1) & ~1]}
local rmatch=${matching[1 + (idx-1) | 1]}
local -i start=CURSOR+1 end=CURSOR+1 rfind=find

[[ $BUFFER[start] = "$rmatch" ]] && (( start--, end-- ))
if (( REGION_ACTIVE  && MARK != CURSOR)); then
  (( MARK < CURSOR && (start=end=MARK+1) ))
  local -i origstart=start-1
  [[ $style = i ]] && (( origstart-- ))
fi

while (( find )); do
  for (( ; find && start; --start )); do
    case $BUFFER[start] in
      "$lmatch") (( find-- )) ;;
      "$rmatch") (( find++ )) ;;
    esac
  done

  (( find )) && return 1 # opening bracket not found

  while (( rfind && end++ < $#BUFFER )); do
    case $BUFFER[end] in
      "$lmatch") (( rfind++ )) ;;
      "$rmatch") (( rfind-- )) ;;
    esac
  done

  (( rfind )) && return 1 # closing bracket not found

  (( REGION_ACTIVE && MARK != CURSOR && start >= origstart &&
    ( find=rfind=${NUMERIC:-1} ) ))
done

[[ $style = i ]] && (( start++, end-- ))
(( REGION_ACTIVE = !!REGION_ACTIVE ))
[[ $KEYMAP = vicmd ]] && (( REGION_ACTIVE && end-- ))
MARK=$start
CURSOR=$end