zsh-users
 help / color / mirror / code / Atom feed
* vim-a-like vi mode status bar
@ 2002-02-16 17:20 Ian Lynagh
  2002-02-16 17:48 ` Thomas Köhler
  2002-02-20 22:12 ` Steve Talley
  0 siblings, 2 replies; 5+ messages in thread
From: Ian Lynagh @ 2002-02-16 17:20 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1272 bytes --]


Hi all

I have thought it would be nice to have a vim-a-like indicator of
whether or not you are insert or command mode when using the vi line
editting mode for a long time now. In a burst of enthusiasm I have put
something together over the last couple of days (attached). However it's
not quite as nice as it might have been and I have run into a few
annoyances along the way.

Initially I was planning to have the indicator in the prompt. However
AFAICT once the prompt has been displayed it is cached, so even if you
for zsh to redraw it (I tried various things like "zle redisplay", "zle
push-input; zle get-line", "zle -R") it just redraws the old one. Did I
miss a way to do this?

Is there a reason why it shouldn't be possible to pipe something into
source? Or another way to do it without a temporary file?

With the script attached, if I paste a command in then only the first
character is visible until I press ^R. If I type something else first
then it works fine (even if I first delete what I typed!). Perhaps this
is a bug?

I also couldn't find a way to set the statusbar after accepting a
command. zsh -M complains it's not being called from a widget if I call
it from precmd.

Finally I would welcome any comments/criticisms on the code!


Thanks
Ian


[-- Attachment #2: zsh-vi-mode-status-bar --]
[-- Type: text/plain, Size: 2772 bytes --]


# Provides you with a vim-a-like vi-mode status bar showing what mode
# you are in.
# To be called from .zshrc

# Author: Ian Lynagh <igloo@earth.li>

# Licence: GPL 2
# Copyright: Ian Lynagh <igloo@earth.li> 2002

# Should we show "<insert>" or "" for insert mode?
alias statusbar-show-insert="zstyle :vi-mode-statusbar: show-insert yes"
alias statusbar-no-show-insert="zstyle :vi-mode-statusbar: show-insert no"
alias statusbar-test-show-insert="zstyle -t :vi-mode-statusbar: show-insert"
statusbar-no-show-insert

# What mode are we now in?
alias statusbar-now-insert="zstyle :vi-mode-statusbar: now-insert yes"
alias statusbar-now-command="zstyle :vi-mode-statusbar: now-insert no"
alias statusbar-test-now-insert="zstyle -t :vi-mode-statusbar: now-insert"

# What mode were we in last time?
alias statusbar-last-insert="zstyle :vi-mode-statusbar: last-insert yes"
alias statusbar-last-command="zstyle :vi-mode-statusbar: last-insert no"
alias statusbar-test-last-insert="zstyle -t :vi-mode-statusbar: last-insert"

# Helper function
function stat-statusbar-update {
    if statusbar-test-now-insert
    then
        if statusbar-test-show-insert
        then
            zle -M "<insert>"
        else
            if ! statusbar-test-last-insert
            then
                zle -M ""
            fi
        fi
        statusbar-last-insert
    else
        zle -M "<command>"
        statusbar-last-command
    fi
}

# Before each prompt reset
function precmd {
    statusbar-now-insert
    statusbar-last-command
}

# Wrap each widget

# This makes a new ~/.zshrc.stat.functions
function gen-stat-functions {
    local EXTRA CHANGE
    rm ~/.zshrc.stat.functions
    zle -l -a | grep "^[a-zA-Z]" | while read WIDGET
    do
        UPDATE="stat-statusbar-update"
        CHANGE=""
        case "$WIDGET" in
            vi-(add-(eol|next)|insert(|-bol)|change-(eol|whole-line) \
               |open-line-(above|below)|replace) \
           |accept-(and-(hold|infer-next-history)|line(|-and-down-history)) \
           |get-line|pound-insert|push-(input|line(|-or-edit)) \
           |send-break|run-help|which-command)
                CHANGE="statusbar-now-insert"
            ;;
            vi-cmd-mode)
                echo foo
                CHANGE="statusbar-now-command"
            ;;
            vi-change)
                CHANGE="statusbar-now-insert"
                UPDATE=""
            ;;
        esac
        echo "
