In this post I’ll give a very high-level overview of Yi’s structure. This the first part of a series that should eventually constitute a guide for Yi hacking… but let’s get going!
Yi code can be categorized into four parts:
Actions, which are operations having some effect on the editor state. This can be opening or saving a file, or moving the cursor in the current buffer.
Keymaps, governing how user input maps to actions. Yi comes with keymaps for emacs and vi emulation (and users are encouraged to write their own keymaps). Keymaps are very much like parser-combinators, but they produce a stream of actions instead of a parse-tree.
UIs, which are responsible for rendering the editor state, and getting the stream of input events from the user. Yi comes with console, gtk and experimental cocoa UI.
Glue code, to tie the knot between Keymaps and UI.
The structure described above is very flexible: there is very low coupling between components. Indeed, one can easily swap out one component for another in the same category. For example, the user can choose between the different UIs and key-bindings at runtime.
The “actions” part makes up most of the editor code. This part is structured around a stack of three monadic DSLs.
BufferM: A monad for all buffer-local operations, like insertion and deletion of text, and annotation of buffer contents. It can be understood as a monad that encapsulates the state of one buffer.
EditorM: A monad for editor-level operations, e.g., opening and closing windows and buffers. Operations involving more than one buffer are handled at this level too.
YiM: A monad for IO-level operations. There, one can operate on files, processes, etc. This is the only level where IO can be performed.
All these parts are easily composable, and this makes convenient to extend (and configure) the editor. In the next post we’ll see in more detail how to do so.