* Rotate shell words widget
@ 2016-05-11 8:39 Sebastian Gniazdowski
2016-05-11 21:21 ` Bart Schaefer
0 siblings, 1 reply; 7+ messages in thread
From: Sebastian Gniazdowski @ 2016-05-11 8:39 UTC (permalink / raw)
To: Zsh Users
[-- Attachment #1: Type: text/plain, Size: 636 bytes --]
Hello,
I'm sharing my widget that rotates shell words. Thus:
$(( 1 )) $( 2 ) 3
becomes
3 $(( 1 )) $( 2 )
https://asciinema.org/a/7igqc3pmyhunbqcxf09lqs1ju
To use copy the two attached files to *functions directory and add to zshrc:
# Alt-r to rotate shell words right, Alt-R - left
autoload zew-rotate-shell-words
zle -N zew-rotate-shell-words
zle -N zew-rotate-shell-words-backwards zew-rotate-shell-words
bindkey '^[r' zew-rotate-shell-words
bindkey '^[R' zew-rotate-shell-words-backwards
The widget is part of Zsh Editing Workbench plugin:
https://github.com/psprint/zsh-editing-workbench
Best regards,
Sebastian Gniazdowski
[-- Attachment #2: zew-rotate-shell-words --]
[-- Type: application/octet-stream, Size: 1368 bytes --]
# Transpose shell-words, i.e. parts of lines obtained by (Z) flag, i.e.
# as if zsh parsed the line.
#
# Code to activate the functionality with binding to Alt-t:
# autoload zew-rotate-shell-words
# zle -N zew-rotate-shell-words
# zle -N zew-rotate-shell-words-backwards zew-rotate-shell-words
# bindkey '^[r' zew-rotate-shell-words
# bindkey '^[R' zew-rotate-shell-words-backwards
local curcontext=":zle:$WIDGET"
local MATCH MBEGIN MEND i
# Prepare output variables for zew-process-buffer
local ZEW_PB_WORDS ZEW_PB_WORDS_BEGINNINGS ZEW_PB_SPACES
local ZEW_PB_SELECTED_WORD ZEW_PB_LEFT ZEW_PB_RIGHT
autoload zew-process-buffer
zew-process-buffer "$BUFFER"
# No active shell word found (shouldn't happen) (-1)
# or it's the first shell word (1), or word before first
# shell word (0)? Return
[ "$ZEW_PB_SELECTED_WORD" -le 1 ] && return 0
# Rotate
if [[ "$WIDGET" != *-backwards ]]; then
ZEW_PB_WORDS=( "${ZEW_PB_WORDS[-1]}" "${(@)ZEW_PB_WORDS[1,-2]}" )
else
ZEW_PB_WORDS=( "${(@)ZEW_PB_WORDS[2,-1]}" "${ZEW_PB_WORDS[1]}" )
fi
# Build BUFFER
integer size="${#ZEW_PB_WORDS}"
integer newcursor
buf=""
for (( i=1; i<=size; i++ )); do
buf+="$ZEW_PB_SPACES[i]$ZEW_PB_WORDS[i]"
[ "$i" = "$ZEW_PB_SELECTED_WORD" ] && newcursor="$#buf"
done
# Append final white spaces
buf+="$ZEW_PB_SPACES[i]"
BUFFER="$buf"
CURSOR="$newcursor"
return 0
# vim:ft=zsh
[-- Attachment #3: zew-process-buffer --]
[-- Type: application/octet-stream, Size: 3350 bytes --]
# 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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Rotate shell words widget
2016-05-11 8:39 Rotate shell words widget Sebastian Gniazdowski
@ 2016-05-11 21:21 ` Bart Schaefer
2016-05-12 7:07 ` Sebastian Gniazdowski
0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2016-05-11 21:21 UTC (permalink / raw)
To: Zsh Users
On May 11, 10:39am, Sebastian Gniazdowski wrote:
}
} $(( 1 )) $( 2 ) 3
}
} becomes
}
} 3 $(( 1 )) $( 2 )
What common usage did you have in mind for this?
I presume rotate acts on $RBUFFER and rotate-backwards works on $LBUFFER
(approximately).
Might want to have $NUMERIC mean something, e.g. <ESC 2 ESC r> rotates
the 2nd word after the cursor, <ESC - ESC 2 ESC r> rotates the 2nd
word counting back from the end of the line; invert for <ESC 2 ESC R>.
Or not. Whether that's useful depends on why you want this in the first
place (hence my first question).
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Rotate shell words widget
2016-05-11 21:21 ` Bart Schaefer
@ 2016-05-12 7:07 ` Sebastian Gniazdowski
2016-05-13 9:23 ` Bart Schaefer
0 siblings, 1 reply; 7+ messages in thread
From: Sebastian Gniazdowski @ 2016-05-12 7:07 UTC (permalink / raw)
To: Bart Schaefer; +Cc: Zsh Users
On 11 May 2016 at 23:21, Bart Schaefer <schaefer@brasslantern.com> wrote:
> What common usage did you have in mind for this?
>
> I presume rotate acts on $RBUFFER and rotate-backwards works on $LBUFFER
> (approximately).
I wasn't enough specific again? It rotates words in command line not
letters in words. The usage is then I think clear, to go to some
previous word, edit it, and put it in its original place again.
Alternative to Alt-b in bindkey -e.
Too relying on established word set like "shell word". Some users
might not be aware that this will allow them to rotate sophisticated
command lines with words like a\ b\ c.
Best regards,
Sebastian Gniazdowski
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Rotate shell words widget
2016-05-12 7:07 ` Sebastian Gniazdowski
@ 2016-05-13 9:23 ` Bart Schaefer
2016-05-14 21:30 ` Sebastian Gniazdowski
0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2016-05-13 9:23 UTC (permalink / raw)
To: Sebastian Gniazdowski; +Cc: Zsh Users
On Thu, May 12, 2016 at 12:07 AM, Sebastian Gniazdowski
<sgniazdowski@gmail.com> wrote:
> On 11 May 2016 at 23:21, Bart Schaefer <schaefer@brasslantern.com> wrote:
>> What common usage did you have in mind for this?
>>
>> I presume rotate acts on $RBUFFER and rotate-backwards works on $LBUFFER
>> (approximately).
>
> I wasn't enough specific again? It rotates words in command line not
> letters in words.
No, you were quite clear that it acted on words, that wasn't my
question. I used RBUFFER and LBUFFER as shorthand for "words found
after the cursor" and "words found before the cursor." Now that
you've said this ...
> The usage is then I think clear, to go to some
> previous word, edit it, and put it in its original place again.
... I see that the difference is whether you rotate the last word to
the front or the first word to the end. But why would you rotate the
words in order to edit one, rather than just move the cursor to the
word you want to change?
Also it looks like this always rotates all the words in the buffer, so
e.g. the last word moves to command position no matter what word the
cursor is on. If the reason is to be able to edit a different word,
wouldn't it make more sense to move the word at the end to the cursor
(or the word at the cursor to the end)?
> Alternative to Alt-b in bindkey -e.
I don't follow that at all. How is rotating words an alternative to
moving backward by one word?
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Rotate shell words widget
2016-05-13 9:23 ` Bart Schaefer
@ 2016-05-14 21:30 ` Sebastian Gniazdowski
2016-05-14 22:41 ` René Wilhelm
2016-05-15 10:49 ` Bart Schaefer
0 siblings, 2 replies; 7+ messages in thread
From: Sebastian Gniazdowski @ 2016-05-14 21:30 UTC (permalink / raw)
To: Bart Schaefer; +Cc: Zsh Users
On 13 May 2016 at 11:23, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Thu, May 12, 2016 at 12:07 AM, Sebastian Gniazdowski
> <sgniazdowski@gmail.com> wrote:
>> On 11 May 2016 at 23:21, Bart Schaefer <schaefer@brasslantern.com> wrote:
>> The usage is then I think clear, to go to some
>> previous word, edit it, and put it in its original place again.
>
> ... I see that the difference is whether you rotate the last word to
> the front or the first word to the end. But why would you rotate the
> words in order to edit one, rather than just move the cursor to the
> word you want to change?
I thought about it as an extension of transpose-words, which I use
instead of Alt-b pressed once. Now I see transpose-words can be used
to e.g. revert "mv" command by doing opposite rename (not that I
didn't use it that way). Well, I always preferred transposing than
Alt-b-jumping and cursor keys. Careful positioning with Alt-b and
cursor keys, and then Ctrl-E to continue at the end, I don't like it.
> Also it looks like this always rotates all the words in the buffer, so
> e.g. the last word moves to command position no matter what word the
> cursor is on. If the reason is to be able to edit a different word,
> wouldn't it make more sense to move the word at the end to the cursor
> (or the word at the cursor to the end)?
I'm not fully following this, maybe an example? Seems sophisticated, though.
Best regards,
Sebastian Gniazdowski
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Rotate shell words widget
2016-05-14 21:30 ` Sebastian Gniazdowski
@ 2016-05-14 22:41 ` René Wilhelm
2016-05-15 10:49 ` Bart Schaefer
1 sibling, 0 replies; 7+ messages in thread
From: René Wilhelm @ 2016-05-14 22:41 UTC (permalink / raw)
To: Sebastian Gniazdowski; +Cc: Bart Schaefer, Zsh Users
[-- Attachment #1: Type: text/plain, Size: 786 bytes --]
On 14 May 2016 at 23:30, Sebastian Gniazdowski <sgniazdowski@gmail.com>
wrote:
> I thought about it as an extension of transpose-words, which I use
> instead of Alt-b pressed once. Now I see transpose-words can be used
> to e.g. revert "mv" command by doing opposite rename (not that I
> didn't use it that way). Well, I always preferred transposing than
> Alt-b-jumping and cursor keys. Careful positioning with Alt-b and
> cursor keys, and then Ctrl-E to continue at the end, I don't like it.
>
You can prefix most things with a number, like <ESC 2 ESC b> to move the
cursor two words backwards. In conjunction with a little intuitive counting
(https://en.wikipedia.org/wiki/Subitizing), this should allow for pretty
good cursor positioning. Hope that helps.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Rotate shell words widget
2016-05-14 21:30 ` Sebastian Gniazdowski
2016-05-14 22:41 ` René Wilhelm
@ 2016-05-15 10:49 ` Bart Schaefer
1 sibling, 0 replies; 7+ messages in thread
From: Bart Schaefer @ 2016-05-15 10:49 UTC (permalink / raw)
To: Sebastian Gniazdowski; +Cc: Zsh Users
On Sat, May 14, 2016 at 2:30 PM, Sebastian Gniazdowski
<sgniazdowski@gmail.com> wrote:
> On 13 May 2016 at 11:23, Bart Schaefer <schaefer@brasslantern.com> wrote:
>> Also it looks like this always rotates all the words in the buffer, so
>> e.g. the last word moves to command position no matter what word the
>> cursor is on. If the reason is to be able to edit a different word,
>> wouldn't it make more sense to move the word at the end to the cursor
>> (or the word at the cursor to the end)?
>
> I'm not fully following this, maybe an example? Seems sophisticated, though.
Suppose I have:
% echo one two three four
and the cursor is on the "w". With your widget as-is, rotating "forward" gives
% four echo one two three
with the cursor on the space between "one" and "two". I don't
understand why someone would ever want to do that. It doesn't make
sense for "four" to become the command word, and the final cursor
placement isn't helpful. (Also the choice of calling this "forward"
rotation is a bit arbitrary, because the most obvious change is that
"four" moved *backward*, it's the rest of the line that went forward;
but you can define it either way.) If instead rotate forward produced
% echo one four two three
with the cursor either still on the "w" or somewhere in the word
"four", that might have some utility. (This is what I meant by "acts
on $RBUFFER"). Similarly I'd expect rotate backward to do one of
% echo one three four two
OR ("acts on $LBUFFER")
% two echo one three four
though again I don't know why you'd shift a different word into
command position. Maybe "rotate-arguments" would be a better widget,
something that would produce
% echo four one two three
i.e. without moving the "echo".
And in that case ESC 2 ESC r would produce
% echo three four one two
Cursor placement still needs some thought.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-05-15 10:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-11 8:39 Rotate shell words widget Sebastian Gniazdowski
2016-05-11 21:21 ` Bart Schaefer
2016-05-12 7:07 ` Sebastian Gniazdowski
2016-05-13 9:23 ` Bart Schaefer
2016-05-14 21:30 ` Sebastian Gniazdowski
2016-05-14 22:41 ` René Wilhelm
2016-05-15 10:49 ` Bart Schaefer
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).