A Vile Page

Tutorials Macros Modes

This will be where I bury some Vile tidbits that I piece together or steal from others. I won't claim to be the greatest macro writer: in fact, I've only been playing with Vile macros for a couple weeks and am only beginning to use the features.

Vile is not vi, but it feels like it. Most of the vi commands work just as expected. It's also smaller and faster than vim. My only wish-list item at the moment is for better context highlighting. (Well, that, and more examples on what you can do with it, but that's why this page is here... If you have some cool vile macros or tricks, feel free to pass them on. If you set up your own web page of vile tricks, I'll be glad to add a pointer to it.)

Other Vile Pages

Of course, there's the obligatory screen shot of xvile. The center window is output from a make command (done with ^X!make) and the top window is where the error was found (^X^X will step through errors). There is a reason I use vile as a sort of integrated development environment.

Some have asked what widget set it is that I use: it's Xaw-XPM, which is a hack of Xaw3d (as Xaw3d is a hack of Xaw) that looks a bit prettier. You can do nifty things like have backing pixmaps to all your Athena items. You can download it at http://www.zip.com.au/~bb/XawXpm/.

For the lazy, a copy of my .vilerc.

Vile Tutorials

If you need a quick tutorial on vi commands, try vi.tutorial.tar.gz. It's a couple of files that you edit in vi (or vile) and will teach you the basics of getting around in vi. I believe this is from the nvi distribution.

A similar tutorial is vilearn. This is a series of 5 lessons on how to get around in vi and comes with a nice installer and invoker that make it work well on multiuser systems. (It will copy the lesson from a shared directory, move it to the current directory and even keep track of what you've seen.)

You can also check out the 'Vi Lovers Home Page' for more docs on vi.

Vile Macros

One of the advantage of Vile over other vi clones is that it has a rich macro language inherited from its Micro-emacs roots.

The first offering is the below macro, invoked as a read-hook that auto-strips quoted signatures when replying. It works with both Mutt and slrn. By changing the suffix, it should work with other clients as well, but why bother?


;
;  A delete-sig macro for mail/news posts (this works great with both
;  slrn and mutt: others may need to change the suffixes).
store-procedure del-sig
    ~if &not &seq $majormode "mail"
        ~goto finish
    ~endif
    set fcolor white
    goto-beginning-of-file
    ~force search-forward "^> -- $"

    ; if .sig exists ...
    ~if &not &equ $curline 1
        ; this one took me a while to fix... we delete until our sig
        ; seperator, or a null line (being end of file).  Without the
        ; second trap, if you have no .sig file it would loop forever
        ; trying to delete that last line.
        ~while &and &not &seq $line "-- " &not &seq $line ""
            ~force delete-til lines
        ~endwhile
        ; shove a newline back in right before our own .sig (it
        ; looks better this way).
        newline
        goto-beginning-of-file
    ~endif
     
    ; move the cursor after the headers, on the first line of the body.
    ; (I have $edit_hdrs set :)  remove these two lines if you don't.
    ; I also 'force' them, since it would otherwise fail if I have
    ; no .sig and write a new letter.
    ~force next-paragraph
    ~force next-line
    ; 'because I can', let's colorize the headers.  I make 'em cyan
    ; to match my header colors in mutt.
    perl "require 'mail.pl'"
    perl format_mail
*finish
~endm
     
define-mode mail
    define-submode mail suffixes \\(^\\(/tmp/mutt-[a-z]\\+-[0-9]\\+-[0-9]\\+\\)\\|\\(.followup\\|.letter\\|.article\\)\\)$
    define-submode mail wm 8

set read-hook "del-sig"


These two are for working on HTML with Vile. Sometimes you want to run a preview of your page. There are two ways to do this: the first is to spawn off a web browser in a seperate window or we can snarf lynx's output into a buffer. I do both. :)

I guess I -could- spawn off 'remotescape' for the xvile command, but, well, I like Lynx.


; spawn off lynx on the current file (forcing html mode)
22 store-macro
    write-message &cat "Viewing " $cfilname
    ~if &seq $progname "vile"
        1 shell-command &cat "lynx -force_html " $cfilname
    ~else
        shell-command &cat &cat "xterm -e lynx -force_html " $cfilname "&"
    ~endif
~endm

; render HTML into [Output] buffer with lynx.
23 store-macro
    set-variable %command &cat "lynx -dump -force_html " $cfilname
    capture-command %command
~endm

I haven't made up a decent binding for the above two yet. Suggestions are welcome. (Right now, I pull them down through a menu in xvile, or :execute-macro 23 in vile.)

And one more cute macro for HTML: I (and many others :)) will often type a word that is the name of a file in the same directory and then have to do a <a href="blah"> and a </a> around the word 'blah'. Or I'll type the full URL of something so people can go see where the link goes even if they are relying on a printed version of the page.

