Skip to content

Feature request ⚡: attach to a UI client and consume redraw events #37

@gorillamoe

Description

@gorillamoe

Try if this is feasible to get the same functionality as we currently have.

This could open up the possibility to have the real representation of what the user sees in the complete Neovim instance, including:

  • Every visible grid
  • Exact cell contents
  • Highlight IDs
  • Window placement
  • Floating windows
  • Statuslines, tablines, cmdline, popupmenu
vim.api.nvim_ui_attach(width, height, {
  ext_linegrid = true,
  ext_multigrid = true,
  ext_hlstate = true,
  ext_termcolors = true,
})

Per redraw event we should get batches like this:

{
  { "grid_resize", grid, width, height },
  { "grid_line", grid, row, col, cells },
  { "grid_clear", grid },
  { "grid_cursor_goto", grid, row, col },
  { "win_pos", grid, win, row, col, width, height },
  { "hl_attr_define", id, rgb_attrs, cterm_attrs },
}

In each grid_line the cells contain:

{ text, hl_id, repeat }
  • Handles wide chars
  • Handles tabs
  • Already includes virtual text, folds, conceal, etc.

This is probably how the layout looks like:

Neovim Scene
├── Grid 1 (main window)
│   ├── Cell[row][col] → { text, style }
├── Grid 2 (statusline)
├── Grid 3 (floating LSP hover)
├── Grid 4 (cmdline)
  • Resolve win_pos → absolute screen coordinates
  • Paint grids back-to-front
  • Apply highlight attributes

This gets us:

  • Splits
  • Floats
  • Borders
  • Statuslines
  • Tabline
  • Cmdline
  • Popup menu

We should cache the highlight ids we receive, because they probably don't change:

hl_attr_define(id, {
  foreground = 0xRRGGBB,
  background = 0xRRGGBB,
  bold = true,
  italic = true,
  underline = true,
})

For caching, we might go with cache highlight ids by default and even reuse them for consecutive :Snap calls.

But we should implement a way to force the rebuilt of that cache.

This is probably an edge case scenario, but people who want to take snaps of themes or developer of themes might benefit from this, because here, the highlight ids might stay the same, but the styling might change "all the time".

I think the best way to approach this is by having the :Snap command not only work with :Snap [type] like :Snap image, but also parse additional arguments as key value pairs if it includes a =, or just consume them as instructions if no = is found.

So both :Snap image cache=false and :Snap image nocache would work.

I think, we should implement the complete parsing of arguments, but only go with the nocache instruction for this feature. This can also be extended afterwards, if needed.

Every cell references a highlight ID → CSS mapping.

Check if we can also track/query and resolve:

  • grid_cursor_goto
  • mode_change
  • busy_start / busy_stop
  • Cursor block rendering
  • Insert-mode caret
  • Blinking

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

Status

Ready

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions