* [tip] mouse support
@ 2004-11-11 12:20 Stephane Chazelas
2004-11-11 14:40 ` Peter Stephenson
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-11 12:20 UTC (permalink / raw)
To: Zsh users list
Hi zsh users,
I just posted that to comp.unix.shell, I thought it might be of
some interest for some of you. Basically, it's cursor
positionning with the mouse under xterm like terminals (works
with xterm, gnome-terminal and rxvt AFAICS, probably also with
putty, not if there are tabs or NLs (or multi-byte characters)
in the zle buffer).
I'm not used to writing zle code. Please tell me what you think.
### code begins
if [[ $TERM = *xterm* ]]; then
zle-xterm-mouse() {
emulate -L zsh
setopt extendedglob # for (#b)
local bt mx my cx cy i match mbegin mend
read -k bt # mouse button, x, y reported after \e[M
read -k mx
read -k my
[[ $bt = "#" ]] || return 0 # only for btn1 release
print -n '\e[6n' # query cursor position
while read -k i && [[ $i != R ]]; do cx+=$i; done
# can't use read -d R in zle
[[ $cx = (#b)??(*)\;(*) ]] || return
cy=$match[1]
cx=$match[2]
(( CURSOR += #mx - 32 - cx + (#my - 32 - cy) * COLUMNS ))
return 0
}
precmd() {
# enable mouse tracking
print -n '\e[?1000h'
}
preexec() {
# disable mouse tracking
print -n '\e[?1000l'
}
zle -N zle-xterm-mouse zle-xterm-mouse
bindkey '\e[M' zle-xterm-mouse
fi
### code ends
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 12:20 [tip] mouse support Stephane Chazelas
@ 2004-11-11 14:40 ` Peter Stephenson
2004-11-11 16:22 ` Stephane Chazelas
2004-11-11 16:07 ` Andy Spiegl
2004-11-12 12:02 ` [tip] mouse and mouse-wheel support! Stephane Chazelas
2 siblings, 1 reply; 13+ messages in thread
From: Peter Stephenson @ 2004-11-11 14:40 UTC (permalink / raw)
To: Zsh users list
Stephane Chazelas wrote:
> I just posted that to comp.unix.shell, I thought it might be of
> some interest for some of you. Basically, it's cursor
> positionning with the mouse under xterm like terminals (works
> with xterm, gnome-terminal and rxvt AFAICS, probably also with
> putty, not if there are tabs or NLs (or multi-byte characters)
> in the zle buffer).
This is very useful. (Other people should note it's only useful with
the current zsh editing buffer; there's no way of accessing other
information on the screen.)
I've extended it. Other people may have suggestions, too. This
probably requires zsh 4.2 to use the cutbuffer and killring.
Button 1 is as before.
Button 2 pastes the zsh cutbuffer at the mouse position. This
is identical to yank. It also emulates normal xterm behaviour
by pasting at the cursor, not the mouse position. This seemed
less surprising but is easy to change or make optional.
Button 3 copies the region from the cursor to the mouse position
into the zsh cutbuffer. This is like copy-region-as-kill but
doesn't use the zsh mark. (I could set that too, I suppose.)
Note I'm not 100% confident the limits (i.e. indices into the editing
buffer) used are the best ones.
Note no use is made of the X selection mechanism.
Other additions
- It takes care to change the existing precmd and preexec rather
than overwriting them. This won't work if there is a "return"
earlier in either. Possibly the new lines should go at the top.
- There's a function/widget zle-toggle-mouse to switch between normal
xterm mouse and zle mouse. Positive prefix forces zle mouse,
negative or zero prefix forces normal xterm mouse.
The version of code below is designed to be used as a (normal,
i.e. non-zle) function, called eg. setup-zle-mouse. (Naming might need
rationalising, too.)
### code begins
[[ $TERM = *xterm* ]] || return
zmodload -i zsh/parameter
zle-xterm-mouse() {
emulate -L zsh
setopt extendedglob # for (#b)
local bt mx my cx cy i match mbegin mend text
integer rel
read -k bt # mouse button, x, y reported after \e[M
read -k mx
read -k my
if [[ $bt != "#" ]]; then
# Process on release, but record the button on press.
ZLE_MOUSE_BUTTON=$bt
return
fi
print -n '\e[6n' # query cursor position
while read -k i && [[ $i != R ]]; do cx+=$i; done
# can't use read -d R in zle
[[ $cx = (#b)??(*)\;(*) ]] || return
cy=$match[1]
cx=$match[2]
# Relative position between cursor and mouse.
(( rel = #mx - 32 - cx + (#my - 32 - cy) * COLUMNS ))
case $ZLE_MOUSE_BUTTON in
(' ')
# Button 1. Move cursor.
(( CURSOR += rel ))
;;
('!')
# Button 2. Insert selection at cursor postion.
LBUFFER+=$CUTBUFFER
;;
('"')
# Button 3. Copy from cursor to mouse to cutbuffer.
if (( rel > 0 )); then
text=${RBUFFER[1,rel]}
elif (( CURSOR + rel > 0 )); then
text=${LBUFFER[rel,-1]}
else
text=$LBUFFER
fi
killring=("$CUTBUFFER" "${(@)killring[1,-2]}")
CUTBUFFER=$text
;;
esac
return 0
}
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
ZLE_USE_MOUSE=1
### code ends
--
Peter Stephenson <pws@csr.com> Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070
**********************************************************************
This email and any files transmitted with it are confidential and
intended solely for the use of the individual or entity to whom they
are addressed. If you have received this email in error please notify
the system manager.
This footnote also confirms that this email message has been swept by
MIMEsweeper for the presence of computer viruses.
www.mimesweeper.com
**********************************************************************
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 12:20 [tip] mouse support Stephane Chazelas
2004-11-11 14:40 ` Peter Stephenson
@ 2004-11-11 16:07 ` Andy Spiegl
2004-11-11 17:26 ` Stephane Chazelas
2004-11-12 12:02 ` [tip] mouse and mouse-wheel support! Stephane Chazelas
2 siblings, 1 reply; 13+ messages in thread
From: Andy Spiegl @ 2004-11-11 16:07 UTC (permalink / raw)
To: Zsh users list
Hi Stephane,
wow great idea! Not that I use the mouse a lot while typing in the
shell but sometimes it would really be useful, especially with very
long lines or multiline commands.
With multilines it doesn't work however. :-(
And it also breaks the usual copy&paste behaviour. It is necessary
to hold the SHIFT key to be able to copy&paste. Hm, maybe it would
be better to just get the new behaviour holding down some modifier key.
Any other opinions?
Andy.
--
o _ _ _
------- __o __o /\_ _ \\o (_)\__/o (_) -o)
----- _`\<,_ _`\<,_ _>(_) (_)/<_ \_| \ _|/' \/ /\\
---- (_)/ (_) (_)/ (_) (_) (_) (_) (_)' _\o_ _\_v
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Being adopted means that you grew in your mother's heart
instead of her tummy. (Jocelynn, http://adoption.here.de/)
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 14:40 ` Peter Stephenson
@ 2004-11-11 16:22 ` Stephane Chazelas
2004-11-11 17:47 ` Bart Schaefer
0 siblings, 1 reply; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-11 16:22 UTC (permalink / raw)
To: Zsh users list
On Thu, Nov 11, 2004 at 02:40:32PM +0000, Peter Stephenson wrote:
> Stephane Chazelas wrote:
> > I just posted that to comp.unix.shell, I thought it might be of
> > some interest for some of you. Basically, it's cursor
> > positionning with the mouse under xterm like terminals (works
> > with xterm, gnome-terminal and rxvt AFAICS, probably also with
> > putty, not if there are tabs or NLs (or multi-byte characters)
> > in the zle buffer).
>
> This is very useful. (Other people should note it's only useful with
> the current zsh editing buffer; there's no way of accessing other
> information on the screen.)
In that new one, I tried to address the tab/newline issue.
It tries to calculate the length of the last line of the prompt,
it may fail if PS1 contains %%s or %{ %{ ... %} %} or if two
consecutive expansions of PS1 may not generate the same thing,
it would be nice to have access at what zsh thinks is the
cursor horizontal position at begining of buffer.
> I've extended it. Other people may have suggestions, too. This
> probably requires zsh 4.2 to use the cutbuffer and killring.
>
> Button 1 is as before.
>
> Button 2 pastes the zsh cutbuffer at the mouse position. This
> is identical to yank. It also emulates normal xterm behaviour
> by pasting at the cursor, not the mouse position. This seemed
> less surprising but is easy to change or make optional.
I changed for "pasting at the mouse cursor".
> Button 3 copies the region from the cursor to the mouse position
> into the zsh cutbuffer. This is like copy-region-as-kill but
> doesn't use the zsh mark. (I could set that too, I suppose.)
> Note I'm not 100% confident the limits (i.e. indices into the editing
> buffer) used are the best ones.
Not sure of mines either ;).
> Other additions
> - It takes care to change the existing precmd and preexec rather
> than overwriting them. This won't work if there is a "return"
> earlier in either. Possibly the new lines should go at the top.
Thanks for that. I didn't know about the $functions hash.
> - There's a function/widget zle-toggle-mouse to switch between normal
> xterm mouse and zle mouse. Positive prefix forces zle mouse,
> negative or zero prefix forces normal xterm mouse.
You can use hold the <Shift> key to have the normal xterm
behavior.
Here's the code. Be careful when you bullet proof it, it may be
full of bugs...
### code begin
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
read -k mx
read -k my
if [[ $bt != "#" ]]; then
# Process on release, but record the button on press.
ZLE_MOUSE_BUTTON=$bt
return 0
fi
(( my = #my - 32 ))
(( mx = #mx - 32 ))
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
if [[ -o promptsubst ]]; then
cur_prompt=${(e)cur_prompt}
else
cur_prompt=$cur_prompt
fi
# remove visual effects:
cur_prompt=${(S)cur_prompt//("%{"*"%}"|%[BbEuUsS])/}
# restore the exit status in case $PS<n> relies on it
set-status $last_status
cur_prompt=${(%)cur_prompt}
cur_prompt=${cur_prompt##*$'\n'}
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
(' ')
# Button 1. Move cursor.
CURSOR=$mouse_CURSOR
;;
('!')
# Button 2. Insert selection at mouse cursor postion.
BUFFER=$BUFFER[1,mouse_CURSOR]$CUTBUFFER$BUFFER[mouse_CURSOR+1,-1]
(( CURSOR = $mouse_CURSOR + $#CUTBUFFER ))
;;
('"')
# 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
}
### code ends
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 16:07 ` Andy Spiegl
@ 2004-11-11 17:26 ` Stephane Chazelas
0 siblings, 0 replies; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-11 17:26 UTC (permalink / raw)
To: Zsh users list
On Thu, Nov 11, 2004 at 05:07:36PM +0100, Andy Spiegl wrote:
[...]
> wow great idea! Not that I use the mouse a lot while typing in the
> shell but sometimes it would really be useful, especially with very
> long lines or multiline commands.
>
> With multilines it doesn't work however. :-(
The new one I provided fixes that.
> And it also breaks the usual copy&paste behaviour. It is necessary
> to hold the SHIFT key to be able to copy&paste. Hm, maybe it would
> be better to just get the new behaviour holding down some modifier key.
[...]
I don't think it is possible. We'd have to tell xterm to send
the mouse tracking escape sequences on other events than the
default ones, and I don't think it is possible.
We could map any action on <Ctrl-btn<n>> but not the sending of
the cursor position. We may be able to do something with
dired-button(), though.
That would involve install a new translation table, you could
map:
someModifiers <BtnDown1>: string(0x1b) string("[M1") dired-button()\n\
someModifiers <BtnDown2>: string(0x1b) string("[M2") dired-button()\n\
someModifiers <BtnDown3>: string(0x1b) string("[M3") dired-button()\n\
and modify the code of zle-xterm-mouse so that it recognizes
those new sequences.
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 16:22 ` Stephane Chazelas
@ 2004-11-11 17:47 ` Bart Schaefer
2004-11-11 18:05 ` Stephane Chazelas
2004-11-11 18:22 ` Stephane Chazelas
0 siblings, 2 replies; 13+ messages in thread
From: Bart Schaefer @ 2004-11-11 17:47 UTC (permalink / raw)
To: Stephane Chazelas; +Cc: Zsh users list
On Thu, 11 Nov 2004, Stephane Chazelas wrote:
> In that new one, I tried to address the tab/newline issue.
> It tries to calculate the length of the last line of the prompt,
> it may fail if PS1 contains %%s or %{ %{ ... %} %} or if two
> consecutive expansions of PS1 may not generate the same thing
There's some code in Functions/Prompts/prompt_bart_setup in the function
prompt_bart_precmd that computes the width of prompt strings. It's been
specialized to expect to compute only the width of the first line of a
two-line PS1, but it shouldn't be hard to adapt.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 17:47 ` Bart Schaefer
@ 2004-11-11 18:05 ` Stephane Chazelas
2004-11-11 18:22 ` Stephane Chazelas
1 sibling, 0 replies; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-11 18:05 UTC (permalink / raw)
To: Zsh users list
On Thu, Nov 11, 2004 at 09:47:02AM -0800, Bart Schaefer wrote:
> On Thu, 11 Nov 2004, Stephane Chazelas wrote:
>
> > In that new one, I tried to address the tab/newline issue.
> > It tries to calculate the length of the last line of the prompt,
> > it may fail if PS1 contains %%s or %{ %{ ... %} %} or if two
> > consecutive expansions of PS1 may not generate the same thing
>
> There's some code in Functions/Prompts/prompt_bart_setup in the function
> prompt_bart_precmd that computes the width of prompt strings. It's been
> specialized to expect to compute only the width of the first line of a
> two-line PS1, but it shouldn't be hard to adapt.
Hi Bart,
we actually chose the same approach, it suffers from the same
problems:
zero='%([BSUbsu]|{*%})'
It replaces '%%some %{%{some%}%}' with '%ome %}' instead of
'%%some '
Thanks for the (%%) flag, though.
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 17:47 ` Bart Schaefer
2004-11-11 18:05 ` Stephane Chazelas
@ 2004-11-11 18:22 ` Stephane Chazelas
2004-11-12 1:02 ` Bart Schaefer
1 sibling, 1 reply; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-11 18:22 UTC (permalink / raw)
To: Zsh users list
On Thu, Nov 11, 2004 at 09:47:02AM -0800, Bart Schaefer wrote:
> On Thu, 11 Nov 2004, Stephane Chazelas wrote:
>
> > In that new one, I tried to address the tab/newline issue.
> > It tries to calculate the length of the last line of the prompt,
> > it may fail if PS1 contains %%s or %{ %{ ... %} %} or if two
> > consecutive expansions of PS1 may not generate the same thing
>
> There's some code in Functions/Prompts/prompt_bart_setup in the function
> prompt_bart_precmd that computes the width of prompt strings. It's been
> specialized to expect to compute only the width of the first line of a
> two-line PS1, but it shouldn't be hard to adapt.
Well the (%%) expansion flag has another problem:
var='%Sfoo%s'
PS1='$var'
In that case, you need to expand first the variables in PS1 or
you'll miss the %S %s visual sequences.
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-11 18:22 ` Stephane Chazelas
@ 2004-11-12 1:02 ` Bart Schaefer
2004-11-12 9:22 ` Stephane Chazelas
0 siblings, 1 reply; 13+ messages in thread
From: Bart Schaefer @ 2004-11-12 1:02 UTC (permalink / raw)
To: Stephane Chazelas; +Cc: Zsh users list
On Thu, 11 Nov 2004, Stephane Chazelas wrote:
> zero='%([BSUbsu]|{*%})'
>
> It replaces '%%some %{%{some%}%}' with '%ome %}' instead of
> '%%some '
Hmm. To fix that, you need extended globbing:
setopt extendedglob
zero='(#b)([^%]|(#s))%([BSUbsu]|{*%})'
print ${(%%)PS1//$~zero/$match[1]}
On Thu, 11 Nov 2004, Stephane Chazelas wrote:
> Well the (%%) expansion flag has another problem:
>
> var='%Sfoo%s'
> PS1='$var'
>
> In that case, you need to expand first the variables in PS1 or
> you'll miss the %S %s visual sequences.
That's easy enough:
if [[ -o promptsubst ]]
then print ${(%%)${(e)PS1}//$~zero/$match[1]}
else print ${(%%)PS1//$~zero/$match[1]}
fi
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse support
2004-11-12 1:02 ` Bart Schaefer
@ 2004-11-12 9:22 ` Stephane Chazelas
0 siblings, 0 replies; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-12 9:22 UTC (permalink / raw)
To: Zsh users list
On Thu, Nov 11, 2004 at 05:02:47PM -0800, Bart Schaefer wrote:
> On Thu, 11 Nov 2004, Stephane Chazelas wrote:
>
> > zero='%([BSUbsu]|{*%})'
> >
> > It replaces '%%some %{%{some%}%}' with '%ome %}' instead of
> > '%%some '
>
> Hmm. To fix that, you need extended globbing:
>
> setopt extendedglob
> zero='(#b)([^%]|(#s))%([BSUbsu]|{*%})'
> print ${(%%)PS1//$~zero/$match[1]}
[...]
That moves the problem (the first one)
ow, there's a problem with '%%%S'
A better fix:
zero='(#b)(%([BSUbsu]|{*%})|(%[^BSUbsu{}]))'
print ${(S%%)PS1//$~zero/$match[3]}
But, it still doesn't fix the problem of nested %{ (maybe not
too big an issue, as I can't think of any case where nesting
%{'s can be useful).
> On Thu, 11 Nov 2004, Stephane Chazelas wrote:
>
> > Well the (%%) expansion flag has another problem:
> >
> > var='%Sfoo%s'
> > PS1='$var'
> >
> > In that case, you need to expand first the variables in PS1 or
> > you'll miss the %S %s visual sequences.
>
> That's easy enough:
>
> if [[ -o promptsubst ]]
> then print ${(%%)${(e)PS1}//$~zero/$match[1]}
> else print ${(%%)PS1//$~zero/$match[1]}
> fi
Yes, that was what I did. Except that I used (%) instead of
(%%). But with (%%) PS1 may be expanded again (PS1='$(echo "\$foo")')
So a refined solution could be:
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]}
what do you think?
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
* [tip] mouse and mouse-wheel support!
2004-11-11 12:20 [tip] mouse support Stephane Chazelas
2004-11-11 14:40 ` Peter Stephenson
2004-11-11 16:07 ` Andy Spiegl
@ 2004-11-12 12:02 ` Stephane Chazelas
2004-11-15 12:21 ` Stephane Chazelas
2 siblings, 1 reply; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-12 12:02 UTC (permalink / raw)
To: Zsh users list
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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse and mouse-wheel support!
2004-11-12 12:02 ` [tip] mouse and mouse-wheel support! Stephane Chazelas
@ 2004-11-15 12:21 ` Stephane Chazelas
2004-11-15 13:14 ` Stephane Chazelas
0 siblings, 1 reply; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-15 12:21 UTC (permalink / raw)
To: Zsh users list
On Fri, Nov 12, 2004 at 12:02:48PM +0000, Stephane Chazelas wrote:
> Ok, thanks to the help of Peter, Bart and Andy, here is a new
> version.
[...]
Yet another one, please test it:
- fix problem when a ^M like char is spanned on two lines
- works within "select" and zed and zcalc
- fixed typo bug ($'\0200' should be $'\200')
- now works within vared as long as there is no prompt (-p vared
option) because I didn't know how to get vared prompt.
(again, either set ZLE_USE_MOUSE to 1 or add
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)
to your resource file to have <Super-btnClick> do the stuff).
### code begins
if [[ $TERM = *xterm* || $TERM = *rxvt* || $TERM = *screen* ]]; 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
case $CONTEXT in
(vared)
if [[ $0 = zcalc ]]; then
cur_prompt=${ZCALCPROMPT-'%1v> '}
setopt nopromptsubst nopromptbang promptpercent
# (ZCALCPROMPT is expanded with (%))
fi;;
# if vared is passed a prompt, we're lost
(select)
cur_prompt=$PS3;;
(cont)
cur_prompt=$PS2;;
(start)
cur_prompt=$PS1;;
esac
[[ -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 n x=0 y=1 cursor=$((${#cur_prompt}+$CURSOR+1))
local Y
set -x
buf=$cur_prompt$BUFFER
for ((i=1; i<=$#buf; i++)); do
(( i == cursor )) && Y=$y
n=0
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'$'\200'-$'\237'])
# characters like ^M
n=2;;
(*)
n=1;;
esac
while
(( x >= mx )) && : ${pos[y]=$i}
(( x >= COLUMNS )) && (( x=0, y++ ))
(( n > 0 ))
do
(( x++, n-- ))
done
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 ends
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [tip] mouse and mouse-wheel support!
2004-11-15 12:21 ` Stephane Chazelas
@ 2004-11-15 13:14 ` Stephane Chazelas
0 siblings, 0 replies; 13+ messages in thread
From: Stephane Chazelas @ 2004-11-15 13:14 UTC (permalink / raw)
To: Zsh users list
On Mon, Nov 15, 2004 at 12:21:34PM +0000, Stephane Chazelas wrote:
[...]
> 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)
[...]
I've experienced weird xterm behaviors with the above, this one
works better:
XTerm.VT100.translations: #override\
Mod4 <Btn1Down>: ignore()\n\
Mod4 <Btn2Down>: ignore()\n\
Mod4 <Btn3Down>: ignore()\n\
Mod4 <Btn1Up>: string(0x1b) string("[M ") dired-button()\n\
Mod4 <Btn2Up>: string(0x1b) string("[M!") dired-button()\n\
Mod4 <Btn3Up>: string(0x1b) string("[M") string(0x22) dired-button()\n\
Mod4 <Btn5Down>,<Btn5Up>: string(0xe)\n\
Mod4 <Btn4Down>,<Btn4Up>: string(0x10)
--
Stéphane
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2004-11-15 13:17 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-11-11 12:20 [tip] mouse support Stephane Chazelas
2004-11-11 14:40 ` Peter Stephenson
2004-11-11 16:22 ` Stephane Chazelas
2004-11-11 17:47 ` Bart Schaefer
2004-11-11 18:05 ` Stephane Chazelas
2004-11-11 18:22 ` Stephane Chazelas
2004-11-12 1:02 ` Bart Schaefer
2004-11-12 9:22 ` Stephane Chazelas
2004-11-11 16:07 ` Andy Spiegl
2004-11-11 17:26 ` Stephane Chazelas
2004-11-12 12:02 ` [tip] mouse and mouse-wheel support! Stephane Chazelas
2004-11-15 12:21 ` Stephane Chazelas
2004-11-15 13:14 ` Stephane Chazelas
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).