function stat-$WIDGET {
    zle .$WIDGET
    $CHANGE
    $UPDATE
}
zle -N stat-$WIDGET stat-$WIDGET
zle -A stat-$WIDGET      $WIDGET" >> ~/.zshrc.stat.functions
    done
}

# Don't bother updating it automagically - that's just asking for it!
# Just . whatever was last created
. ~/.zshrc.stat.functions

# Use vi mode
bindkey -v


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: vim-a-like vi mode status bar
  2002-02-16 17:20 vim-a-like vi mode status bar Ian Lynagh
@ 2002-02-16 17:48 ` Thomas Köhler
  2002-02-16 20:05   ` Ian Lynagh
  2002-02-20 22:12 ` Steve Talley
  1 sibling, 1 reply; 5+ messages in thread
From: Thomas Köhler @ 2002-02-16 17:48 UTC (permalink / raw)
  To: zsh-users


[-- Attachment #1.1: Type: text/plain, Size: 988 bytes --]

Hi,

Ian Lynagh wrote [020216 18:28]:
> Hi all
> 
> I have thought it would be nice to have a vim-a-like indicator of
> whether or not you are insert or command mode when using the vi line
> editting mode for a long time now. In a burst of enthusiasm I have put
> something together over the last couple of days (attached). However it's
> not quite as nice as it might have been and I have run into a few
> annoyances along the way.

Well, I use something similar. Of course, I have a multiline
prompt, so what I have here might work for you, but it might need
some adjustment - the escape sequences for moving the cursor
might not work for your type of terminal...

Ciao,
Thomas

-- 
 Thomas Köhler Email:   jean-luc@picard.franken.de     | LCARS - Linux
     <><        WWW:     http://jeanluc-picard.de      | for Computers
                IRC:             jeanluc               | on All Real
               PGP public key available from Homepage! | Starships

[-- Attachment #1.2: zshrc.showmode --]
[-- Type: text/plain, Size: 4947 bytes --]

# vi keybindings
bindkey -v

bindkey -M vicmd "^R" redo
bindkey -M vicmd "u" undo
bindkey -M vicmd "ga" what-cursor-position

unsetopt promptcr


redisplay() {
   builtin zle .redisplay
   ( true ; show_mode "INSERT") &!
}
redisplay2() {
   builtin zle .redisplay
   (true ; show_mode "NORMAL") &!
}
zle -N redisplay
zle -N redisplay2
bindkey -M viins "^X^R" redisplay
bindkey -M vicmd "^X^R" redisplay2

screenclear () {
   echo -n "\033[2J\033[400H"
   builtin zle .redisplay
   (true ; show_mode "INSERT") &!
}
zle -N screenclear
bindkey "\f" screenclear

screenclearx () {
   repeat 2 print 
   local MYLINE="$LBUFFER$RBUFFER"
   highlight $MYLINE
   repeat 4 print 
   builtin zle redisplay
}
zle -N screenclearx
bindkey "^Xl" screenclearx

show_mode() {
   local COL
   local x
   COL=$[COLUMNS-3]
   COL=$[COL-$#1]
   x=$(echo $PREBUFFER | wc -l )
   x=$[x+1]
   echo -n "^[7^[[$x;A^[[0;G"
   echo -n ""
   echo -n "^[[0;37;44m--$1--^[[0m"
   echo -n "^[8"
}

zmodload zsh/parameter

###       vi-add-eol (unbound) (A) (unbound)
###              Move  to the end of the line and enter insert mode.

vi-add-eol() {
   show_mode "INSERT"
   builtin zle .vi-add-eol
}
zle -N vi-add-eol
bindkey -M vicmd "A" vi-add-eol

###       vi-add-next (unbound) (a) (unbound)
###              Enter insert mode after the  current  cursor  posi­
###              tion, without changing lines.
vi-add-next() {
   show_mode "INSERT"
   builtin zle .vi-add-next
   # OLDLBUFFER=$LBUFFER
   # OLDRBUFFER=$RBUFFER
   # NNUMERIC=$NUMERIC
   # bindkey -M viins "^[" vi-cmd-mode-a
}
zle -N vi-add-next
bindkey -M vicmd "a" vi-add-next


###       vi-change (unbound) (c) (unbound)
###              Read a movement command from the keyboard, and kill
###              from  the  cursor  position  to the endpoint of the
###              movement.  Then enter insert mode.  If the  command
###              is vi-change, change the current line.

vi-change() {
   show_mode "INSERT"
   builtin zle .vi-change
}
zle -N vi-change
bindkey -M vicmd "c" vi-change

###       vi-change-eol (unbound) (C) (unbound)
###              Kill  to the end of the line and enter insert mode.

vi-change-eol() {
   show_mode "INSERT"
   builtin zle .vi-change-eol
}
zle -N vi-change-eol
bindkey -M vicmd "C" vi-change-eol

###       vi-change-whole-line (unbound) (S) (unbound)
###              Kill the current line and enter insert mode.

vi-change-whole-line() {
   show_mode "INSERT"
   builtin zle .vi-change-whole-line
}
zle -N vi-change-whole-line
bindkey -M vicmd "S" vi-change-whole-line

###       vi-insert (unbound) (i) (unbound)
###              Enter insert mode.

vi-insert() {
   show_mode "INSERT"
   builtin zle .vi-insert
}
zle -N vi-insert
bindkey -M vicmd "i" vi-insert

###       vi-insert-bol (unbound) (I) (unbound)
###              Move to the first non-blank character on  the  line
###              and enter insert mode.

vi-insert-bol() {
   show_mode "INSERT"
   builtin zle .vi-insert-bol
}
zle -N vi-insert-bol
bindkey -M vicmd "I" vi-insert-bol

###       vi-open-line-above (unbound) (O) (unbound)
###              Open a line above the cursor and enter insert mode.

vi-open-line-above() {
   show_mode "INSERT"
   builtin zle .vi-open-line-above
}
zle -N vi-open-line-above
bindkey -M vicmd "O" vi-open-line-above

###       vi-open-line-below (unbound) (o) (unbound)
###              Open a line below the cursor and enter insert mode.

vi-open-line-below() {
   show_mode "INSERT"
   builtin zle .vi-open-line-below
}
zle -N vi-open-line-below
bindkey -M vicmd "o" vi-open-line-below

###       vi-substitute (unbound) (s) (unbound)
###              Substitute the next character(s).

vi-substitute() {
   show_mode "INSERT"
   builtin zle .vi-substitute
}
zle -N vi-substitute
bindkey -M vicmd "s" vi-substitute


###       vi-replace (unbound) (R) (unbound)
###              Enter overwrite mode.
###

vi-replace() {
   show_mode "REPLACE"
   builtin zle .vi-replace
}
zle -N vi-replace
bindkey -M vicmd "R" vi-replace

###       vi-cmd-mode (^X^V) (unbound) (^[)
###              Enter  command  mode;  that  is, select the `vicmd'
###              keymap.  Yes, this is bound  by  default  in  emacs
###              mode.

