Skip to content

HTML in output (proof-of-concept) #5172

Open
@PerBothner

Description

My html-blocks forkallows an application to "print" output lines containing HTML to an xterm.js terminal. This is a generalization of existing extensions to "print" images, such as using Sixel. However, using HTML is often preferable, as the output can be scaled, selected (copied), can include clickable links and buttons, is usually more compact, and more easily serialized. The output can also re-flow (based on terminal width and zoom), and can also react to style changes, such a light vs dark mode.

The current implementation is restricted to HTML blocks that extend the full width of the screen. It is also limited to output that gets appended to the end of the buffer. While limited, this is basically what you need to support a REPL with "rich" output. For example a graphing program that display plots using SVG. Emitting nicer-looking and copyable tables. A symbolic math program that emits formulas using MathML.

Replacing/updating previously-printed HTML blocks would be a straight-forward extension. Another natural extension would be a protocol for buttons that when clicked sends a string to the application.

This is a very preliminary proof-of-concept, not usable for real use. It is based on my buffer-cell-cursor fork, which is mostly-usable (though there are still bugs to fix). I think of the html-blocks branch as an example and motivation for the buffer-cell-cursor branch: The former adds a new class ElementBufferLine that extends BufferLine.

Screenshots and examples

Gnuplot is plotting program that can emit plots in a number of formals, including SVG and "domterm" (which is just SVG wrapped in an escape sequence). Gnuplot defaults to "domterm" output when the DOMTERM environment varible is set. The following shows an example, running gnuplot in batch (rather than interactive) mode.

Screenshot from 2024-09-29 17-49-50

More examples later.

Issues

  • Before polishing and finishing the html-blocks branch we need to polish and finish the buffer-cell-cursor branch that it depends on.

  • Scrolling is xterm.js is done as multiples of rows. This doesn't work well when lines are different heights. A work-around is to treat an HTML block as multiple rows, rounding up the height divided by standard row height. However, this leads to ugly excess space. It is also not good long-term. For example one might want to allow plain-text lines with a mix of font sizes:
    We don't want each line to be some multiple of the "standard row size" depending on the font used.

    Probably the best solution is to change the scrolling API and implementation to work in terms of pixels rather than rows.
    This is not inherently complicated, but it is extensive. I added a scrollPartialLines option to enable scrolling by fractional rows, but it does not do much yet. Getting it working should be a separate issue and PR.

  • If lines no longer are a fixed height, mapping between pixel offsets and (row, char) offsets are no longer simple
    multiplications or divisions. Linear or binary search may be needed, augmented with caching. However, note that while (for example) mapping a mouse click to a (row, char) offset may require a linear or binary search, the constant factors are small, since we are restricted to the visible screen.

  • Only the Dom renderer has the needed support, but I see no reason the WebGl renderer should be a problem.

  • Selection is not implemented. Ideally, one would want selection to extend across both regular rows and parts of HTML blocks.

  • Re-flow on screen resize is not implemented.

  • Truncation of output is not implemented. (Most people who want rich HTML output will probably want infinite scrollback, so it is a lesser priority.)

  • Serialization of HTML segments has not been implemented, though no complicated issues are foreseen.

Trying it out

Let me know if you want to try it out.

My current test-bed uses xterm.js embedded in DomTerm. DomTerm provides "safety-scrubbing" of the HTML that most people will want, and some other features to make the feature easier. I can provide instructions, if requested.

The next step is to make this feature not depend on DomTerm. Specifcally, it should be accessible from the Demo. This would probably involve a new addon (which we might call addon-html-blocks). This would include customizable safety-scrubbing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    type/proposalA proposal that needs some discussion before proceeding

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions