Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: bug with camel case and delete-whole-word-match function
- X-seq: zsh-workers 38929
- From: Oliver Kiddle <okiddle@xxxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: Re: bug with camel case and delete-whole-word-match function
- Date: Sun, 24 Jul 2016 01:06:02 +0200
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.co.uk; s=s2048; t=1469315162; bh=UTCfRThy6J3tqS3UzzinllMBM4YeT4jQA+LC1oeWwOU=; h=In-reply-to:From:References:To:Subject:Date:From:Subject; b=fm6KOSn/rem/dzGYwCsu57IJXQ4EewLhOrKQ+UgK2sB+LudjctptAzIWWK3MhmpmoSzf6KwgT3wRydGDMNEYzF5Jxz1YXpjFLH2UMADNxm4JuKuvtqeYQ2g1dt7oAB//aUrOkTe5/JswNhyyNnmD3AocD5K35mtuNMhcr361FqPCFljw6vC94dngPaZzbbUgi5WCR7KA63a/6BSvHyGX6mpdFmiBekBkPkjjIeeue7ZeSoymHhWCzOrCeiq+C2U283nYpLa1TNAQYtg48stTDJaXAHUvDXREDzRRTVBUlOAdh+U2mPuW3NdK8dVZo/CL8iCTwFfSiWsSGtTzNFaMXw==
- In-reply-to: <20160705111900.7e1599f0@pwslap01u.europe.root.pri>
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
- References: <588168129.3340906.1467709726474.JavaMail.yahoo.ref@mail.yahoo.com> <588168129.3340906.1467709726474.JavaMail.yahoo@mail.yahoo.com> <20160705111900.7e1599f0@pwslap01u.europe.root.pri>
On 5 Jul, Peter wrote:
> If you have "ThisIsSomeWords"
> However, if you're on the "S", you get "Is" before and "Some" after.
> Again there's no white space, so there's nothing to indicate to the
> calling function that these are two separate words rather than bits of
> the same word. So I think we'd need to add some extra signalling from
> match-words-by-style to indicate "I'm at a word start" whether or not
> there's white space, which needs some thinking about.
Do we need to keep the existing seven elements of matched_words
unchanged for backwards compatibility? Not that I can think of a
particularly obvious way to augment it for this case. May be just
a 1/0 indicator for start of word is the simplest. It also seems
to lack having a <whitespace before the word> field.
I've attached a patch for a select-word-match function which uses the
mechanism for a vim style text object. In the process, I've found a
couple of other issues with match-words-by-style:
One is that if the cursor is in the middle of a block of whitespace
at the end of the line, the 4th element (whitespace after cursor)
is empty while element 7 contains the whitespace.
A similar issue occurs at the start of the line - element 1 contains
whitespace while element 3 doesn't.
The other issue is that with the shell word style, it'll put whitespace
at the end of element 5 instead of in element 6.
Oliver
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 1d2b7ca..c3dec34 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -1940,6 +1940,8 @@ tindex(transpose-words-match)
tindex(capitalize-word-match)
tindex(up-case-word-match)
tindex(down-case-word-match)
+tindex(delete-whole-word-match)
+tindex(select-word-match)
tindex(select-word-style)
tindex(match-word-context)
tindex(match-words-by-style)
@@ -1947,12 +1949,14 @@ xitem(tt(forward-word-match), tt(backward-word-match))
xitem(tt(kill-word-match), tt(backward-kill-word-match))
xitem(tt(transpose-words-match), tt(capitalize-word-match))
xitem(tt(up-case-word-match), tt(down-case-word-match))
+xitem(tt(delete-whole-word-match), tt(select-word-match))
item(tt(select-word-style), tt(match-word-context), tt(match-words-by-style))(
-The eight `tt(-match)' functions are drop-in replacements for the
+The first eight `tt(-match)' functions are drop-in replacements for the
builtin widgets without the suffix. By default they behave in a similar
way. However, by the use of styles and the function tt(select-word-style),
-the way words are matched can be altered. For comparison, the widgets
-described in ifzman(zmanref(zshzle) under Text Objects)\
+the way words are matched can be altered. tt(select-word-match) is intended
+to be used as a text object in vi mode but with custom word styles. For
+comparison, the widgets described in ifzman(zmanref(zshzle) under Text Objects)\
ifnzman(noderef(Text Objects)) use fixed definitions of words, compatible
with the tt(vim) editor.
@@ -1960,7 +1964,7 @@ The simplest way of configuring the functions is to use
tt(select-word-style), which can either be called as a normal function with
the appropriate argument, or invoked as a user-defined widget that will
prompt for the first character of the word style to be used. The first
-time it is invoked, the eight tt(-match) functions will automatically
+time it is invoked, the first eight tt(-match) functions will automatically
replace the builtin versions, so they do not need to be loaded explicitly.
The word styles available are as follows. Only the first character
diff --git a/Functions/Zle/select-word-match b/Functions/Zle/select-word-match
new file mode 100644
index 0000000..24620c9
--- /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
Messages sorted by:
Reverse Date,
Date,
Thread,
Author