fluffos/docs
Yucong Sun 5f7be1008f
Char-mode input: deliver real keystrokes (BS/DEL, whole UTF-8, raw ESC); fix NAWS lost at logon (#1245)
* Char-mode input: deliver real keystrokes (BS/DEL, whole UTF-8, raw ESC); fix NAWS lost at logon

Five input-path fixes that make raw-keystroke (get_char) applications
viable, found by building the LPC TUI library on top of them:

- comm.cc: char mode delivered "" for Backspace/Delete (the byte was
  zeroed before delivery, making BS/DEL/NUL indistinguishable). The
  literal byte is now delivered; line-mode in-buffer editing unchanged.
- comm.cc: char mode delivered one *byte* per callback, splitting a
  multi-byte UTF-8 character into 2-4 invalid one-byte strings.
  Extraction is now UTF-8 aware: a complete sequence arrives as one
  callback carrying one valid character; malformed bytes still go
  byte-at-a-time (no stalls).
- comm.cc: the "no ansi" + "strip before process input" ESC->space
  rewrite (both default on) also applied to char mode, so arrow keys
  arrived as literal "[A". The rewrite is an anti-ANSI-injection
  protection for line-mode commands; char mode now always passes ESC
  through.
- net/telnet.cc: each received chunk was u8_sanitize()d independently,
  so a UTF-8 character split across TCP segments became U+FFFD in any
  input mode. An incomplete trailing sequence (new u8_incomplete_tail(),
  GTest-covered) is now carried over in interactive_t and prepended to
  the next chunk.
- net/telnet.cc + comm.cc: fast clients answer the initial DO NAWS
  while ip->ob is still the master object, so the window_size apply
  fired on the wrong object and the size was lost until the next
  resize. The last report is cached and replayed on the user object at
  logon.

docs/efun/interactive/get_char.md documents the delivery contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RpXv4yGCWpkzbkifyZy9EE

* Add /std/tui: an LPC TUI library (readline + ncurses for the prompt line and full-screen apps)

A terminal-UI toolkit in pure LPC, strictly layered (design + rationale
in testsuite/std/tui/DESIGN.md; user docs in docs/concepts/general/tui.md):

- ansi.lpc: escape builders plus the width toolkit the driver lacks
  (visible_width/wslice/wpad are ANSI-blind and wide-char aware).
- keys.lpc: keystroke decoder state machine: the get_char byte stream ->
  key events (CSI/SS3 with xterm modifiers, Alt prefixes, bracketed
  paste as one event, SGR mouse, UTF-8, lone-ESC via caller-driven
  flush()).
- readline.lpc: the line editor: emacs keymap (motion/kill/yank/
  transpose), Up/Down history, C-r/C-s incremental search, Tab
  completion, masked mode, horizontal scrolling with wide-char aware
  viewport; repaints only its own line so it works at any scroll
  position.
- screen.lpc: virtual cell grid + minimal-diff frame renderer with
  copy-on-write rows (frame cost tracks touched rows, not W x H);
  wide chars own two cells, boxes/fills/attrs as SGR param strings.
- widget.lpc + w/ (label, list, textfield) + app.lpc: widget protocol,
  focus cycling, event routing; textfield embeds a readline engine.
- terminal.lpc: the one impure module, inherited by the user object:
  get_char re-arm loop (I_NOECHO across re-arms), NAWS/TTYPE caching
  via the window_size/terminal_type applies, lone-ESC walltime timeout,
  guaranteed teardown. tui_readline() is a drop-in input_to()
  replacement; tui_open() runs full-screen apps on the alt screen.

Everything below terminal.lpc is a pure state machine: 194 checks in
single/tests/std/tui/ cover the decoder, editor sessions, history
search, screen diffing and widgets headlessly. `tuidemo` /
`tuidemo app` (command/tuidemo.lpc) demo both modes over any telnet
client; the whole stack was verified end-to-end over a live connection
including split-packet UTF-8, modifier keys, paste, resize and
alternate-screen teardown.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RpXv4yGCWpkzbkifyZy9EE

* /std/tui v2: pterm/blessed-inspired widgets, inline printers and prompts, showcases

Reviewed the pterm (Go) and blessed widget catalogs and ported what earns
its keep in a MUD; DESIGN.md is renamed to README.md and documents the
full set (including what was deliberately not ported).

New layers:
- print.lpc — pterm-style printers that compose with plain write():
  p_table (boxed, width-aware, header rule), p_tree, p_bars, p_spark,
  p_panel, p_bullets, p_header, p_progress, p_info/success/warn/error,
  and p_bigtext via the existing /std/bitmap_font.
- menu.lpc + terminal glue — inline interactive prompts in the normal
  output flow: tui_select(), tui_multiselect() (Space toggles, list
  windows by height, collapses to a "? prompt: answer" line) and
  tui_confirm() (y/n with a default).

New widgets (/std/tui/w/): table (columns + header + selection), tree
(collapsible, arrows fold), checklist, radiolist, button, progress,
spinner (app-driven tick()), and log (bottom-anchored scrollback pane).

Showcases (command/tuidemo.lpc): `tuidemo select` (prompt chain),
`tuidemo print` (all printers), `tuidemo dashboard` (animated spinner,
progress bars, sparkline, live table and log on a call_out tick), and
`tuidemo form` (textfield, radio group, checkboxes, buttons).

Coverage: three new test files (print exact-output, menu sessions,
widgets2) bring /std/tui to 8 files in the suite; the live-connection
e2e run now drives all six showcases end-to-end (52 checks), including
the select->multiselect->confirm chain, unattended dashboard animation,
and full form entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RpXv4yGCWpkzbkifyZy9EE

* /std/tui: charts — braille canvas, line charts, vertical bars, heatmap

Fills the chart gap left by v2 (only the horizontal p_bars existed):

- canvas.lpc: a braille dot canvas (each cell is a 2x4 dot grid from the
  U+2800 block — the blessed-contrib/drawille technique), giving sub-cell
  resolution: c_set/c_unset/c_get, Bresenham c_line, and c_plot (scale a
  value series across the canvas), with per-cell colour. Renders as a
  string, per-row strings, or per-cell ({ ch, attr }) pairs for blitting
  into a screen.
- print.lpc: p_chart (multi-series braille line chart with y-axis gutter
  and coloured legend), p_vbars (vertical bar chart with eighth-block
  partial tops and optional value row), p_heatmap (2D matrix as
  256-colour cells, cool-to-hot ramp, optional axis labels).
- w/chart.lpc: the live line-chart widget — add_series()/add_point()
  rolling history sized to the widget, auto or fixed y-range; replaces
  the dashboard's sparkline label with a real animating graph.
- `tuidemo charts` showcase; chart docs in README.md and the docs page
  (heatmap removed from the not-ported list).

Tests: single/tests/std/tui/charts.lpc pins the braille bit math with
exact glyphs, line drawing, plot endpoints, exact p_vbars output,
chart/heatmap structure, and the widget's rolling window. The live e2e
run verifies `tuidemo charts` output and braille frames streaming from
the dashboard chart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RpXv4yGCWpkzbkifyZy9EE

* docs: move the TUI page from Concepts to STDLIB

/std/tui is a mudlib library like base64/break_string/json, so its page
belongs under docs/stdlib/ with the rest of the /std modules, not under
Concepts. Registered in stdlib/index.md; README file-layout pointer
updated. (Concepts' sidebar is autogenerated, so the old entry disappears
with the file.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RpXv4yGCWpkzbkifyZy9EE

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-11 15:00:36 -04:00
..
apply Add inherit_program / include_file master applies; auto hot-reload demo (#1230) 2026-07-10 10:27:27 -04:00
archive Move to /docs folder 2018-12-30 17:03:14 -08:00
cli Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
concepts Add recompile_object() efun: in-place program update, state preserved (#1237) 2026-07-11 11:24:30 -04:00
driver Preserve this_player() in resolve() and async_* callbacks (#1104) 2026-07-11 14:56:46 -04:00
efun Char-mode input: deliver real keystrokes (BS/DEL, whole UTF-8, raw ESC); fix NAWS lost at logon (#1245) 2026-07-11 15:00:36 -04:00
lpc lexer: strip comments from directive payloads before parsing (#1240) (#1241) 2026-07-11 12:15:19 -04:00
src/css setup vitepress 2023-12-02 20:00:33 -08:00
static Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
stdlib Char-mode input: deliver real keystrokes (BS/DEL, whole UTF-8, raw ESC); fix NAWS lost at logon (#1245) 2026-07-11 15:00:36 -04:00
zh-CN dwlib: make the package buildable again (opt-in) 2026-07-10 10:26:58 -04:00
.gitignore Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
add_missing_efuns.py Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
bug.md Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
build-wasm.md wasm: shrink the driver to ~0.8MB over the wire (33.5MB -> 3.5MB raw) (#1243) 2026-07-11 13:12:44 -04:00
build.md build: add pkg-config and libffi to dependency lists (#1235) 2026-07-10 23:26:25 -04:00
build_v2017.md Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
CLAUDE.md Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
docusaurus.config.ts Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
gen_config_docs.py package_ffi: foreign function interface for LPC (libffi), with callbacks 2026-07-09 20:48:48 -04:00
gen_index.py Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
index.md Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
package-lock.json Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
package.json Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
README.md Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00
sidebars.ts wasm: run the full driver in the browser (Emscripten port) (#1231) 2026-07-10 23:33:51 -04:00
update_index.sh Add local search and documentation guide for docs site (#1221) 2026-07-09 22:09:55 -04:00

FluffOS Documentation

This directory contains the source for the FluffOS documentation site, published at https://www.fluffos.info.

The site is built with Docusaurus 3 (@docusaurus/preset-classic). Markdown files live directly in this directory (the docs plugin is configured with path: '.' and routeBasePath: '/'), so docs/efun/strings/explode.md becomes /efun/strings/explode on the site.

This README is for contributors and is excluded from the published site (see exclude in docusaurus.config.ts).

Local Development

Requires Node.js 18+ (Node 22 recommended).

cd docs
npm install
npm run dev       # dev server on http://localhost:3000

Other scripts:

npm run build     # production build → docs/build/
npm run preview   # serve the production build locally
npm run clear     # clear the Docusaurus cache

Full-text search is provided by @easyops-cn/docusaurus-search-local, an offline/local search theme — the index is generated at build time and shipped with the site, so no external search service (e.g. Algolia) is needed.

Notes:

  • The search index is only generated by npm run build. In the dev server (npm run dev) the search bar shows a hint instead of results; use npm run build && npm run preview to test search locally.
  • Both English and Chinese (zh-CN/) pages are indexed (language: ['en', 'zh']).
  • Search options live in the themes section of docusaurus.config.ts.

Layout

Path Contents
docusaurus.config.ts Site config: navbar, footer, docs plugin, search theme
sidebars.ts Sidebar navigation tree (Docusaurus SidebarsConfig format)
src/css/custom.css Infima CSS variable overrides
static/ Files copied verbatim to the site root (CNAME, Google site verification)
apply/ Driver-to-LPC callback (apply) reference
efun/ Built-in function (efun) reference, by category
stdlib/ LPC standard-library reference
driver/ Driver internals & configuration
lpc/ LPC language reference
concepts/ High-level LPC / MUD concepts
cli/ Command-line tool docs
zh-CN/ Chinese documentation
archive/ Historical MudOS-era documents (not published)

Maintenance scripts

Script Purpose
update_index.sh Regenerates all generated index.md listing pages (calls gen_index.py)
gen_index.py Writes an index.md for one doc tree (e.g. ./gen_index.py efun EFUN)
gen_config_docs.py Regenerates driver/config.md from src/base/internal/rc.cc
add_missing_efuns.py Creates stub pages under efun/general/ for undocumented efuns (needs a keywords.json from the generate_keywords tool)

Conventions & Gotchas

  • driver/config.md is auto-generated from src/base/internal/rc.cc — never edit it by hand. Regenerate with python3 docs/gen_config_docs.py; CI fails if it is stale.
  • .md files are treated as standard CommonMark (markdown.format: 'detect'), but bare {...} in prose is still parsed as a JSX expression and breaks the build — escape it as \{...\} outside fenced code blocks.
  • Sidebar entries in sidebars.ts use doc IDs (relative path without extension), not URLs.
  • Generated index.md listing pages (efun/apply/stdlib/cli/concepts/driver/zh-CN) are rewritten by ./update_index.sh — regenerate rather than hand-edit them. lpc/index.md is hand-written and deliberately not regenerated.
  • onBrokenLinks is set to 'throw': a broken internal link fails the build (and the Pages deploy) instead of shipping a 404.

See CLAUDE.md for detailed documentation templates (applies, efuns, CLI tools) and the full contribution workflow.