Eli's Implementation of Vi Modelines in Vim

Vim is a good clone of vi, but it does not support the enormously powerful (and hideously insecure) modelines of the original. It does support it's own crippled version of modelines useful only for changing settings. The crippling is intended to go a long way towards closing the security hole of modelines.

One vim feature however is that it supports autocommands to be run on certain events, such as reading in a file buffer. This can be massaged into running any vim command script. I seized upon this feature and used it to implement modelines.

Basically it consists of two parts. First an entry into a .vimrc file setting an autocommand to run the script on all buffer reads. Second the script itself.

Security concerns:

Vi compatible modelines are capible of executing any vi command including shell escapes. Improper activation of modelines will kill you. Do not try this at home, these stunts are performed by trained professionals.

Bugs fixed in this version:

  1. No longer beeps when there are no modelines.
  2. Does not leave you on the last line of the file.
  3. Shell escapes work properly.
  4. No longer attempts to execute vim modelines. (See known features.)
  5. Execution order known to be the same as vi (vim modelines and command line commands are executed first).

Known bugs:

  1. Modelines which alter the file may not work properly on files of less than 10 lines. A few complex map commands may also fail on short files. (Start worrying if your map commands call other map commands.)
  2. Command line searches get clobbered.
  3. Registers x, y, and z are clobbered. (This happens every time you :e or :n to a file.)
  4. Vim does not support :append, :insert, or :change which may break some (very) obscure modelines.

Known features:

  1. I decided not to support vim style modelines because they do not need a trailing ":", which I find awkward, and because they are not valid ex commands. E.g: " vim:ts=8:" is a valid vim modeline, but ":ts=8" is not a valid command in vim. If you want to execute these, have vim process the modelines itself.
  2. Whitespace rules for finding modelines follow the vi style and not the vim style.

Testing:

While I have subjected these to some grueling tests, more bugs may be hiding. Three of the tests I applied:

  1. Should fork a vim to edit the file. Written to get vi to call vim. env places the VIMINIT (which turns on showmode, closest to a no-op I could think of) setting in the environment to prevent the child vim from finding any vimrc's with the autocmd for modelines.

    vi: set noml | w! | ! env VIMINIT="set sm" vim % :
    vi: e! % | w! | q :

    Note: this was written in response to a question on Usenet asking how to do this. Some of the useless bits in there are left over from the question. "| w!" from the first line and "e! % | w! |" from the second may be removed with no change in function.

  2. Infinitely looping "Hello World" program. Note the extra lines to work around the less than ten line bug.

    An infinitely looping "Hello World" for true vi or vim with my
    autocommand modeline script.
    3
    4
    5
    6
    7
    vi:$d a|$y b|@b:
    pu a|@b
    Hello World

  3. My .signature virus.

    vi: /virus!$/w >>~/.signature : Eli's vi modeline .signature virus!


Now for the implentation!

If for some reason you still want to use these, here is how to do it.

For your .vimrc file:

Put these two lines in your ~/.vimrc file to activate this system for all files:

" Modeline auotcommand
autocmd bufread * :so! ~/.modeline.vimrc

Alternatively, you can "set exrc" in your ~/.vimrc and put those two lines only in .vimrc's in subdirectories where you want modelines to be executed.

The ~/.modeline.vimrc file:

First a human readible version (control characters escaped):

:$-4,$y z | 1,5y x
^Wn"xpG"zp:1y y |v/\(ex\|vi\):.*[^ ]\+.*:/d
:%s/.*\(ex\|vi\):\(.*\):.*/\2/
:$s/$/^V^M1/
:g/./y Y
:q!
G:@y

By changing the ^W and ^V^M in the above to a literal <ctrl-W> and <ctrl-V><ctrl-M>, you will have a working version of the script. In vi or vim you must type a <ctrl-V> before entering each of the control characters.

Second a uuencoded version of the script file:

begin 644 .modeline.vimrc
M.B0M-"PD>2!Z('P@,2PU>2!X"A=N(GAP1R)Z<#HQ>2!Y('QV+UPH97A<?'9I
M7"DZ+BI;7B!=7"LN*CHO9 HZ)7,O+BI<*&5X7'QV:5PI.EPH+BI<*3HN*B]<
@,B\*.B1S+R0O%@TQ+PHZ9R\N+WD@60HZ<2$*1SI >0HI
 
end

Go back to my vim page
Last modified (15:28:11 26/11/96) by Benjamin Elijah Griffin.