Use Virtual DOM for rendering
See original GitHub issueI’d like to discuss the usage of a virtual dom implementation for rendering the output (lines, selection, links…).
At the moment, we implement something similar by caching spans that we can reuse for the next render cycle. Although this is okay for the moment, I feel it is very constraining:
-
There is no real view / model that is used to render the DOM nodes in the viewport. At the moment there is a quite complex and difficult to extend block of logical statements that directly create the DOM nodes from the somewhat flat row / col array. I feel it would be much nicer if those logical statements would produce a data structure (view model) that can be efficiently rendered, cached and extended by a virtual dom library.
-
It is very hard to delay rendering for certain features, like the linkifier. It would be much nicer if the linkifier could asynchronously process the data and eventually update the targeted cols with a flag, that will then be reflected in the rendered output automatically.
-
The current data structure is neither optimised for rendering performance, nor for scenarios like
linkify
orfind
that have to get context from the data.
Challenges
I believe the biggest challenge is to convert a flat data structure (row/col data) into a optimised, reusable view model. For example the string:
Hello World
would have to end up as
Hello <span class="xterm-bold">World</span>
In other words, cols have to be grouped based on their flags. Cols that share the exact same flags can go into the same group (DOM node).
My approach would be to use the following (possibly extendable) flags for every col:
fg
number: The foreground colorbg
number: The background colorbold
boolean: Bold colunderline
boolean: Underlined colblink
boolean: Blink colinverse
boolean: Invert fg/bginvisible
boolean: Col is invisible (.xterm-hidden)cursor
boolean: Cursor is at this positionwide
boolean: Is a wide character being renderednoAscii
boolean: Is the character a non-ascii character (charcode > 255)selected
boolean: Col is currently selected (Selection Manager)matched
boolean: Col is currently matched by a search term (find addon)link
string: Col is linked with this url (Linkifier)
And process them into an array of lines, where every line contains the definition of the grouped cols that share the same flags:
[[
{ chars: 'Hello ', flags: {} },
{ chars: 'World', flags: { bold: true } }
]]
This view model would be easy to convert into virtual dom by looping over the rows, rendering a div for every row, and then looping over the groups and creating a span
or a
for every group and add a class or style to reflect the flags.
In order for the linkifier, selection manager or the find addon to set / remove flags, they would have to register themselves as a middleware before the grouping stage, so they can flag cols before they are grouped.
Any thoughts?
Issue Analytics
- State:
- Created 6 years ago
- Comments:14 (14 by maintainers)
Top GitHub Comments
Just thinking, another perk of having a drawing abstraction in between: it would allow us to implement a drawing engine that is not based on actual DOM elements - for example we could render the screen in a
canvas
orsvg
or even inwebgl
, which should boost the performance even further 😎Oh now I see what you mean, maybe there should be an additional api like this:
Which would create a stack:
That is finally rendered as:
where only the div is absolutely positioned. I’ll try to figure out a nicer and more consistent API syntax when implementing the prototype.