It should be possible to change where the rendering starts by adding an offset on the x-axis. Here the offset is two columns of the terminal, meaning we've scrolled two columns to the right:
│ D Name or Initial Func Red |
│ ID<0.0.0> init 373 |
│ ID<0.1.0> erts_code_purger 229 |
│ ID<0.2.0> erts_literal_area_collector:start/0 220 |
│ ID<0.3.0> erts_dirty_process_signal_handler:start/0 575 |
│ ID<0.4.0> erts_dirty_process_signal_handler:start/0 46 |
We can continue scrolling right by increasing the x offset to four columns:
Similar to how we've applied an x-axis offset above, it can be helpful to apply an offset to the y-axis:
GREP(1) General Commands Manual GREP(1)
NAME
grep, egrep, fgrep - print lines matching a pattern
SYNOPSIS
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] -e PATTERN ... [FILE...]
grep [OPTIONS] -f FILE ... [FILE...]
DESCRIPTION
grep searches for PATTERN in each FILE. A FILE of “-” stands
for standard input. If no FILE is given, recursive searches
examine the working directory, and nonrecursive searches read
standard input. By default, grep prints the matching lines.
With 2 rows of offset applied:
NAME
grep, egrep, fgrep - print lines matching a pattern
SYNOPSIS
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] -e PATTERN ... [FILE...]
grep [OPTIONS] -f FILE ... [FILE...]
DESCRIPTION
grep searches for PATTERN in each FILE. A FILE of “-” stands
for standard input. If no FILE is given, recursive searches
examine the working directory, and nonrecursive searches read
standard input. By default, grep prints the matching lines.
In addition, the variant programs egrep and fgrep are the same
as grep -E and grep -F, respectively. These variants are
Contrasting with Scrolling on the Web
While HTML defines a structured document, it makes few prescriptions as to how the content is actually rendered. In the case of a scrollbar, it's the web browser that ultimately decides to show a scrollbar based on directives from CSS and whether or not the content would overflow the allotted rendering region. How the browser's viewport looks at any given moment depends on the HTML, the CSS, running scripts, and the browser's own internal state and environment.
Ratatouille provides both a language for defining such a structured document and a rendering engine for rendering the document. Rendering in Ratatouille is a pure function. Rendering the same document onto the same canvas should always produce an identical resulting canvas. Whether the resulting canvas is then output to a terminal or as a string is just a small implementation detail. Unlike the browser, Ratatouille never directly changes what's rendered in response to user input. Rather, it only provides a pattern for it---an application needs to define a new document in response to the input event, and Ratatouille will render this new document. In this way, rendering and event handling are decoupled in Ratatouille.
This also ties back into scrolling. Since rendering in Ratatouille is just a pure function of a canvas and a document, any rendering directives (height, width, color, etc.) would need to be stored within the canvas (which stores dimensions and cells) or the document. Unlike the document, the canvas isn't hierarchical---it's only top-level information. That means we could store a scroll offset on the top-level, but not for nested elements such as a table within a tab pane.
Implementation
I think this means we need to somehow encode the offsets in the document itself, e.g.
table(offset_x: 5) do
table_row do
table_cell(content: "foo")
end
end
A more elegant approach could be to define a container to handle offseting arbitrary child elements:
viewport(offset_x: 5, offset_y: 3)
table do
table_row do
table_cell(content: "foo")
end
end
end
The rendering logic for the viewport element could initially be relatively simple. E.g., given a canvas with a rendering region of 100 columns by 40 rows, and a desired x-offset of 5 and y-offset of 3:
Make a copy of the canvas with no cells and an adjusted rendering region of 105 columns and 43 rows.
Render the viewport's content onto this copy.
Shift all of the rendered cells in the copy by -5 columns and -3 rows.
Merge the copy with the original canvas and return the result.
In order to implement scrolling in a UI, it should be possible to render content such that it's offset by some number of rows and/or columns.
Examples
Horizontal scrolling inside a table
The major use case I have in mind is horizontal scrolling within a table. For example, take the following table:
The table will be further truncated whenever the screen width does not accomodate rendering additional columns, e.g.:
It should be possible to change where the rendering starts by adding an offset on the x-axis. Here the offset is two columns of the terminal, meaning we've scrolled two columns to the right:
We can continue scrolling right by increasing the x offset to four columns:
less/more-style pager
Similar to how we've applied an x-axis offset above, it can be helpful to apply an offset to the y-axis:
With 2 rows of offset applied:
Contrasting with Scrolling on the Web
While HTML defines a structured document, it makes few prescriptions as to how the content is actually rendered. In the case of a scrollbar, it's the web browser that ultimately decides to show a scrollbar based on directives from CSS and whether or not the content would overflow the allotted rendering region. How the browser's viewport looks at any given moment depends on the HTML, the CSS, running scripts, and the browser's own internal state and environment.
Ratatouille provides both a language for defining such a structured document and a rendering engine for rendering the document. Rendering in Ratatouille is a pure function. Rendering the same document onto the same canvas should always produce an identical resulting canvas. Whether the resulting canvas is then output to a terminal or as a string is just a small implementation detail. Unlike the browser, Ratatouille never directly changes what's rendered in response to user input. Rather, it only provides a pattern for it---an application needs to define a new document in response to the input event, and Ratatouille will render this new document. In this way, rendering and event handling are decoupled in Ratatouille.
This also ties back into scrolling. Since rendering in Ratatouille is just a pure function of a canvas and a document, any rendering directives (height, width, color, etc.) would need to be stored within the canvas (which stores dimensions and cells) or the document. Unlike the document, the canvas isn't hierarchical---it's only top-level information. That means we could store a scroll offset on the top-level, but not for nested elements such as a table within a tab pane.
Implementation
I think this means we need to somehow encode the offsets in the document itself, e.g.
A more elegant approach could be to define a container to handle offseting arbitrary child elements:
The rendering logic for the
viewport
element could initially be relatively simple. E.g., given a canvas with a rendering region of 100 columns by 40 rows, and a desired x-offset of 5 and y-offset of 3:viewport
's content onto this copy.