Skip to content
C++ Vim implementation
C++ Python
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore Support .vvvimrc Jul 1, 2019
.vvvimrc Implement status bar rendering Jul 1, 2019
ncurses.BUILD Initial commit Jun 30, 2019


Vvvim is lightweight Vim implementation built as a C++ practice. Don't use it for anything serious.

Vvvim implements:

  • Basic Vim key bindings
  • Basic Vim commands (e.g. w, q, and [inv](nore)?map family)
  • Fully remappable keys and key sequences (both recursive and non-recursive) powered by prefix trees
  • A homemade data structure for text buffer -- Nested Gap Buffer
  • Configuration file, see .vvvimrc for an example
  • Key/Operator repeat

Vvvim will probably implement:

  • Visual mode
  • Searching
  • Syntax highlighting
  • Color schemes
  • Tabs
  • set options (All hard-coded to my preference, so things like number and wrap can't be disabled)
  • Macros
  • Marks
  • Registers
  • autocmd

Vvvim will not implement:

  • Vimscript support
  • Plugins
  • Functions
  • Folding
  • ...


Template pattern for supporting multiple frontends

The logic for buffer management, key remapping, key handling etc. are all implemented in Editor, the abstract class with the Template pattern. Editor frontends extends the Editor class and implements methods such as Insert() and SwitchMode.

Nested Gap Buffer

Homemade data structure for interacting with the editor buffer. It has two layers:

  1. Inner layer: Just a normal gap buffer with head_ and tail_ strings, representing the line currently being edited, and the line can be reconstructed by head_ + reverse(tail_)
    "hello w|orld"
    head = "hello w"
    tail = "dlro"
  2. Outer layer: Gap buffer of strings, lines_head_ and lines_tail_ are lists of strings. The full buffer can be reconstructed with: lines_head_ + [head_ + reverse(tail_) + reverse(lines_tail_)

Important operations and complexities:

  • MoveInsertionPointTo(int row, int col): changes the place where Insert(char c) will take place. O(r + c) time where r is the number of rows and c is the length of the row.
    • This operation is only invoked upon entering insert mode, not with any normal mode movement operator.
  • GetLineView(int line_number): random access of buffer lines, returns a std::string_view. O(c) time when accessing current line which needs a merge, otherwise O(1).
  • ToString(): creates a flattened copy of the buffer. O(n) time where n is the length of the buffer.
  • Insert(char c) and Delete(): insert or delete a character from insertion point. O(1) time.

Key Mapping Layer

Full logic:

ncurses         Editor               KeyMap     Editor
getch() -> MapAndExecuteKey ---------> Map --> ExecuteKey --> action
                  ^                     |
                  |                     |
                   <--- if recursive ---

Implementation: Using one prefix tree for each editor mode.

Bindings that starts with an existing binding is not allowed. E.g. imap a bc and imap ad ef cannot both be active.

You can’t perform that action at this time.