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

Jon j at ngedit.com
Mon Jun 29 12:56:44 CEST 2009

Alessandro, you're very welcome. ViEmu is closed source and commercial, 
so the design is not really publicly available. I hope the short summary 
can be helpful if anyone is curious.

I am not very familiar with viper or vimpulse internally, I understand 
the context may make some design decisions impossible.

Good luck with your project.

  -- Jon

Alessandro Piras wrote:
> 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.
> Alessandro
> 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
> _______________________________________________
> 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