mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 06:00:54 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			120 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| # Select the entire word around the cursor. Intended for use as
 | |
| # a vim-style text object in vi mode but with customisable
 | |
| # word boundaries.
 | |
| #
 | |
| # For example:
 | |
| #   autoload -U select-word-match
 | |
| #   zle -N select-in-camel select-word-match
 | |
| #   bindkey -M viopp ic select-in-camel
 | |
| #   zstyle ':zle:*-camel' word-style normal-subword
 | |
| 
 | |
| emulate -L zsh
 | |
| setopt extendedglob
 | |
| 
 | |
| local curcontext=:zle:$WIDGET
 | |
| local -A matched_words
 | |
| # Start and end of range of characters
 | |
| integer pos1 pos2 num=${NUMERIC:-1}
 | |
| local style word
 | |
| 
 | |
| # choose between inner word or a word style of widget
 | |
| for style in $1 ${${WIDGET#*-}[1]} $KEYS[1] "i"; do
 | |
|   [[ $style = [ai] ]] && break
 | |
| done
 | |
| 
 | |
| autoload -Uz match-words-by-style
 | |
| 
 | |
| while (( num-- )); do
 | |
|   if (( MARK > CURSOR )); then
 | |
|     # if cursor is at the start of the selection, just move back a word
 | |
|     match-words-by-style
 | |
|     if [[ $style = i && -n $matched_words[ws-before-cursor] ]]; then
 | |
|       word=$matched_words[ws-before-cursor]
 | |
|     else
 | |
|       word=$matched_words[word-before-cursor]$matched_words[ws-before-cursor]
 | |
|     fi
 | |
|     if [[ -n $word ]]; then
 | |
|       (( CURSOR -= ${#word} ))
 | |
|     else
 | |
|       return 1
 | |
|     fi
 | |
|   elif (( MARK >= 0 && MARK < CURSOR )); then
 | |
|     # cursor at the end, move forward a word
 | |
|     (( CURSOR+1 == $#BUFFER )) && return 1
 | |
|     (( CURSOR++ ))
 | |
|     match-words-by-style
 | |
|     if [[ -n $matched_words[ws-after-cursor] ]]; then
 | |
|       if [[ $style = i ]]; then
 | |
| 	# just skip the whitespace
 | |
| 	word=$matched_words[ws-after-cursor]
 | |
|       else
 | |
| 	# skip the whitespace plus word
 | |
| 	word=$matched_words[ws-after-cursor]$matched_words[word-after-cursor]
 | |
|       fi
 | |
|     else
 | |
|       if [[ $style = i ]]; then
 | |
| 	# skip the word
 | |
| 	word=$matched_words[word-after-cursor]
 | |
|       else
 | |
| 	# skip word and following whitespace
 | |
| 	word=$matched_words[word-after-cursor]$matched_words[ws-after-word]
 | |
|       fi
 | |
|     fi
 | |
|     (( CURSOR += ${#word} - 1 ))
 | |
|   else
 | |
|     match-words-by-style
 | |
| 
 | |
|     if (( ${matched_words[is-word-start]} )); then
 | |
|       # The word we are selecting starts at the cursor position.
 | |
|       pos1=$CURSOR
 | |
|     else
 | |
|       # No whitespace before us, so select any wordcharacters there.
 | |
|       pos1="${#matched_words[start]}"
 | |
|     fi
 | |
| 
 | |
|     if [[ -n "${matched_words[ws-after-cursor]}" ]]; then
 | |
|       if [[ -n "${matched_words[ws-before-cursor]}" ]] || (( CURSOR == 0 )); then
 | |
|         # whitespace either side, select it
 | |
| 	(( pos1 = CURSOR - ${#matched_words[ws-before-cursor]} ))
 | |
| 	(( pos2 = CURSOR + ${#matched_words[ws-after-cursor]} ))
 | |
|       else
 | |
| 	# There's whitespace at the cursor position, so only select
 | |
| 	# up to the cursor position.
 | |
| 	(( pos2 = CURSOR + 1 ))
 | |
|       fi
 | |
|     else
 | |
|       # No whitespace at the cursor position, so select the
 | |
|       # current character and any following wordcharacters.
 | |
|       (( pos2 = CURSOR + ${#matched_words[word-after-cursor]} ))
 | |
|     fi
 | |
| 
 | |
|     if [[ $style = a ]]; then
 | |
|       if [[ -n "${matched_words[ws-after-cursor]}"  && ( -n "${matched_words[ws-before-cursor]}" || CURSOR -eq 0 ) ]]; then
 | |
| 	# in the middle of whitespace so grab a word
 | |
| 	if [[ -n "${matched_words[word-after-cursor]}" ]]; then
 | |
| 	  (( pos2 += ${#matched_words[word-after-cursor]} )) # preferably the one after
 | |
| 	else
 | |
| 	  (( pos1 -= ${#matched_words[word-before-cursor]} )) # otherwise the one before
 | |
| 	fi
 | |
|       elif [[ -n "${matched_words[ws-after-word]}" ]]; then
 | |
| 	(( pos2 += ${#matched_words[ws-after-word]} ))
 | |
|       elif [[ -n "${matched_words[ws-before-cursor]}" ]]; then
 | |
| 	# couldn't grab whitespace forwards so try backwards
 | |
| 	(( pos1 -= ${#matched_words[ws-before-cursor]} ))
 | |
|       elif (( pos1 > 0 )); then
 | |
| 	# There might have been whitespace before the word
 | |
| 	(( CURSOR = pos1 ))
 | |
| 	match-words-by-style
 | |
| 	if [[ -n "${matched_words[ws-before-cursor]}" ]]; then
 | |
| 	  (( pos1 -= ${#matched_words[ws-before-cursor]} ))
 | |
| 	fi
 | |
|       fi
 | |
|     fi
 | |
| 
 | |
|     (( MARK = pos1, CURSOR = pos2-1 ))
 | |
|   fi
 | |
| done
 | |
| 
 | |
| if [[ $KEYMAP == vicmd ]] && (( !REGION_ACTIVE )); then
 | |
|   (( CURSOR++ )) # Need to include cursor position for operators
 | |
| fi
 |