Home - OXY2DEV/ui.nvim GitHub Wiki

💻 ui.nvim

A blueprint/template/guide for ricing Neovim's UI using Lua.

📚 Table of contents

📐 Architecture

ui.lua ─── vim.ui_attach() ┬┬─> cmdline.lua ──> handle() ──> state change ──> __render() | __close()
                           │└─> message.lua ──> handle() ──> __add() | __replace() | __confirm() | __list() ──> __render() 
                           └──> popup.lua   ──> handle() ──> state change ──> __render()

                           ───> linegrid.lua ──> handle()

For the sake of making things easy to understand and simple to debug/test, the plugin follows a simple tree-like file structure.

It's flow is also linear(in most cases).

You can visualize the files like so,

     nvim
      ↓
plugin/ui.lua
 │    ↓
 │  ui.lua ┬┬┬─> cmdline.lua
 │         ││└─> message.lua 
 │         │└──> popup.lua 
 │         └───> linegrid.lua 
 │
 │              ─>  log.lua  ─>   # Logger connects to all the files.
 │              <─ utils.lua <─   # Utilities are used by all other files.
 │
 └─> highlight.lua

To prevent needing to call setup(), the setup function gets called in plugin/ui.lua. Also, everything is loaded after VimEnter to reduce load time.

Everything starts at the vim.ui_attach() function in ui.lua. The UI events captured by it gets sent to one of the sub-modules(ui/cmdline.lua, ui/message.lua, ui/popup.lua, ui/linegrid.lua).

A map(see here) is used to determine the sub-module an event is supposed to go to.

📝 Event handling

Each sub-module has a handle() function for handling various event types. A setup() function may optionally exist within the sub-module(s) that will get called when the plugin loads.

Event callbacks wrapped in a pcall() to prevent internal errors from disrupting the user.

🔰 Command-line

The command-line(aka cmdline.lua) sub-module works by updating a command-line state variable(see here).

The state later gets read by the __render() function which populates a buffer with the necessary lines of text. This buffer then gets shown in a window.

In most cases the __render() function gets scheduled(instead of immediately executing). However, when commands have previews(e.g. :s/) it gets executed immediately.

🔰 Messages

The messages sub-module(aka message.lua) works by using a table(see here) to store messages.

Messages initially gets stored in the message.visible table which represents the messages that will be shown to the user. Each message entry later gets removed from this table, which hides them from the user.

Most messages gets also stored in message.history table. You can view them via :messages command and using the internal message history.

🔰 Completion

The completion sub-module(aka popup.lua) is used to show completions. It works by maintaining a completion state(like the command-line).

When __render() gets called it reads each entry in the completion menu and writes them to a buffer which gets shown in the completion/pop-up window.

🔰 Line-grid

Currently has no use.