Vim-fork focused on extensibility and usability
Go to file
Thiago de Arruda 8d93621c63 main: Start modeling Nvim as pushdown automaton
From a very high level point of view, Vim/Nvim can be described as state
machines following these instructions in a loop:

- Read user input
- Peform some action. The action is determined by the current state and can
  switch states.
- Possibly display some feedback to the user.

This is not immediately visible because these instructions spread across dozens
of nested loops and function calls, making it very hard to modify the state
machine(to support more event types, for example).

So far, the approach Nvim has taken to allow more events is this:

- At the very core function that blocks for input, poll for arbitrary events.
- If the event received from the OS is user input, just return it normally to
  the callers.
- If the event is not direct result of user input(possibly a vimscript function
  call coming from a msgpack-rpc socket or a job control callback), return a
  special key code(`K_EVENT`) that is handled by callers where it is safer to
  perform arbitrary actions.

One problem with this approach is that the `K_EVENT` signal is being sent across
multiple states that may be unaware of it. This was partially fixed with the
`input_enable_events`/`input_disable_events` functions, which were added as a
mechanism that the upper layers can use to tell the core input functions that it
is ready to accept `K_EVENT`.

Another problem is that the mapping engine is implemented in getchar.c
which is called from every state, but the mapping engine is not aware of
`K_EVENT` so events can break mappings.

