Adds test/terminal/core/core_test.dart — 36 unit tests across the small standalone files that sit directly under `lib/src/terminal/src/core/*.dart`: - CellData (constructor + empty + getHash + toString), - CursorStyle (default ctor, every set/unset attr getter pair, all three colour-mode setters per channel, reset, the .empty singleton) + CursorPosition, - Charset (translate, designate/use, save/restore, asciiTranslator, decSpecGraphicsTranslator with in-table, out-of-table, and high- codepoint paths), - TabStops (default 8-column grid, find with empty-range / out-of- bounds / no-stop-in-range cases, setAt/clearAt/clearAll/reset), - reflow (empty input, single-line passthrough, grow, shrink-with- split, wrapped-run continuation, wide-char boundary on the new width, inner wide-char clamp during _addPart, anchor reparent on the main path, anchor reparent past trimmedLength). Two source-side cleanups folded in: - `CursorStyle.isItalis` was a defined-but-never-called getter with a typo. No external callers reference it; renamed to `isItalic` in the same change as the test that exercises it. - `_LineBuilder.isEmpty` in reflow.dart was dead — the only callers use `isNotEmpty` or check `_lines.isNotEmpty` separately. Removed. Coverage delta: - cell.dart: 3/7 → 7/7. - charset.dart: 12/25 → 25/25. - cursor.dart: 2/62 → 62/62. - tabs.dart: 0/23 → 23/23. - reflow.dart: 24/72 → 71/71 (file shrank by one line after the isEmpty getter removal). - Total project: 52.72% → 54.62%; coverage_floor bumped 52 → 54. Note for follow-up (not blocking): the post-loop "anchor.x >= to" branch in reflow's `_addPart` reparents anchors past trimmedLength onto whatever builder line is active at that moment. If no subsequent content is added (no wrapped continuations after the last shrink iteration), that builder line is never emitted by `finish()` and the anchor lands on a dangling reference. The path is exercised by the new test, but the contract it implements is arguably broken — anchors that should follow the source content end up off the visible buffer. Worth a separate ticket if real terminals trip it. Co-Authored-By: Claude <noreply@anthropic.com>
clide
An IDE for Claude Code CLI. Native rendering, terminal-first interaction, pql-powered queries, canvas and graph surfaces. Linux and macOS.
Architecture
Single Flutter package at the repo root. The app hosts everything in-process: IPC server, subsystem handlers (pane, files, editor, git, pql), and the extension framework. tmux owns Claude session persistence.
lib/— all Dart code. Kernel services (theme, i18n, settings, panels, commands, focus), UI widgets, built-in extensions, and the extension contract.ptyc/— small C helper. Spawns a PTY + child and hands the master fd back overSCM_RIGHTS. Every pane (shell, tmux, claude, LSP, debug adapter) goes through it.- pql — external supporter tool. Clide wraps it for every query surface; never re-implements it.
Claude drives the UI through a clide CLI surface (Bash, not MCP). Every CLI subcommand has a UI affordance and every UI action has a CLI equivalent.
Built-in extensions
canvas, claude, claude_control, decisions, diff, editor, extensions_ui, files, git, graph, grammars_core, ipc_status, keybindings_ui, markdown, pql, problems, settings_ui, terminal, theme_picker, tickets, todos, welcome.
Building
Requires Flutter (stable channel) on the host. One-time setup:
make hooks && flutter pub get
Then:
make run # launch the desktop app
make test # fast suite: analyze + format + unit + widget + golden
make test-core # core subsystem tests (IPC, PTY, git, pane registry)
make test-integration # real app boot integration tests
make build-linux # flutter build linux
make build-macos # flutter build macos
make ptyc-build # build the ptyc PTY-spawn helper
make push-check # pre-push gate: decisions + core + fast tests
Status
Pre-v2.0 (2.0.0-dev). Interaction model and panel system landed. The Python Textual v1.2.0 predecessor is archived under legacy/.
Design doc: docs/initial-plan.md. Architectural decisions: decisions/.
License
MIT. See LICENSE.