diff --git a/Functions/Zle/transpose-segments b/Functions/Zle/transpose-segments new file mode 100644 index 0000000..313febf --- /dev/null +++ b/Functions/Zle/transpose-segments @@ -0,0 +1,82 @@ +# Transpose segments, i.e. parts of line obtained by (z) flag, i.e. +# as if zsh parsed the line. +# +# Code to activate the functionality with Alt-t: +# autoload transpose-segments +# zle -N transpose-segments +# bindkey "^[t" transpose-segments + +local curcontext=":zle:$WIDGET" skip +local MATCH MBEGIN MEND + +# Will remember white spaces before each segment +typeset -a spaces +spaces=() + +# Working variable for $BUFFER +local buf="$BUFFER" + +# Split the buffer +typeset -a bufarr +bufarr=( "${(z)buf}" ) + +# (z) handles spaces nicely, but we need them for the user +integer size="$#bufarr" +integer char_count=0 +integer selected_segment=0 + +for (( i=1; i<=size; i++ )); do + local segment="$bufarr[i]" + + # In general, $buf can start with white spaces + # We will not search for them, but instead + # search for any char that's current segment's + # leading character. So this is an approach that + # doesn't trust [::space::] + + local leadchar="$segment[1]" + buf="${buf##(#m)[^$leadchar]#}" + + # Remember the spaces + spaces[$i]="$MATCH" + + # Count all characters being processed, remove the spaces, then remove segment + char_count=char_count+"$#MATCH"+"$#segment" + buf="${buf#$MATCH}" + MATCH="" + buf="${buf#(#m)$segment}" + + # If segment not found, return from the function doing nothing + # This of course shoudln't happen + [ -z "$MATCH" ] && return 0 + + # Detect which segment is active + [[ "$selected_segment" -eq 0 && "$char_count" -ge "$CURSOR" ]] && selected_segment=i +done + + +# What's left in $buf can be only white spaces +spaces[i]="$buf" +char_count=char_count+"$#buf" + +[[ "$selected_segment" -eq 0 && "$char_count" -ge "$CURSOR" ]] && selected_segment=i-1 +# No active segment found, or it's a first segment? Return. (this shouldn't happen) +[[ "$selected_segment" -eq "0" || "$selected_segment" -eq "1" ]] && return 0 + +# Swap segments +local tmp="$bufarr[selected_segment]" +bufarr[selected_segment]="$bufarr[selected_segment-1]" +bufarr[selected_segment-1]="$tmp" + +# Build BUFFER +integer curbkp="$CURSOR" +BUFFER="" +for (( i=1; i<=size; i++ )); do + BUFFER+="$spaces[i]$bufarr[i]" +done +CURSOR="$curbkp" + +# Append final white spaces +BUFFER+="$spaces[i]" + +return 0