Skip to content

Improve multiple neovim instances support (viminfo) #999

@ZyX-I

Description

@ZyX-I

There is one known problem with Vim: if you launched two instances, did some things in both of them and quit only data from last Vim is saved into viminfo: Vim does not bother reading viminfo before writing it (except for marks). Thus my suggestion:

  1. Tag all saved values with the time they were modified. Specifically
    • Variables (:h viminfo-!), registers, uppercase marks should be tagged per-element (one tag for one variable, register and mark). Default tag (for unset or converted values) is -inf.
    • Buffer list should not be tagged at all (last one always wins).
    • Each previous edited file (:h viminfo-') should be tagged on its own, and each saved lowercase mark should be tagged as well. Tags on edited files are updated whenever file is closed (if file is not closed then it should use exit time).
    • Each history item should be tagged on its own.
  2. When saving read this back and
    • Update variables, registers and uppercase marks only in case they were modified in this vim instance after those in viminfo or at the same time. Decision is to be made element-wise.
    • Buffer list is just saved.
    • When deciding on previously edited file first decide on the list (if it is too lengthy drop the oldest elements), then retag remaining files using the most recent time. After this merge lowercase marks just like uppercase marks were merged before.
    • History items are ordered according to their tag (if times are equal quiting neovim instance’s history comes last) and drop some oldest elements if list became too lengthy.
  3. Use some kind of synchronization before saving file in order to not mess up with viminfo. I think documenting officially that viminfo must not be a symlink, writing viminfo to some adjacent location and overwriting viminfo with new one iff inode did not change should work (if inode did change merging should be repeated) (some sort of CAS) nearly always, even though between reading inode and moving saved viminfo it may be overwritten: there is not much sense in having 100% bullet-proof solution here. I also know about flock(), but never saw it working. And using lock files is slow and requires detection of the situation “other neovim crashed before releasing lock”.

Before implementing any of the above it is good to look at zsh: it has such interesting options as INC_APPEND_HISTORY (update history file as soon as history item appears), APPEND_HISTORY (the most simple way to avoid problem Vim has) and SHARE_HISTORY (history file is read each time it is updated, so all zsh instances have the same history list always).

It may be better to take alternative approach: write viminfo as a log and when it grows too large clean it. This makes it possible to directly take code from zsh and support all of the above options. Log should look like this: timestamp:action:arguments:

1406449750:set_previously_edited_file:/home/zyx/foo
1406449750:set_file_mark:\0/home/zyx/foo\0:.:18:0

(Note: using NUL to terminate file name. Newline can also be present in the filename and I do not want to bother with escaping. First NUL is there to indicate that newline may be in the argument.)

Though I am not sure whether we should make this log human-readable: using uint64_t casted to char[8] (need to ensure endianness though), one character for action (with switch) and special parser for each of the actions should work much faster and reqire much less on-disk space. Will need a tool to show this log in a human-readable fashion, but this is really simple.

By cleaning I mean first removing successive elements that obsolete each other (e.g. two elements setting one uppercase mark). Then remove oldest duplicate elements from history (e.g. two successive appends of identical history lines). Last: remove oldest items that makes some list (of old files, history lines, etc) grow too large.

This should be decided before first release because we do not want to add compatibility code, do we?


Want to back this issue? Place a bounty on it! We accept bounties via Bountysource.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs:decisiondiscussion has run its course, need decision how to proceedneeds:designneeds a clear design proposal

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions