CRAN resubmission following the initial 1.0.0 submission (not published on CRAN).
NOT_CRAN=true retains the full seed and
iteration counts.First stable release, prepared as the first CRAN submission. This section summarizes the pre-1.0 work. Stability classifications are defined in API stability.
The release candidate tag v1.0.0-rc1 points to
1846527d3968cdd12fa9900bbe80a9f2a89a1a3e, whose DESCRIPTION
retains Version: 0.9.0.9000. Changes since that tag are
limited to documentation, release metadata and the following:
DESCRIPTION gains URL and
BugReports.animate() and run_worker() examples
now run headlessly with test_app() instead of being wrapped
in \dontrun{}.table_source() pages feed DataTable’s bounded
viewport cache. SQLite tables and views support delegated
sorting/filtering; read-only db_query_source() adds bounded
query-result paging and driver callbacks.sql_editor() keeps materialized query results by
default; lazy mode is opt-in. db_explorer() uses lazy
SQLite previews and query results, portable metadata and an in-memory
history. Database calls are synchronous.status_bar(), property_grid(),
record_view(), data_profile(), and
json_view() for reactive status, record inspection, vector
profiling, and paged R-object trees. record_view() reuses
the property-grid renderer; json_view() reuses lazy
TreeView nodes.data-workbench composition example. These
workflow widgets add no mandatory runtime dependency; optional JSON text
parsing uses jsonlite from Suggests.docs/ssh.md.vt100 as
monochrome, and avoids enabling SGR mouse or bracketed paste for legacy
Linux/VT100 terminals.args still
serialize. The regression passed on Linux, macOS and Windows.ssh -t smoke were manually reported PASS. macOS real
terminal, tmux, screen and RStudio Terminal remain NOT RUN. PTY CI is
separate from manual console validation.jsonlite), explicit
knitr/Quarto output (knitr), and a single
write_rendered() convenience function.snapshot_json() is now
screen_snapshot_json() and inspect_json() is
now widget_snapshot_json(), matching
screen_snapshot() and widget_snapshot(). Both
were new in 0.9; there are no aliases. widget_snapshot()
gains a root schema_version (1).db_table_source(own_connection = ) is now
owned =, as in db_connection(owned = ).register_layout() gains replace = FALSE;
pass TRUE to replace a registration on purpose, e.g. when a
package registering in .onLoad() is reloaded.datatable.source_error is posted once per failure
rather than once per failed page, and carries the root
error message; source_stats() gains
fetch_errors. db_explorer() therefore shows
one notification for one broken connection.Terminal input validates UTF-8 bytes before locale conversion and retains incomplete characters across reads, including on R 4.1.
Workers inherit the parent’s library search paths while keeping
R_TESTS disabled. Process exit drains output without an
unbounded EOF wait, cleans up descendants immediately, and reports
process diagnostics on unexpected exit or a Pilot timeout.
The db_explorer() documentation example now stops
its app and closes the owned SQLite connection.
db_table_source() works with current RSQLite (3.53 /
DBI 1.3), which rejects an empty parameter list; previously every
unfiltered SQLite source, and therefore the db_explorer()
preview, failed at creation. It now also accepts a
db_connection() wrapper.
data_table() with a table source fetches one page
per source call for all columns instead of one call per painted
column.
Moving a mounted widget with mount() keeps its
bind_reactive() bindings, widget timers and owned workers;
only remove() ends them.
widget$on() also accepts the argument order of
on() / app$on():
widget$on(type, selector, handler).
Password inputs no longer reveal their value through
print(), the event log, the debug overlay or
inspect_widget(), and never copy it to a
clipboard.
Text and cells drop C1 control characters (U+0080-U+009F) as well as C0 controls, so untrusted text cannot emit 8-bit CSI/OSC sequences.
The key parser replaces bytes that are not UTF-8 instead of failing, and drops over-long escape sequences instead of buffering them without bound.
batch() and watch() restore the
reactive graph after an interrupt; an interrupted handler previously
left every watcher deferred.
render_html(trim = TRUE) trims only the end of each
row (inner spaces were removed, shifting columns); SVG output preserves
runs of spaces.
Large trees no longer trigger the “too many events in one tick” warning at start-up; the guard counts events added during a tick.
db_explorer(): the object filter is case-insensitive
as documented, and expanding a group after the connection closed no
longer errors.
db_explorer() with lazy DBI metadata browsing,
SQLite table/view browsing and lazy table previews, integrated SQL
execution and result tables, details, status, and in-memory query
history.db_metadata() as a small portable metadata
interface. DBI and RSQLite remain optional dependencies; SQL query
results are materialized and generic DBI query execution is
synchronous.table_source() protocol and lazy
SQLite table source, with viewport-driven pages, delegated
sorting/filtering, bounded caching and source lifecycle methods.sql_highlighter() and the
sql_editor() text-area subclass with selection-aware
synchronous query or execute mode and SQL result events.db_connection() wrapper
and the sql-workspace example. DBI and RSQLite are
suggested dependencies only.The package was renamed from retui to termr during 0.3 development
(no compatibility aliases; options are termr.*, variables
TERMR_*).
app$last_paint reports repainted cells, rectangles and ANSI
bytes.invalidate_paint(),
paint_states).tools/bench/bench.R,
compare.R) measuring batches of ticks and the repainted
area; see docs/performance.md.text_area(): multi-line editor with selection,
undo/redo, find, wrapping, line numbers, mouse and paste.split_pane() with a draggable / keyboard-movable
divider.markdown_view(): headings, lists, quotes, code, tables
and links.process_view(): a program’s output with status, cancel
and restart.command() model shared
with the command palette (categories, shortcuts, enabled state).button(on_press = ); label(),
button(), progress_bar(),
metric(), sparkline() and
key_value() accept reactive functions.data_table() 2.0: resizable (mouse and keyboard),
hideable and frozen columns, multi-column sort with markers,
header_sort, search (Ctrl+F), goto_row(),
auto_size_column() that never scans huge tables, and
experimental cell editing on the table’s own copy
(editable, on_edit,
datatable.cell_changed). Numeric column headers are now
right-aligned.signal(), computed(),
watch(), batch(), peek(),
untracked(), dispose().terminal_capabilities()).PasteEvent, on_paste()),
system clipboard writes via OSC 52 (app$clipboard_write(),
write-only).drag.start/move/end) and capture
(widget$capture_mouse()).on_stdout
/ on_stderr, timeout, interrupt-then-kill
cancellation, shell-free run_process(). The worker progress
function is now termr_progress()."high-contrast" theme; monochrome rendering for
NO_COLOR (reverse video, bold/underline, heavier focus
border) so state never depends on colour alone.app(reduce_motion = ),
options(termr.reduce_motion),
TERMR_REDUCE_MOTION).test_app(color_mode = ); pilot methods
paste(), drag(), focus(),
find(), wait_for(), run_worker(),
system_clipboard().data-explorer, task-runner,
terminal-dashboard, editor,
accessibility-demo. New guides: text area, reactivity,
workers, terminal and accessibility, performance.retui_progress() is termr_progress().datatable Enter on an editable table edits instead of
sending datatable.row_activated; filter()
keeps an active sort.Ctrl+F, Ctrl+G, F1,
F3 and Alt+Left/Right are bound in tables; F1
is bound in every app.on_stdout).A large expansion from the 0.1.0 MVP towards a complete TUI framework, with a focus on data-oriented applications.
data_table(): virtualised, read-only data frame viewer
(millions of rows), row/cell/no cursor, row names, column()
options, formatters, zebra stripes, row_style /
cell_style hooks, horizontal and vertical scrolling,
sort() / filter() views, mouse support and
datatable.* messages.browse_data() / data_browser(): an
interactive data frame browser (metrics, search, sorting, column
summaries, row details).metric(), key_value(),
sparkline(), progress_bar(),
log_view().scroll_view() with scroll bars, keyboard and wheel
scrolling, and scroll-into-view on focus changes.tree_view() / tree_node() with lazy
loading.tabs() / tab().checkbox(), radio_set() /
radio_button(), dropdown(),
option_list(), spinner(), rule(),
panel() (with border titles).input(): selection, word movement and deletion, app
clipboard (app$clipboard), validate = with
input.valid / input.invalid and the
:invalid state.label(wrap = ) /
style(wrap = "word" | "char"): text wrapping by display
width; "auto" heights follow wrapped text.grid_layout() with fixed/auto/fr/percent tracks, gaps
and spans.app$push_screen(),
pop_screen(), switch_screen() with focus
restore and screen.show / screen.hide
events.modal(),
confirm_dialog(), alert_dialog().app$notify().app$add_command().:hover), focus on
click, and pilot$click() / hover() /
scroll() for tests.app$run_worker(), run_worker(),
termr_progress(), worker.* events.animate() / widget$animate()
with easings.inspect_widget(),
app$log_events(), F12 debug overlay
(app(debug = TRUE)).stylesheet(),
stylesheet_file(), app(stylesheet = ) with
specificity, source order and pseudo classes (:focus,
:hover, :disabled, :pressed,
:invalid). Errors report line, column and property.termr_theme() and app(theme = )
with default, dark and light;
colours can refer to the theme ("$primary").style(hover = ), grid properties,
options(termr.ascii = TRUE).Ctrl+A in inputs now selects all (Home still moves to
the start).on() selectors match the target of key and mouse
events.tools/pty/pty-check.py).tools/bench/bench.R rendering benchmarks.label(), button(),
input(), vertical(),
horizontal()), layout, reactive state, events and bindings,
focus, timers, framebuffer diff renderer, Windows/Unix/headless drivers
and test_app().