* [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 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: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
* 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 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
* [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).