Skip to main content

Crate noctiluca

Crate noctiluca 

Source
Expand description

Noctiluca, a terminal web browser on intuiTUIve.

Chrome loads and runs the page. Noctiluca reads what Chrome laid out (one DOMSnapshot.captureSnapshot and the accessibility tree, which the page cannot observe) and draws it in cells: text as terminal text, controls as intuiTUIve widgets, images as media regions. This crate is the noctiluca binary and the library it is built from.

The user guide is on the docs site: Noctiluca, with pages on getting started, keys, configuration, privacy and security and using it as a library. The design and its phases are in docs/design/browser.md.

§The pieces

  • engine: the Engine trait, what Noctiluca needs from a browser, and cdp its Chrome backend over rs-rich-embed (ChromeBackend).
  • tab: a Tab runs an engine on a thread of its own: loading, the debounced change ping, live logs read incrementally, guarded actions, stills and pictures. It sends Updates.
  • model: the Page model, rebuilt from each snapshot: blocks of text, controls and media.
  • layout: the page as lines of cells, in reader mode or the projection; adapt its terminal adaptations, named generic rules that can each be switched off; pictures draws pictures and moving GIFs over their regions. widgets gives controls their intuiTUIve widgets.
  • app: the browser as an intuiTUIve app; actions is the one list of what it can do, with the keys of both presets; pixel_view is the page in Chrome’s own pixels, sent as tiles where they change (#818).
  • control: the control socket’s verbs and the noctiluca ls and noctiluca action client, for scripts and coding agents (#816).
  • config, bookmarks, args, dump (--dump) and url: the rest of the binary, usable on their own.
  • testing: FakeEngine, an engine over saved snapshots, for tests with no browser.

Everything the page says is untrusted: control characters are stripped (clean()) before any of it reaches the terminal.

§Examples

The address bar’s rules, from a config:

use noctiluca::config::{Config, Destination};

let config = Config::parse(
    r#"
[shortcuts]
wiki = "https://en.wikipedia.org/w/index.php?search={}"
"#,
)
.unwrap();
assert!(config.warnings.is_empty());
assert_eq!(
    config.destination("wiki sea sparkle", "about:blank", &[]),
    Destination::Keyword("https://en.wikipedia.org/w/index.php?search=sea+sparkle".into())
);
assert_eq!(
    config.destination("docs.rs/serde", "about:blank", &[]),
    Destination::Url("https://docs.rs/serde".into())
);

A page read once through an engine, as --dump does. Here the engine is FakeEngine, over the snapshots of the crate’s test pages, so no browser runs:

use std::path::Path;
use std::time::Duration;

use noctiluca::testing::FakeEngine;

let snapshots = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/snapshots");
let engine = FakeEngine::from_dir(&snapshots)?;
let page = noctiluca::dump::read_page(
    Box::new(engine),
    "https://fixture.example/second.html",
    Duration::from_secs(10),
)?;
assert_eq!(page.title, "Second page");
assert!(page.text().contains("You followed the link."));
let link = page.find("link", "Back to the start");
assert_eq!(link.len(), 1);

The same with Chrome (it needs a Chrome or Chromium, and a normal user):

use std::time::Duration;

use noctiluca::cdp::{ChromeBackend, ChromeOptions};

let engine = ChromeBackend::start(ChromeOptions {
    columns: 100,
    rows: 40,
    ..ChromeOptions::default()
})?;
let page = noctiluca::dump::read_page(
    Box::new(engine),
    "https://example.com",
    Duration::from_secs(60),
)?;
println!("{}", page.text());

Re-exports§

pub use clean::clean;
pub use url::file_url;

Modules§

about
about:noctiluca: what this browser is, how it adapts pages to the terminal, and what it can play.
actions
The action registry: one list of what Noctiluca can do. The keys, the link hints, site keys and the F1 overlay all run actions from it, and each checks the action is available when it runs.
adapt
Terminal adaptations: named, generic rules about constructs and cells, applied to every page alike (docs/design/browser.md, “Terminal adaptations”). None of them knows a site: each reads only what the model has from the snapshot and the accessibility tree.
app
The browser as an intuiTUIve app: the address line, the page (the projection by default, reader mode one key away), the status line, and the action registry’s keys, hints, find, F1 overlay and site keys.
args
noctiluca’s command line, in the hand-written style of rs-rich-cli’s commands (fn parse_args(&[String]) -> Result<…, String>).
bars
The header and the status bar, as the PoC drew them:
bookmarks
Bookmarks, in a file of Noctiluca’s own (decision 4): bookmarks.toml in its data directory, written only when the user adds or removes one. Each is a [[bookmark]] with a url, a title and an optional keyword, which the address bar expands like a shortcut’s.
cdp
ChromeBackend: the Engine over rs-rich-embed’s ChromeEngine, speaking the DevTools protocol through DevTools::call and DevTools::listen.
clean
Page text made safe for a terminal. Everything a page says is untrusted: its text, title, addresses, alt text, option labels and download names all pass through here before any of it is drawn.
config
Noctiluca’s configuration: noctiluca/config.toml in the platform config directory, or the file --config names. A documented sample is config.sample.toml beside this crate’s manifest.
control
Agent control (#816): scripts and coding agents of the same user drive a running Noctiluca through its control socket, and read the page as the projection’s text, far fewer tokens than a screenshot.
draft
DraftField: a value edited here while the page holds the real one, with a guarded commit and a conflict check. C5 of the design note: it stays in Noctiluca until a second user needs it. A port of the proof of concept’s primitives/draft-field.js.
dump
noctiluca --dump: a page read once and printed, for scripts and CI. Every string in it comes from the model, so it is cleaned already.
engine
The engine trait: what Noctiluca needs from a browser, so the browser behind it can change (decision 1 of docs/design/browser.md). Its first backend is ChromeBackend, over rs-rich-embed’s ChromeEngine; tests use their own.
layout
The page as lines of cells, two ways:
model
The page model: one per tab, built from each PageSnapshot (a DOMSnapshot.captureSnapshot and an Accessibility.getFullAXTree).
pictures
Pictures in the views: each media region’s picture drawn over its cells, and animated pictures kept moving within a byte budget.
pixel_view
The pixel view (#818): the page as Chrome paints it, pixel for pixel, for terminals with Kitty graphics (--pixels, view = "pixels", or the view.pixels action). The projection stays the default: it works in every terminal, and a screen reader can read it.
ssh
--ssh HOST: Chrome runs on this machine and its network goes through HOST (#817). A dev server on the remote’s localhost then opens as if it were local, with no browser on the remote and no frames over SSH.
start
The start page: what Noctiluca shows when it starts with no address (and no home), while Chrome starts behind it.
tab
A tab: an Engine on a thread of its own, which keeps the page model up to date and runs actions with their guards.
testing
A scripted Engine for tests: pages from saved snapshots, actions recorded, and a hook to change the page when an action runs. No browser.
url
Addresses: local files as file:// URLs, links resolved against their page, queries escaped, and what the address bar means by what was typed.
video
Video in its region: frames of a playing <video>, cut from Chrome’s screencast, handed to the picture side to draw.
widgets
Web widgets: a page’s controls as stock intuiTUIve widgets.