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

Alessandro Piras laynor at gmail.com
Wed Jun 24 22:25:33 CEST 2009

Hi Jon,
I don't know the details of the design of ViEmu either, but from what you're
saying it seems a good design, thanks for sharing some details. I will take
into account your suggestions when and if I decide to design and implement a
new vi clone, maybe for emacs.
Now I can only partially follow them, as most of the emulation is already
implemented in viper, and I'm working on top of it, so I have to cope with
its design. Furthermore, I don't have a very deep knowledge of viper, as
vimpulse was born in a rush, out of frustration of having to cope with emacs
"nice" bindings.
I began working again on it last week, after two years in which I didn't use
or contribute to its development.
One of my objectives with vimpulse is changing viper's code only when
strictly needed, as it was in the case of di ci da ca kind of commands.
For example, vimpulse doesn't support commands of the form d2aw. Supporting
them would require major changes to a viper function, because basically,
viper works like this: it checks if the character after command (in the case
of 2d3w, the character '3') is numeric, if it is, reads a numeric argument,
and executes the command following 3. So basically, what it does in a d2w
command is moving the cursor 2 words, and deletes the range identified by
the old and the new position. At least, that's what I understood looking at
the code.
As a result of this, it reacts in a stupid way to nonsense commands like
4d2x, that is equivalent to 2x.
Another side effect is that d2iw results in viper entering insert mode and
inseerting 'w' in the buffer, and when it returns to vi mode, the text
inserted is inserted again as a result of the '2' in d2iw.
I really don't know which changes to viper are needed to get correct
behavior, but it seems to me that the design is not as clean as yours, in
that motions and commands are not as orthogonal.

about my text objects implementation, my motions return a range (start end),
and my commands operate on such ranges. :)
You made me think more about the issue though, thank you, I'll try to keep
things clean at least for what concerns my code.


2009/6/24 Jon <j at ngedit.com>

> 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
> _______________________________________________
> 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