zsh-users
 help / color / mirror / code / Atom feed
* 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

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).