[implementations-list] On the software design of a vi/vim core

Jon j at ngedit.com
Wed Jun 24 18:32:57 CEST 2009

I am Jon Beltran de Heredia, the developer and vendor of the ViEmu 
products (vi/vim emulators for Visual Studio, Word, Outlook and SQL 
Server). See http://www.viemu.com for details.

I am not familiar with the code of viper or vimpulse, but the design of 
my own vi/vim emulation core achieves great orthogonality for commands / 
motions and combinations thereof, requiring only the essentially 
necessary code.

Basically, I have a keypress parser that builds a "full command desc", 
and then it passes this to a command executing subsystem. Commands and 
motions are very orthogonal. Here are the structs that defines a command 
(this is very abstract template-based C++, the same core is used in all 
the ViEmus):

template<class CHAR>
struct ViFullCommand
  unsigned      cmd_count;
  unsigned      motion_count;

  ViCommand     cmd;
  CHAR          chCmdArg;

  ViMotion      mot;
  CHAR          chMotArg;

  char          chRegister;

  // If CHR, and the org motions is CHR, toggle EXCL-INCL. If org is 
linewise, ->CHR-EXCL. Rest simple override.
  bool          bForceMotionType;
  TextRangeType eForceMotionType;

  unsigned      uVirtLines;
  int           iVirtCols;

  basic_heap_string<CHAR> strArg;

ViCommand and ViMotion are simple enums.

A simple motion (w) involves the VI_CMD_NULL command and the 
VI_MO_Word_RIGHT motion. A more complex combination (2"ad3f*) involves 
the VI_OP_DEL command, the VI_MO_FORWARD motion, "*" as the motion arg, 
a chRegister of 'a', a count of 2 for the command and a count of 3 for 
the motion. Most commands multiply both counts together, but this 
structure is designed to faithfully represent the result of parsing a vi 
command, and allow orthogonal implementation.

The motion is calculated by the motion subsystem. This is purely 
functional: it returns the endpoint. Actually, it returns some extra 
info -- "iw" is understood as a motion that returns a new "start point", 
and motions can also return a motion type, and some extra info. "Visual" 
is a special motion that has pre-stored points. The parser handles this 
case -- actual command implementations don't know and don't care where 
the motion range came from.

Then, the command subsytem calls the given command function with the 
result of the motion. If the command is null, the cursor is moved to the 
endpoint. Moving in visual mode is different, etc...

With this kind of architecture, the amount of code you need to write is 
minimize. From the types of bugs I often see reported for other vi/vim 
implementations, I understand people are not writing orthogonal code. A 
design as the above allows the cleanest implementation.

  -- Jon

Marius Andersen wrote:
>> Fra: Alessandro Piras <laynor at gmail.com>
>> Emne: Re: [implementations-list] Vimpulse update
>> Til: "Vi/Vim implementations list" <implementations-list at lists.ourproject.org>
>> Dato: Mandag 22. juni 2009 13.34
>> it's easy stuff actually :) It works like this:
>> I modified the viper-prefix-arg-com function to introduce 4
>> new commands: da di ca ci. These commands will read-char to get motion
>> command.
> Yes, this is a very good way to do it. It means more objects can be easily added without any more mucking around in `viper-prefix-arg-com'.
> Anyway, I mailed Michael Kifer and asked if there was a way to avoid redefining `viper-prefix-arg-com', and he replied he couldn't think of one. So until the original function is redesigned, which will probably not happen any soon, I think we can hold on to the present approach. :)
> What now remains is copying commands, `yiw', `yas', etc., and visual commands like `viw' and `vas'. The former requires updating `viper-prefix-arg-com' with entries for `vimpulse-yi' and `vimpulse-ya', while the latter is just a matter of writing commands for moving the cursor. For example, `vas' moves the cursor one sentence forward if it's at the end of the selection, and one sentence backward if it's at the beginning.
> I think this illustrates another point, incidentally: the power of vi comes from the multitude of ways of combining very basic commands, but implementing those combinations requires lots and lots of code. Therefore I think building vimpulse.el on top on Viper, rather than implementing Vim emulation from scratch, is the better approach.
> Marius Andersen
>       _________________________________________________________
> Alt i ett. Få Yahoo! Mail med adressekartotek, kalender og
> notisblokk. http://no.mail.yahoo.com
> _______________________________________________
> implementations-list mailing list
> implementations-list at lists.ourproject.org
> https://lists.ourproject.org/cgi-bin/mailman/listinfo/implementations-list

More information about the implementations-list mailing list