Needless to say, it quickly becomes a pain in the rear end to keep typing the same thing twice, once for the HTML and once for the rendering. So there's this macro (invoked by F6, for lack of a better place to put it) that makes a link for you. I spent a while fighting with this because I kept doing it 'the vi way', which is to yank stuff into buffers, set marks, etc. It really doesn't work well like that: it's much easier to let vile do the work and watch the 'pathname' under the cursor -- yet another reason a real macro language is nice.


; makes Anchor (<A HREF=....) of the current word.
;
6 store-macro 
        back-word
	~if &or &seq $qidentifier "http:" &seq $qidentifier "ftp:"
	    set-variable %path $word
        ~else
	    ~if &sin $word "@"
	        set-variable %path &cat "mailto:" $word
            ~else
    	        set-variable %path $pathname
	    ~endif
    	~endif
	insert-string &cat "<a href=\"" &cat %path "\">"
        ~force forward-char-scan " "
        ~if &not &equ $char 32
	   end-of-line
           append-string "</a>"
        ~else
           insert-string "</a>"
        ~endif
~endm


This macro stolen from Clark O. Morgan, cmorgan@aracnet.com who posted it to Usenet in <5cb7l6$41q@shelob.aracnet.com>. It probably should strip out quoted material before passing it to ispell as well, but works pretty well and is now in my .vilerc. (And it makes my head hurt on how to do that and then reintegrate the changes...)

Actually, scratch that... there's a modified version in my .vilerc that detects whether you're running xvile (in which case it spawns an xterm for ispell) and if you're in 'html mode', which passes the -h flag to ispell (see below for a patch to ispell to make it handle html files properly). Oh, and it doesn't skip header-stuff unless you're in 'mail mode' (which handles my mail and news posts). Check out my .vilercfor more details.


;
; Vile macro to ispell an e-mail msg or USENET posting that contains
; msg headers (headers are separated from body by at least one blank line).
; This macro feeds the Subject: header and msg body to ispell, then glues
; the returned result back into the original message.  NB: this macro does
; not handle a Subject: hdr that's continued over more than one line and
; it assumes that the blank line separating hdrs & body is exactly "^$"
.
24 store-macro
    beginning-of-file
    search-forward "^"  ; $match has known value
    load-register p ""
    ~force search-forward "^Subject:"
    ~if &seq "Subject:" $match
        use-register p delete-til lines      ; delete til eol
    ~endif
    beginning-of-file
    ~force search-forward "^$"
    ~if &seq "" $match
        use-register P delete-til goto-line  ; delete til EOF
    ~else            ; Assume no msg body, add blank line as msg
        end-of-file
        1 force-blank-lines
        use-register P delete-til goto-line  ; delete til EOF
    ~endif
    write-file
    set-variable %origfile $cfilname
    set-variable %tmpleaf &cat ".vile.ispell." $pid
    set-variable %tmpfile &cat "$HOME/" %tmpleaf
    edit-file %tmpfile
    use-register p put-after ; put subj hdr & msg body in tmp file
    write-file
    1 shell-command &cat "chmod go-rwx " %tmpfile  ; protect file contents
    1 shell-command &cat "ispell " $cfilname
    edit-file %origfile
    end-of-file
    insert-file %tmpfile
    delete-buffer %tmpleaf
    1 shell-command &cat &cat "rm " %tmpfile "*"   ; cleanup tmpfile
