A screen’s worth of text lines, rendered by diffing against the last.
The model is “set every line, render, repeat”. render compares each
line with what was last rendered and emits moves and rewrites only
for the rows that changed, so an otherwise idle board that updates a
clock writes one line rather than twenty-four. That is what makes the
simple model flicker-free.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer(kind=default_int), | private | :: | cols | = | 0_default_int |
Width in code points; |
|
| type(string_type), | private, | allocatable | :: | current(:) |
Lines as set since the last render.
A deferred-length allocatable array cannot be blanked with a
whole-array And a fixed row length has to be guessed. Escape sequences make a styled line far longer in bytes than in columns – per-character colouring runs to about ten bytes a column – so any constant multiple of the width is a cap waiting to truncate someone’s row. |
||
| logical, | private | :: | full_redraw | = | .true. |
Set by |
|
| integer(kind=default_int), | private | :: | rows | = | 0_default_int |
Number of lines. |
|
| type(string_type), | private, | allocatable | :: | shown(:) |
Lines as of the last render, for diffing. |
Width the frame truncates to.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(frame_t), | intent(in) | :: | this |
Force the next render to emit every row.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(frame_t), | intent(inout) | :: | this |
The escape sequence that brings the screen up to date.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(frame_t), | intent(inout) | :: | this |
Set the frame’s dimensions, discarding the diff.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(frame_t), | intent(inout) | :: | this | |||
| integer(kind=default_int), | intent(in) | :: | rows |
Number of lines; below 0 is treated as 0. |
||
| integer(kind=default_int), | intent(in) | :: | cols |
Width in code points; below 0 is treated as 0. |
Number of lines the frame holds.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(frame_t), | intent(in) | :: | this |
Set one line, truncated to the frame width in code points.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(frame_t), | intent(inout) | :: | this | |||
| integer(kind=default_int), | intent(in) | :: | row |
One-based row. |
||
| character(len=*), | intent(in) | :: | text |
Text for the row. |
type :: frame_t !! A screen's worth of text lines, rendered by diffing against the last. !! !! The model is "set every line, render, repeat". `render` compares each !! line with what was last rendered and emits moves and rewrites only !! for the rows that changed, so an otherwise idle board that updates a !! clock writes one line rather than twenty-four. That is what makes the !! simple model flicker-free. private type(string_type), allocatable :: current(:) !! Lines as set since the last render. !! !! `string_type` rather than `character(len=:), allocatable :: (:)` !! for two reasons, both learned the hard way. !! !! A deferred-length allocatable *array* cannot be blanked with a !! whole-array `= ""`: F2018 10.2.1.3 deallocates and reallocates an !! allocatable whose length type parameter differs from the !! expression's, so that assignment sets the length to zero. GNU, !! AOCC and LFortran keep the length and blank-pad; Intel and NVIDIA !! reallocate. Both readings are defensible and the construct is !! therefore unusable here. !! !! And a fixed row length has to be guessed. Escape sequences make a !! styled line far longer in bytes than in columns -- per-character !! colouring runs to about ten bytes a column -- so any constant !! multiple of the width is a cap waiting to truncate someone's row. type(string_type), allocatable :: shown(:) !! Lines as of the last render, for diffing. integer(default_int) :: rows = 0_default_int !! Number of lines. integer(default_int) :: cols = 0_default_int !! Width in code points; `set_line` truncates to it. logical :: full_redraw = .true. !! Set by `resize` and `invalidate`; makes the next render emit every !! row regardless of the diff. contains procedure :: resize => frame_resize procedure :: set_line => frame_set_line procedure :: render => frame_render procedure :: invalidate => frame_invalidate procedure :: row_count => frame_row_count procedure :: col_count => frame_col_count end type frame_t