INTERNAL TEXT REPRESENTATION
	When vi starts up, the file is copied into a temporary file.  Small
	amounts of extra space are inserted into the temporary file to insure
	that no text lines cross block boundaries; this speeds up processing.
	The "extra space" is filled with NUL charcters; the input file must
	not contain any NULs, to avoid confusion.

	The first block of the temporary file is an array of shorts which
	describe the order of the blocks; i.e. header[1] is the block number
	of the first block, and so on.  This limits the temporary file to
	512 active blocks, so the largest file you can edit is about 400K
	bytes long.  I hope that's enough!

	When blocks are altered, they are rewritten to a *different* block
	in the file, and the in-core version of the header block is updated
	accordingly.  The in-core header block will be copied to the temp
	file immediately before the next change... or, to undo this change,
	swap the old header (from the temp file) with the new (in-core)
	header.

	Vi maintains another in-core array which contains the line-number of
	the last line in every block.  This allows you to go directly to a
	line, given its line number.

IMPLEMENTATION OF EDITING
	There are three basic operations which affect text:

		* delete text	- delete(from, to)
		* add text	- add(at, text)
		* yank text	- cut(from, to)

	To yank text, all text between two text positions is copied into
	a cut buffer.  The original text is not changed.  To copy the text
	into a cut buffer, you need only remember which physical blocks that
	contain the cut text, the offset into the first block of the start of
	the cut, the offset into the last block of the end of the cut, and
	what kind of cut it was.  (Cuts may be either character cuts or line
	cuts; the kind of a cut affects the way it is later "put".)

	To delete text, you must modify the first and last blocks, and remove
	any reference to the intervening blocks in the header's list.  The
	text to be deleted is specified by two marks.

	To add text, you must specify the text to insert (as a NUL-terminated
	string) and the place to insert it (as a mark).  The block into which
	the text is to be inserted may need to be split into as many as four
	blocks, with new intervening blocks needed as well... or it could be
	as simple as modifying the block.

	When text is deleted or added, an internal file-revision counter,
	called "changes", is incremented.  This counter is used to detect
	when certain caches are out of date.  (The "changes" counter is
	also incremented when we switch to a different file, and also in
	one or two similar situations -- all related to invalidating caches.)

MARKS AND THE CURSOR
	Marks are places within the text.  They are represented internally
	as a long variable which is split into two bitfields: a line number
	and a character index. Line numbers start with 1, and character
	indexes start with 0.

	Since line numbers start with 1, it is impossible for a set mark to
	have a value of 0L.  0L is therefore used to represent unset marks.

	When you do the "delete text" change, any marks that were part of
	the deleted text are unset, and any marks that were set to points
	after it are adjusted.  Similarly, marks are adjusted after new text
	is inserted.

	The cursor is represented as a mark.

EX COMMAND INTERPRETATION
	EX commands are parsed, and the command name is looked up in an array
	of structures which also contain a pointer to the function that
	implements the command, and a description of the arguments that the
	command can take.  If the command is recognized and its arguments
	are legal, then the function is called.

	Each function performs its task; this may cause the cursor to be moved
	to a different line, or whatever.

SCREEN CONTROL
	The screen is updated via a package which looks like the "curses"
	library, but which is actually implemented in a simpler, faster way.
	Most curses operations are implemented as macros which copy characters
	into a large I/O buffer, which is then written with a single large
	write() call as part of the refresh() operation.

	The functions which modify text remember where text has been modified;
	the screen redrawing function needs this information to help it reduce
	the amount of text that is redrawn each time.