~endm
bind-key execute-macro-24 #-i   ; invoke with the keystroke #i

The following are to macros to PGP-sign a document, also from Clark Morgan. Choose the appropriate ones for your shell and change the 'Clark' name to your username for PGP. Unless you switch shells a lot, only two of the four should be applicable. Looks like vile needs a password input prompt (would be useful for crypt passwords as well) to be fully proper.


; Included below are 4 vile macros to sign buffers with PGP 2.6.2 plain
; text signatures.  One use for these macros is to sign e-mail messages
; or USENET postings.  When selecting one or more of the macros below,
; choose based on these criteria:
;   - type of shell specified in $SHELL
;   - whether or not the buffer contains message headers (at top of
;     buffer) that are separated from message body by a blank line.
;     Some mail user agents expose headers to the end user (e.g., mush)
;     and others do not (elm).  If you post USENET messages via Pnews,
;     message headers are included in the buffer.
;
; All macros use the same principle:
;   - prompts for PGP pass phrase for user Clark (change this user id
;     as appropriate for your application)
;   - places pass phrase at appropriate point in buffer
;   - filters buffer to pgp and forces pgp to read passphrase from buffer.


; Buffer signed from the first blank line of the buffer to end-of-file.
; Macro applicable to Bourne shell and derivatives (ksh, bash, etc).
; Macro elides all pgp stderr output and so if something goes wrong
; (e.g., passphrase typo), you get to figure out what happened.  Look at
; csh-based macros below for a (slower) method that leaves error messages
; in the buffer if pgp fails.
19 store-macro
    set-variable %phrase &cat @"PGP PassPhrase? " "\n"
    write-message " "  ; erase passphrase
    set-variable %var "PGPPASSFD=0; export PGPPASSFD;"
    set-variable %cmd &cat %var "pgp -fsta -u Clark 2>/dev/null"
    beginning-of-file
    search-forward "^[ \t]*$"
    ~force down-line
    insert-string %phrase
    ~force up-line-at-bol
    filter-til end-of-file %cmd
~endm
bind-key execute-macro-19 #-s   ; invoke with the keystroke #s

;
; Same macro as above, except that the entire buffer is signed.
;
20 store-macro
    set-variable %phrase &cat @"PGP PassPhrase? " "\n"
    write-message " "  ; erase passphrase
    set-variable %var "PGPPASSFD=0; export PGPPASSFD;"
    set-variable %cmd &cat %var "pgp -fsta -u Clark 2>/dev/null"
    beginning-of-file
    insert-string %phrase
    ~force up-line-at-bol
    filter-til end-of-file %cmd
~endm
bind-key execute-macro-20 #-S   ; invoke with the keystroke #S

; Buffer signed from the first blank line of the buffer to end-of-file.
; Macro applicable to csh and its derivatives (tcsh, etc).  Due to
; inherent limitations in csh commandline syntax, this macro reads all
; pgp output (stdout & stderr) and then filters it.  Consequently, if
; something goes wrong (e.g., passphrase typo), the pgp error msg is
; retained in the buffer.
21 store-macro
    set-variable %phrase &cat @"PGP PassPhrase? " "\n"
    write-message " "  ; erase passphrase
    set-variable %var "setenv PGPPASSFD 0;"
    set-variable %cmd &cat %var "pgp -fsta -u Clark"
    beginning-of-file
    search-forward "^[ \t]*$"
    set-named-mark q
    ~force down-line
    insert-string %phrase
    ~force up-line-at-bol
    filter-til end-of-file %cmd
    goto-named-mark q
    down-line
    ~force delete-til search-forward "--*BEGIN PGP SIGNED MESSAGE"
~endm
bind-key execute-macro-21 #-t   ; invoke with the keystroke #t