While it is theoretically possible to modify getchar.c to make it aware of
`K_EVENT`, this commit fixes the problem with a different approach: Model Nvim
as a pushdown automaton(https://en.wikipedia.org/wiki/Pushdown_automaton). This
design has many advantages which include:

- Decoupling the event loop from the states reponsible for handling events.
- Better control of state transition with less dependency on global variable
  hacks(eg: 'restart_edit' global variable).
- Easier removal of global variables and function splitting. That is because
  many variables are for state-specific information, and probably ended up being
  global to simplify communication between functions, which we fix by storing
  state-specific information in specialized structures.

The final goal is to let Nvim have a single top-level event loop represented by
the following pseudo-code:

```
while not quitting
  let event = read_event
  current_state(event)
  update_screen()
```

This closely mirrors the state machine description above and makes it easier to
understand, extend and debug the program.

Note that while the pseudo code suggests an explicit stack of states that
doesn't rely on return addresses(as suggested by the principles of
automata-based programming:
https://en.wikipedia.org/wiki/Automata-based_programming), for now we'll use the
call stack as a structure to manage state transitioning as it would be very
difficult to refactor Nvim to use an explicit stack of states, and the benefits
would be small.

While this change may seem like an endless amount of work, it is possible to
do it incrementally as was shown in the previous commits. The general procedure
is:

1- Find a blocking `vgetc()`(or derivatives) call. This call represents an
   implicit state of the program.

2- Split the code before and after the `vgetc()` call into functions that match
   the signature of `state_check_callback` and `state_execute_callback.
   Only `state_execute_callback` is required.

3- Create a `VimState` "subclass" and a initializer function that sets the
   function pointers and performs any other required initialization steps. If
   the state has no local variables, just use `VimState` without subclassing.

4- Instead of calling the original function containing the `vgetc()`,
   initialize a stack-allocated `VimState` subclass, then call `state_enter` to
   begin processing events in the state.

5- The check/execute callbacks can return 1 to continue normally, 0 to break the
   loop or -1 to skip to the next iteration. These callbacks contain code that
   execute before and after the old `vgetc()` call.

The functions created in step 2 may contain other `vgetc()` calls. These
represent implicit sub-states of the current state, but it is fine to remove
them later in smaller steps since we didn't break compatibility with existing
code.
2015-10-26 10:52:01 -03:00
.ci Travis: Install Python 3 to run Python 3 tests. 2015-09-27 00:03:06 +02:00
cmake Windows: Link against libraries libuv needs on Windows. 2015-09-09 17:44:22 -04:00
config config: Check order and endianess even when cross-compiling 2015-10-08 22:00:45 +03:00
contrib viminfo: First version of ShaDa file dumping 2015-10-08 21:59:51 +03:00
man nvim.1: bump date 2015-10-17 14:42:46 -04:00
runtime tutor: fix location for init.vim file 2015-10-26 14:47:11 +01:00
scripts scripts: Add filter argument to shadacat.py 2015-10-23 14:47:59 +03:00
src main: Start modeling Nvim as pushdown automaton 2015-10-26 10:52:01 -03:00
test input: Remove CURSORHOLD key 2015-10-26 10:52:01 -03:00
third-party deps: Update to libtermkey 0.18. 2015-10-07 21:28:09 +02:00
unicode Update unicode files 2015-07-26 22:59:46 +03:00
.asan-blacklist queue: Implement a more flexible event queue 2015-08-13 08:46:21 -03:00
.gitignore mark: Clear marks in some cases, but do not do useless job in free_\* 2015-10-08 22:00:46 +03:00
.travis.yml travis: Use gtest for busted output type 2015-10-05 13:46:13 +03:00
.valgrind.supp job: Refactor process spawning and startup arguments 2015-02-23 21:43:33 -03:00
appveyor.yml Windows: Crank to MSVC 2015 on AppVeyor. #3254 2015-08-27 23:21:04 -04:00
BACKERS.md Remove duplicates in BACKERS.md #2363 2015-04-06 15:43:31 -04:00
clint.py clint: Add support for errors suppression 2015-08-15 19:09:16 +03:00
CMakeLists.txt build: Check if compiler supports -Wvla before use 2015-10-02 13:02:44 -04:00
CONTRIBUTING.md CONTRIBUTING.md: Fix broken links #2702 2015-05-19 17:06:22 -04:00
Doxyfile update theme to match neovim.org 2014-06-19 11:53:57 +02:00
LICENSE LICENSE: add LuaJIT notice. #899 2014-06-30 13:59:56 -04:00
Makefile ci: Use error suppression in place of ignored files list. #3185 2015-08-20 23:40:15 -04:00
neovim.rb Homebrew: move formula to neovim/homebrew-neovim 2014-11-09 20:14:01 +08:00
README.md README.md: Various 2015-07-05 11:45:41 -04:00
uncrustify.cfg spelling fixes #827 2014-06-12 20:26:35 -04:00

Neovim

Website | Community | Wiki | Documentation | Mailing List | Twitter | Bountysource

Travis Build Status AppVeyor Build status Pull requests waiting for review Coverage Status Coverity Scan Build Clang Scan Build Join the chat at https://gitter.im/neovim/neovim

Neovim is a project that seeks to aggressively refactor Vim in order to:

  • Simplify maintenance and encourage contributions
  • Split the work between multiple developers
  • Enable the implementation of new/modern user interfaces without any modifications to the core source
  • Improve extensibility with a new plugin architecture

For lots more details, see the wiki!

What's been done so far

See the progress page for a comprehensive list.

Throughput Graph

What's being worked on now

  • Port all IO to libuv
  • Convert legacy tests to Lua tests
  • VimL => Lua translator

How do I get it?

There is a formula for OSX/homebrew, a PKGBUILD for Arch Linux, RPM, deb, and more. See the wiki!

Contributing

...would be awesome! See the wiki for more details.

License

Neovim is licensed under the terms of the Apache 2.0 license, except for parts that were contributed under the Vim license.

  • Contributions committed before b17d96 by authors who did not sign the Contributor License Agreement (CLA) remain under the Vim license.

  • Contributions committed after b17d96 are licensed under Apache 2.0 unless those contributions were copied from Vim (identified in the commit logs by the vim-patch token).

See LICENSE for details.

Vim is Charityware.  You can use and copy it as much as you like, but you are
encouraged to make a donation for needy children in Uganda.  Please see the
kcc section of the vim docs or visit the ICCF web site, available at these URLs:

        http://iccf-holland.org/
        http://www.vim.org/iccf/
        http://www.iccf.nl/

You can also sponsor the development of Vim.  Vim sponsors can vote for
features.  The money goes to Uganda anyway.