question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use Virtual DOM for rendering

See original GitHub issue

I’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:

  1. 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.

  2. 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.

  3. The current data structure is neither optimised for rendering performance, nor for scenarios like linkify or find 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 color
  • bg number: The background color
  • bold boolean: Bold col
  • underline boolean: Underlined col
  • blink boolean: Blink col
  • inverse boolean: Invert fg/bg
  • invisible boolean: Col is invisible (.xterm-hidden)
  • cursor boolean: Cursor is at this position
  • wide boolean: Is a wide character being rendered
  • noAscii 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:closed
  • Created 6 years ago
  • Comments:14 (14 by maintainers)

github_iconTop GitHub Comments

2reactions
mofuxcommented, Aug 1, 2017

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 or svg or even in webgl, which should boost the performance even further 😎

1reaction
mofuxcommented, Jul 21, 2017

Oh now I see what you mean, maybe there should be an additional api like this:

let rowRect = layer.draw('div', ...);

rowRect.appendText('I like ');

let specialCharSpan = rowRect.appendInline('span');
specialCharSpan.class('xterm-normal');
specialCharSpan.text('🤓');

rowRect.appendText(' faces');

Which would create a stack:

['I like ', <span class="xterm-normal">🤓</span>, ' faces']

That is finally rendered as:

<div>I like <span class="xterm-normal">🤓</span> faces</div>

where only the div is absolutely positioned. I’ll try to figure out a nicer and more consistent API syntax when implementing the prototype.

Read more comments on GitHub >

github_iconTop Results From Across the Web

What is the virtual DOM in React? - LogRocket Blog
When we render an application user interface, React creates a virtual DOM tree representing that UI and keeps it in memory.
Read more >
Virtual DOM and Internals - React
The virtual DOM (VDOM) is a programming concept where an ideal, or “virtual”, representation of a UI is kept in memory and synced...
Read more >
React Virtual DOM Explained in Simple English
React follows the observable pattern and listens for state changes. When the state of a component changes, React updates the virtual DOM tree....
Read more >
ReactJS | Virtual DOM - GeeksforGeeks
Virtual DOM : React uses Virtual DOM exists which is like a lightweight copy of the actual DOM(a virtual representation of the DOM)....
Read more >
Using Virtual DOM in React - KnowledgeHut
To mount HTML elements to the virtual DOM, we need to create our components and then render it to the root directory of...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found