vi-cmd-mode() {
   show_mode "NORMAL"
   builtin zle .vi-cmd-mode
}
zle -N vi-cmd-mode
bindkey -M viins "^[" vi-cmd-mode



###       vi-oper-swap-case
###              Read a movement command from the keyboard, and swap
###              the case of all characters from the cursor position
###              to the endpoint of the movement.  If  the  movement
###              command  is vi-oper-swap-case, swap the case of all
###              characters on the current line.
###

bindkey -M vicmd "g~" vi-oper-swap-case


[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: vim-a-like vi mode status bar
  2002-02-16 17:48 ` Thomas Köhler
@ 2002-02-16 20:05   ` Ian Lynagh
  2002-02-17 18:57     ` Thomas Köhler
  0 siblings, 1 reply; 5+ messages in thread
From: Ian Lynagh @ 2002-02-16 20:05 UTC (permalink / raw)
  To: zsh-users


Hi,

On Sat, Feb 16, 2002 at 06:48:05PM +0100, Thomas Köhler wrote:
> 
> Ian Lynagh wrote [020216 18:28]:
> > I have thought it would be nice to have a vim-a-like indicator of
> > whether or not you are insert or command mode when using the vi line
> > editting mode for a long time now. In a burst of enthusiasm I have put
> > something together over the last couple of days (attached). However it's
> > not quite as nice as it might have been and I have run into a few
> > annoyances along the way.
> 
> Well, I use something similar. Of course, I have a multiline

Thanks, very interesting to see another implementation.

> prompt, so what I have here might work for you, but it might need
> some adjustment - the escape sequences for moving the cursor
> might not work for your type of terminal...

That's an approach I thought of but decided against, partly because of
the potential terminal issues and partly because of the cases like
multi-line input and screen clearing. However, you seem to have these
mostly[0] sussed so I might switch to this with a simple command to
switch to a simpler prompt if I do happen to be using a less fancy
terminal.

[0] It still looks like it has problems when the prompt has scrolled off
    the top of the screen, at least in an rxvt.

This should also solve a few of my current problems (flicker, characters
not being echoed when pasted and having the default state shown).

I do have a couple of further questions for you though...

> redisplay() {
>    builtin zle .redisplay
>    ( true ; show_mode "INSERT") &!
> }

I am not sure why you have the &! here - if it is worth doing then that
implies you might do something else before it has finished in which case
your cursor might not be where you think it is?

It also seems to me you might be better off with a variable (or zstyle
lookup or whatever) for the current state and a single redisplay. This
would have the advantage that you wouldn't have to worry about things
being rebound incorrectly later on.

> zle -N redisplay

Just overwriting the built-in widgets rather than aliasing seems so
*obvious* now how did I ever not think of it? Too caught up in the
excitement of being able to alias them I think!

> show_mode() {
>    local COL
>    local x
>    COL=$[COLUMNS-3]
>    COL=$[COL-$#1]
>    x=$(echo $PREBUFFER | wc -l )
>    x=$[x+1]
>    echo -n "^[7^[[$x;A^[[0;G"
>    echo -n ""
>    echo -n "^[[0;37;44m--$1--^[[0m"
>    echo -n "^[8"
> }

Am I missing something or is COL never actually used?

And doesn't
    echo -n ""
do nothing?


Thanks
Ian


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: vim-a-like vi mode status bar
  2002-02-16 20:05   ` Ian Lynagh
@ 2002-02-17 18:57     ` Thomas Köhler
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Köhler @ 2002-02-17 18:57 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 5214 bytes --]

Hi,

Ian Lynagh wrote [020217 19:03]:
> On Sat, Feb 16, 2002 at 06:48:05PM +0100, Thomas Köhler wrote:
[...]
> > prompt, so what I have here might work for you, but it might need
> > some adjustment - the escape sequences for moving the cursor
> > might not work for your type of terminal...
> 
> That's an approach I thought of but decided against, partly
> because of the potential terminal issues and partly because of
> the cases like multi-line input and screen clearing. However,
> you seem to have these mostly[0] sussed so I might switch to
> this with a simple command to switch to a simpler prompt if I
> do happen to be using a less fancy terminal.

That idea is not so bad, though I usually have very usuable
terminal definitions :-)

> [0] It still looks like it has problems when the prompt has
> scrolled off the top of the screen, at least in an rxvt.

In some cases, it doesn't work correctly, yes. This includes the
case when you type a very long line, a wrap happens and you
switch modes then - bad luck, --NORMAL-- appears in the wrong
place (one line below). But that doesn't happen enough to bother
me for now...

> This should also solve a few of my current problems (flicker,
> characters not being echoed when pasted and having the default
> state shown).

Yes, there's quite a few issues to resolve when you want to write
something to some special position in the terminal...

> I do have a couple of further questions for you though...

No problem :-)

> > redisplay() {
> >    builtin zle .redisplay
> >    ( true ; show_mode "INSERT") &!
> > }
> 
> I am not sure why you have the &! here - if it is worth doing
> then that implies you might do something else before it has
> finished in which case your cursor might not be where you think
> it is?

I've inserted those &! in all places because for some situations,
the cursor was not back to its original position yet before the
function has been called, so by this little trick, the function
returns, the cursor is back, and _then_ the "INSERT" is being
drawed. Funny issue indeed. I don't remember offhand which of
those &! I really needed, and I just dodn't mind because it works
OK for now...

> It also seems to me you might be better off with a variable (or
> zstyle lookup or whatever) for the current state and a single
> redisplay. This would have the advantage that you wouldn't have
> to worry about things being rebound incorrectly later on.

Maybe, didn't evaluate that much further. Perhaps worth thinking
about it...

> > zle -N redisplay
> 
> Just overwriting the built-in widgets rather than aliasing seems so
> *obvious* now how did I ever not think of it? Too caught up in the
> excitement of being able to alias them I think!

That idea came to my mind after reading zsh-users some day, and
once you find the trick, all seems so obvious and you think "why
have I been so silly?". It's always the same :-)

> > show_mode() {
> >    local COL
> >    local x
> >    COL=$[COLUMNS-3]
> >    COL=$[COL-$#1]
> >    x=$(echo $PREBUFFER | wc -l )
> >    x=$[x+1]
> >    echo -n "^[7^[[$x;A^[[0;G"
> >    echo -n ""
> >    echo -n "^[[0;37;44m--$1--^[[0m"
> >    echo -n "^[8"
> > }
> 
> Am I missing something or is COL never actually used?

Well... no, you're not missing anything, I just forgot to remove
it, it was in there in my first version (and has been used then
because I used to have the mode on the right hand side instead of
the left hand side).

> And doesn't
>     echo -n ""
> do nothing?

Actually, it prints an empty string :-)

One thing I'm thinking of at the moment: Some more issues (where
to put the "showmode") could be resolved better by always using
the same position on the screen - for example, always on the last
line, at the left hand side. That way, some fidling around with
$LINES might be needed (as I used to use $COLUMNS in my original
version, but then I decided to put the showmode feature to the
left hand side, and, well, put a clock[1] on the right hand
side), and one would have to create a long prompt (part of which
would be overwritten when you're down at the bottom), but it
might be a better idea? Perhaps worth a try...

[1] Don't try this at home: Sometimes there's a race condition
when zsh tries to complete things and that little cron comes in
the way, and so sometimes (not very often, but still sometimes)
zsh crashes. It used to be worse back in 3.1.9-dev-xx-days,
though :)

Here it is anyways, for those who still want it...

### a clock in the prompt. Yes, this _is_ cool.
trap CRON ALRM
TMOUT=1
CRON() {
   local STRING
   local COL
   local x
   STRING=$(date)
   COL=$[COLUMNS-5]
   COL=$[COL-$#STRING]
   x=$(echo $PREBUFFER | wc -l )
   x=$[x+1]
   echo -n "^[7^[[$x;A^[[$COL;G^[[0;37;44m-- $STRING --^[[0m^[8"
}


> Thanks
> Ian

Ciao,
Thomas

-- 
 Thomas Köhler Email:   jean-luc@picard.franken.de     | LCARS - Linux
     <><        WWW:     http://jeanluc-picard.de      | for Computers
                IRC:             jeanluc               | on All Real
               PGP public key available from Homepage! | Starships

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: vim-a-like vi mode status bar
  2002-02-16 17:20 vim-a-like vi mode status bar Ian Lynagh
  2002-02-16 17:48 ` Thomas Köhler
@ 2002-02-20 22:12 ` Steve Talley
  1 sibling, 0 replies; 5+ messages in thread
From: Steve Talley @ 2002-02-20 22:12 UTC (permalink / raw)
  To: Ian Lynagh; +Cc: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1485 bytes --]

I have a mode line that appears below the command line (attached).  It
has a bug here and there, but is fairly solid and pretty simple.

Steve

Ian Lynagh wrote:

> Hi all
>
> I have thought it would be nice to have a vim-a-like indicator of
> whether or not you are insert or command mode when using the vi line
> editting mode for a long time now. In a burst of enthusiasm I have
> put something together over the last couple of days (attached).
> However it's not quite as nice as it might have been and I have run
> into a few annoyances along the way.
>
> Initially I was planning to have the indicator in the prompt.
> However AFAICT once the prompt has been displayed it is cached, so
> even if you for zsh to redraw it (I tried various things like "zle
> redisplay", "zle push-input; zle get-line", "zle -R") it just
> redraws the old one. Did I miss a way to do this?
>
> Is there a reason why it shouldn't be possible to pipe something
> into source? Or another way to do it without a temporary file?
>
> With the script attached, if I paste a command in then only the
> first character is visible until I press ^R. If I type something
> else first then it works fine (even if I first delete what I
> typed!). Perhaps this is a bug?
>
> I also couldn't find a way to set the statusbar after accepting a
> command. zsh -M complains it's not being called from a widget if I
> call it from precmd.
>
> Finally I would welcome any comments/criticisms on the code!
>
> Thanks Ian

[-- Attachment #2: zshmode --]
[-- Type: text/plain, Size: 2387 bytes --]

#
# Set vi mode status bar
#

#
# Reads until the given character has been entered.
#
readuntil () {
    typeset a
    while [ "$a" != "$1" ]
    do
        read -E -k 1 a
    done
}

#
# If the $SHOWMODE variable is set, displays the vi mode, specified by
# the $VIMODE variable, under the current command line.
# 
# Arguments:
#
#   1 (optional): Beyond normal calculations, the number of additional
#   lines to move down before printing the mode.  Defaults to zero.
#
showmode() {
    typeset movedown
    typeset row

    # Get number of lines down to print mode
    movedown=$(($(echo "$RBUFFER" | wc -l) + ${1:-0}))
    
    # Get current row position
    echo -n "\e[6n"
    row="${${$(readuntil R)#*\[}%;*}"
    
    # Are we at the bottom of the terminal?
    if [ $((row+movedown)) -gt "$LINES" ]
    then
        # Scroll terminal up one line
        echo -n "\e[1S"
        
        # Move cursor up one line
        echo -n "\e[1A"
    fi
    
    # Save cursor position
    echo -n "\e[s"
    
    # Move cursor to start of line $movedown lines down
    echo -n "\e[$movedown;E"
    
    # Change font attributes
    echo -n "\e[1m"
    
    # Has a mode been set?
    if [ -n "$VIMODE" ]
    then
        # Print mode line
        echo -n "-- $VIMODE -- "
    else
        # Clear mode line
        echo -n "\e[0K"
    fi

    # Restore font
    echo -n "\e[0m"
    
    # Restore cursor position
    echo -n "\e[u"
}

clearmode() {
    VIMODE= showmode
}

#
# Temporary function to extend built-in widgets to display mode.
#
#   1: The name of the widget.
#
#   2: The mode string.
#
#   3 (optional): Beyond normal calculations, the number of additional
#   lines to move down before printing the mode.  Defaults to zero.
#
makemodal () {
    # Create new function
    eval "$1() { zle .'$1'; ${2:+VIMODE='$2'}; showmode $3 }"

    # Create new widget
    zle -N "$1"
}

# Extend widgets
makemodal vi-add-eol           INSERT
makemodal vi-add-next          INSERT
makemodal vi-change            INSERT
makemodal vi-change-eol        INSERT
makemodal vi-change-whole-line INSERT
makemodal vi-insert            INSERT
makemodal vi-insert-bol        INSERT
makemodal vi-open-line-above   INSERT
makemodal vi-substitute        INSERT
makemodal vi-open-line-below   INSERT 1
makemodal vi-replace           REPLACE
makemodal vi-cmd-mode          NORMAL

unfunction makemodal

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2002-02-20 22:13 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-02-16 17:20 vim-a-like vi mode status bar Ian Lynagh
2002-02-16 17:48 ` Thomas Köhler
2002-02-16 20:05   ` Ian Lynagh
2002-02-17 18:57     ` Thomas Köhler
2002-02-20 22:12 ` Steve Talley

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).