;
; Same macro as above, except that the entire buffer is signed.
;
22 store-macro
    set-variable %phrase &cat @"PGP PassPhrase? " "\n"
    write-message " "  ; erase passphrase
    set-variable %var "setenv PGPPASSFD 0;"
    set-variable %cmd &cat %var "pgp -fsta -u Clark"
    beginning-of-file
    insert-string %phrase
    ~force up-line-at-bol
    filter-til end-of-file %cmd
    beginning-of-file
    ~force delete-til search-forward "--*BEGIN PGP SIGNED MESSAGE"
~endm
bind-key execute-macro-22 #-T   ; invoke with the keystroke #T

Vile Modes

Vile also supports 'modes' on its buffers. These allow each buffer to take on an individual set of configurations. Note above the 'mail' mode, for example, that has a slightly different config when doing mail or news posts from a 'c-mode' buffer.

At the moment, I'm piecing together an HTML mode that I It does a couple minor things like set the paragraphs to something that works pretty well with HTML (tags like 'p', 'br' and 'li' designate paragraphs because they generate breaks). It's not entirely to my liking (d} doesn't do what I want, for example, but ^Af} does....), though perhaps I should get used to counting the tags themselves and do a 3d} when I want to yank them (since I ^Af} much much more often). I haven't really decided on other settings to aid in HTML writing.

I did manage to convince Vile to accept "%F(%L):%T", as an additional item in [Error Expressions] so that it will work nicely with weblint. This turned out to be somewhat tricky and I had to resort to perl to be satisfied with it.

When I tried this from .vilerc it would either end up still displaying [Error Expressions] (which is not what I wanted), or .vilerc (since it was reading that) or perhaps the file I specified on the command line. I couldn't convince it to do the right thing when there was a filename specified on the command line and when there wasn't: I could get one or the other working but not both.

By using the perl hooks, though, I can modify the [Error Expressions] buffer, without caring what buffer I'm in now or where I'm going. The perl init in its entirety:


#!/usr/bin/perl
# (again, not really: this will only work when required or included from
# vile.)  I use this in perl instead of Vile because I don't force us
# getting dumped into [Error Expressions] if no filename is specified on
# the command line.
#
# and some year, I may actually get around to shoving more stuff in here
# as initialization code.

my $buffer = edit Vile::Buffer '[Error Expressions]';

Vile::set(noview => 1);

print $buffer "%F(%L):%T\n";

$buffer->dot(1,0);

1;

In order to load the above you need to be slightly tricky in your .vilerc. The [Error Expressions] don't exist unless you use them. But you can compile them into existence. I compile them to create them, require the above program and then recompile them so that my new pattern will be found.


compile-error-expressions
perl "require 'vileinit.pl'"
compile-error-expressions

This defines the output format of weblint (see http://www.cre.canon.co.uk/~neilb/weblint for more info on weblint) in a way that ^X^X understands, so I can weblint my pages without leaving vile. On my 'todo' list is a macro that pipes output to weblint so that I don't even have to save them.


define-majormode html
    define-submode html suffixes "\\.\\(s\\|p\\)\\?html\\?$"
    define-submode html shiftwidth 4
    define-submode html wrapmargin 8
    define-submode html tabs=8
    define-submode html autoindent
    define-submode html fence-pairs "<>"
; paragraphs are <p>, <br>, <li>... anything else?  In short, these are
; things that force a hard return so that ^Af} will be happy to reformat
; them for us without breaking the HTML or making it look ugly.
define-submode html paragraphs "</\\?\\([pP]\\|[bB][Rr]\\|[lL][iI]\\)[^>]*>"
; sections.... should these be table-things?

One last freebie that has nothing (well, almost nothing) to do with vile: a patch to ispell to let it handle HTML better. (It ignores tags, but knows to spell-check alt tags.) If you've ever tried to spell check a web page and been frustrated with being told 'IMG' or 'PRE' is spelled wrong, this should be useful. It's here because the link on the ispell home page points to a dead site and I spent hours looking for an alternative... can't hurt to let this propogate further.


Made with Vile Enhanced for Lynx