From 932ff2b6f8990b027facc93fb23bc1dc0163707e Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sun, 24 Jul 2016 22:18:34 +0200 Subject: 38929: new vim style text object using match-words-by-style mechanism --- Functions/Zle/select-word-match | 121 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 Functions/Zle/select-word-match (limited to 'Functions/Zle/select-word-match') diff --git a/Functions/Zle/select-word-match b/Functions/Zle/select-word-match new file mode 100644 index 000000000..24620c995 --- /dev/null +++ b/Functions/Zle/select-word-match @@ -0,0 +1,121 @@ +# 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[3] ]]; then + word=$matched_words[3] + else + word=$matched_words[2]$matched_words[3] + 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[4] ]]; then + if [[ $style = i ]]; then + # just skip the whitespace + word=$matched_words[4] + else + # skip the whitespace plus word + word=$matched_words[4]$matched_words[5] + fi + else + if [[ $style = i ]]; then + # skip the word + word=$matched_words[5] + else + # skip word and following whitespace + word=$matched_words[5]$matched_words[6] + fi + fi + (( CURSOR += ${#word} - 1 )) + else + match-words-by-style + + if [[ -n "${matched_words[3]}" ]]; then + # There's whitespace before the cursor, so 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[1]}" + fi + + if [[ -n "${matched_words[4]}" ]]; then + if [[ -n "${matched_words[3]}" ]] || (( CURSOR == 0 )); then + # whitespace either side, select it + (( pos1 = CURSOR - ${#matched_words[3]} )) + (( pos2 = CURSOR + ${#matched_words[4]} )) + 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[5]} )) + fi + + if [[ $style = a ]]; then + if [[ -n "${matched_words[4]}" && ( -n "${matched_words[3]}" || CURSOR -eq 0 ) ]]; then + # in the middle of whitespace so grab a word + if [[ -n "${matched_words[5]}" ]]; then + (( pos2 += ${#matched_words[5]} )) # preferably the one after + else + (( pos1 -= ${#matched_words[2]} )) # otherwise the one before + fi + elif [[ -n "${matched_words[6]}" ]]; then + (( pos2 += ${#matched_words[6]} )) + elif [[ -n "${matched_words[3]}" ]]; then + # couldn't grab whitespace forwards so try backwards + (( pos1 -= ${#matched_words[3]} )) + elif (( pos1 > 0 )); then + # There might have been whitespace before the word + (( CURSOR = pos1 )) + match-words-by-style + if [[ -n "${matched_words[3]}" ]]; then + (( pos1 -= ${#matched_words[3]} )) + 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 -- cgit v1.2.3 From b816bb42cfc4d0fa05abb63ebf4098af05a3d593 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Thu, 28 Jul 2016 16:16:25 +0200 Subject: 38957: make use of updates to match-words-by-style and better support completion of word-style styles for zstyle --- ChangeLog | 5 ++++ Completion/Zsh/Command/_zstyle | 7 ++++-- Doc/Zsh/contrib.yo | 2 +- Functions/Zle/select-word-match | 55 ++++++++++++++++++++--------------------- 4 files changed, 38 insertions(+), 31 deletions(-) (limited to 'Functions/Zle/select-word-match') diff --git a/ChangeLog b/ChangeLog index 6a5b0e5c4..1d68cf75d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2016-07-28 Oliver Kiddle + * 38957: Functions/Zle/select-word-match, + Completion/Zsh/Command/_zstyle, Doc/Zsh/contrib.yo: + make use of updates to match-words-by-style and better support + completion of word-style styles for zstyle + * 38956: Completion/Zsh/Command/_bindkey, Completion/Zsh/Command/_vared, Completion/Zsh/Command/_zle, Completion/Zsh/Function/_add-zle-hook-widget, diff --git a/Completion/Zsh/Command/_zstyle b/Completion/Zsh/Command/_zstyle index 9a6d61891..20ff47f87 100644 --- a/Completion/Zsh/Command/_zstyle +++ b/Completion/Zsh/Command/_zstyle @@ -173,6 +173,7 @@ styles=( url-seps e: whence e: word-chars e: + word-class e: word-style e:word-style word-context e: @@ -241,11 +242,13 @@ while (( $#state )); do case "$state[1]" in (contexts) if [[ ! -prefix :*: ]]; then - _wanted contexts expl context compadd -P : -qS : completion vcs_info zftp + _wanted contexts expl context compadd -P : -qS : chpwd completion vcs_info zftp zle elif compset -P :completion:; then contexts=( functions _completers cmdorcont argument tag ) elif compset -P :vcs_info:; then contexts=( vcs-string user-context repo-root-name ) + elif compset -P :zle:; then + _wanted widgets expl widget _widgets -qS : fi if (( $#contexts )); then for ostate in $contexts; do @@ -521,7 +524,7 @@ while (( $#state )); do ;; (word-style) - _wanted word-styles expl 'word style' compadd normal shell space + _wanted word-styles expl 'word style' compadd {normal,specified,unspecified,shell,whitespace}-subword ;; (vcs-string) diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 8db7395d0..00ed08029 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -2105,7 +2105,7 @@ Here are some examples of use of the tt(word-context) style to extend the context. example(zstyle ':zle:*' word-context \ - "*/*" file "[[:space:]]" whitespace + "*/*" filename "[[:space:]]" whitespace zstyle ':zle:transpose-words:whitespace' word-style shell zstyle ':zle:transpose-words:filename' word-style normal zstyle ':zle:transpose-words:filename' word-chars '') diff --git a/Functions/Zle/select-word-match b/Functions/Zle/select-word-match index 24620c995..8440852ab 100644 --- a/Functions/Zle/select-word-match +++ b/Functions/Zle/select-word-match @@ -12,7 +12,7 @@ emulate -L zsh setopt extendedglob local curcontext=:zle:$WIDGET -local -a matched_words +local -A matched_words # Start and end of range of characters integer pos1 pos2 num=${NUMERIC:-1} local style word @@ -28,10 +28,10 @@ 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[3] ]]; then - word=$matched_words[3] + if [[ $style = i && -n $matched_words[ws-before-cursor] ]]; then + word=$matched_words[ws-before-cursor] else - word=$matched_words[2]$matched_words[3] + word=$matched_words[word-before-cursor]$matched_words[ws-before-cursor] fi if [[ -n $word ]]; then (( CURSOR -= ${#word} )) @@ -43,41 +43,40 @@ while (( num-- )); do (( CURSOR+1 == $#BUFFER )) && return 1 (( CURSOR++ )) match-words-by-style - if [[ -n $matched_words[4] ]]; then + if [[ -n $matched_words[ws-after-cursor] ]]; then if [[ $style = i ]]; then # just skip the whitespace - word=$matched_words[4] + word=$matched_words[ws-after-cursor] else # skip the whitespace plus word - word=$matched_words[4]$matched_words[5] + word=$matched_words[ws-after-cursor]$matched_words[word-after-cursor] fi else if [[ $style = i ]]; then # skip the word - word=$matched_words[5] + word=$matched_words[word-after-cursor] else # skip word and following whitespace - word=$matched_words[5]$matched_words[6] + word=$matched_words[word-after-cursor]$matched_words[ws-after-word] fi fi (( CURSOR += ${#word} - 1 )) else match-words-by-style - if [[ -n "${matched_words[3]}" ]]; then - # There's whitespace before the cursor, so the word we are selecting - # starts at the cursor position. + 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[1]}" + pos1="${#matched_words[start]}" fi - if [[ -n "${matched_words[4]}" ]]; then - if [[ -n "${matched_words[3]}" ]] || (( CURSOR == 0 )); then + 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[3]} )) - (( pos2 = CURSOR + ${#matched_words[4]} )) + (( 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. @@ -86,28 +85,28 @@ while (( num-- )); do else # No whitespace at the cursor position, so select the # current character and any following wordcharacters. - (( pos2 = CURSOR + ${#matched_words[5]} )) + (( pos2 = CURSOR + ${#matched_words[word-after-cursor]} )) fi if [[ $style = a ]]; then - if [[ -n "${matched_words[4]}" && ( -n "${matched_words[3]}" || CURSOR -eq 0 ) ]]; 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[5]}" ]]; then - (( pos2 += ${#matched_words[5]} )) # preferably the one after + if [[ -n "${matched_words[word-after-cursor]}" ]]; then + (( pos2 += ${#matched_words[word-after-cursor]} )) # preferably the one after else - (( pos1 -= ${#matched_words[2]} )) # otherwise the one before + (( pos1 -= ${#matched_words[word-before-cursor]} )) # otherwise the one before fi - elif [[ -n "${matched_words[6]}" ]]; then - (( pos2 += ${#matched_words[6]} )) - elif [[ -n "${matched_words[3]}" ]]; then + 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[3]} )) + (( 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[3]}" ]]; then - (( pos1 -= ${#matched_words[3]} )) + if [[ -n "${matched_words[ws-before-cursor]}" ]]; then + (( pos1 -= ${#matched_words[ws-before-cursor]} )) fi fi fi -- cgit v1.2.3