Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [tip] mouse and mouse-wheel support!



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



Messages sorted by: Reverse Date, Date, Thread, Author