Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[tip] mouse and mouse-wheel support!
- X-seq: zsh-users 8209
- From: Stephane Chazelas <Stephane_Chazelas@xxxxxxxx>
- To: Zsh users list <zsh-users@xxxxxxxxxx>
- Subject: [tip] mouse and mouse-wheel support!
- Date: Fri, 12 Nov 2004 12:02:48 +0000
- In-reply-to: <20041111122011.GB4451@sc>
- Mail-followup-to: Zsh users list <zsh-users@xxxxxxxxxx>
- Mailing-list: contact zsh-users-help@xxxxxxxxxx; run by ezmlm
- References: <20041111122011.GB4451@sc>
Ok, thanks to the help of Peter, Bart and Andy, here is a new
version.
Improvements:
- it handles the multi-line buffers correctly (except in minor
corner cases I didn't bother to fix)
- the prompt handling has been improved
- now there are two mouse modes:
o the first one, when ZLE_USE_MOUSE is set to 1, that uses
xterm mouse tracking (works with rxvt, gnome-terminal,
xterm but doesn't support mouse wheel)
o a new one that will probably work only with xterm (note
that (XFree86) xterm has 256 color, UTF8 support, a better
mouse support, a better font display... than rxvt or
gnome-terminal so why bother with other terminals).
You need to modify your resource file (~/.Xdefaults-host or
~/.Xdefaults or $XENVIRONMENT or $XAPP_RESDIR or
$XUSERFILESEARCHPATH..., see your man page for X) as
described below.
Note that the mouse wheel behavior is not connected to those
functions, it's just that the translation table tells Xterm to
send ^N and ^P characters on mouse wheel events (with modifier
Mod4).
So, it should work with every application that recognizes those
keys as <Down> and <Up>, not only zsh (readline (bash, gdb,
rc...), emacs, vim...).
### code begin
# Add that to your X resource file to have wheel-mouse support
# and <Mod4-Button> when ZLE_USE_MOUSE is off under xterm
# (remove the #)
#!!!BEGIN
#XTerm.VT100.translations: #override\
# Mod4 <Btn1Down>,<Btn1Up>: string(0x1b) string("[M ") dired-button()\n\
# Mod4 <Btn2Down>,<Btn2Up>: string(0x1b) string("[M!") dired-button()\n\
# Mod4 <Btn3Down>,<Btn3Up>: string(0x1b) string("[M") string(0x22) dired-button()\n\
# Mod4 <Btn5Down>,<Btn5Up>: string(0xe)\n\
# Mod4 <Btn4Down>,<Btn4Up>: string(0x10)
#!!!END
# note that you need to hold whatever key puts you in the "Mod4"
# (for me, it's the MS Windows keys aka "Super", see xmodmap -pm
# for details)
if [[ $TERM = *xterm* || $TERM = *rxvt* ]]; then
zmodload -i zsh/parameter
set-status() { return $1; }
zle-xterm-mouse() {
local last_status=$?
emulate -L zsh
setopt extendedglob # for (#b)
local bt mx my cy i buf
read -k bt # mouse button, x, y reported after \e[M
bt=$((#bt & 7))
read -k mx
read -k my
if [[ $mx = $'\030' ]]; then
# assume btns were mapped to \E[M<btn>dired-button()(^X\EG<x><y>)
read -k mx
read -k mx
read -k my
(( my = #my - 31 ))
(( mx = #mx - 31 ))
ZLE_MOUSE_BUTTON=$bt
else
(( my = #my - 32 ))
(( mx = #mx - 32 ))
if [[ $bt != 3 ]]; then
# Process on release, but record the button on press.
ZLE_MOUSE_BUTTON=$bt
return 0
fi
fi
print -n '\e[6n' # query cursor position
while read -k i && [[ $i != R ]]; do buf+=$i; done
local match mbegin mend
[[ $buf = (#b)??(*)\;* ]] || return
cy=$match[1]
# we don't need cx
local cur_prompt
if [[ -n $PREBUFFER ]]; then
cur_prompt=$PS2
# decide wether we're at the PS2 or PS1 prompt
else
cur_prompt=$PS1
fi
[[ -o promptsubst ]] && cur_prompt=${${(e)cur_prompt}//(#b)([\\\$\`])/\\$match}
# restore the exit status in case $PS<n> relies on it
set-status $last_status
cur_prompt=${(S%%)cur_prompt//(#b)(%([BSUbsu]|{*%})|(%[^BSUbsu{}]))/$match[3]}
local -a pos # array holding the possible positions of
# the mouse pointer
local -i x=0 y=1 cursor=$((${#cur_prompt}+$CURSOR+1))
local Y
buf=$cur_prompt$BUFFER
for ((i=1; i<=$#buf; i++)); do
(( i == cursor )) && Y=$y
case $buf[i] in
($'\n') # newline
: ${pos[y]=$i}
(( y++, x=0 ));;
($'\t') # tab advance til next tab stop
(( x = x/8*8+8 ));;
([$'\0'-$'\037'$'\0200'-$'\0237'])
# characters like ^M
(( x += 2 ));;
# may cause trouble if spanned on two lines but well...
(*)
(( x++ ));;
esac
(( x >= mx )) && : ${pos[y]=$i}
(( x >= COLUMNS )) && (( x=0, y++ ))
done
: ${pos[y]=$i} ${Y:=$y}
local mouse_CURSOR
if ((my + Y - cy > y)); then
mouse_CURSOR=$#BUFFER
elif ((my + Y - cy < 1)); then
mouse_CURSOR=0
else
mouse_CURSOR=$(($pos[my + Y - cy] - ${#cur_prompt} - 1))
fi
case $ZLE_MOUSE_BUTTON in
(0)
# Button 1. Move cursor.
CURSOR=$mouse_CURSOR
;;
(1)
# Button 2. Insert selection at mouse cursor postion.
BUFFER=$BUFFER[1,mouse_CURSOR]$CUTBUFFER$BUFFER[mouse_CURSOR+1,-1]
(( CURSOR = $mouse_CURSOR + $#CUTBUFFER ))
;;
(2)
# Button 3. Copy from cursor to mouse to cutbuffer.
killring=("$CUTBUFFER" "${(@)killring[1,-2]}")
if (( mouse_CURSOR < CURSOR )); then
CUTBUFFER=$BUFFER[mouse_CURSOR+1,CURSOR+1]
else
CUTBUFFER=$BUFFER[CURSOR+1,mouse_CURSOR+1]
fi
;;
esac
}
zle-toggle-mouse() {
# If no prefix, toggle state.
# If positive prefix, turn on.
# If zero or negative prefix, turn off.
# Allow this to be used as a normal function, too.
if [[ -n $1 ]]; then
local PREFIX=$1
fi
if (( $+PREFIX )); then
if (( PREFIX > 0 )); then
ZLE_USE_MOUSE=1
else
ZLE_USE_MOUSE=
fi
else
if [[ -n $ZLE_USE_MOUSE ]]; then
ZLE_USE_MOUSE=
else
ZLE_USE_MOUSE=1
fi
fi
if [[ -n $WIDGET ]]; then
# Zle is currently active.
# Make sure it's turned on or off straight away if required.
if [[ -n $ZLE_USE_MOUSE ]]; then
print -n '\e[?1000h'
else
print -n '\e[?1000l'
fi
fi
}
if [[ $functions[precmd] != *ZLE_USE_MOUSE* ]]; then
functions[precmd]+='
[[ -n $ZLE_USE_MOUSE ]] && print -n '\''\e[?1000h'\'
fi
if [[ $functions[preexec] != *ZLE_USE_MOUSE* ]]; then
functions[preexec]+='
[[ -n $ZLE_USE_MOUSE ]] && print -n '\''\e[?1000l'\'
fi
zle -N zle-xterm-mouse
bindkey '\e[M' zle-xterm-mouse
zle -N zle-toggle-mouse
fi
### code end
--
Stéphane
Messages sorted by:
Reverse Date,
Date,
Thread,
Author