survos / tui-extras-bundle
Extra TUI widgets and data source abstractions for symfony/tui
Package info
github.com/survos/tui-extras-bundle
Type:symfony-bundle
pkg:composer/survos/tui-extras-bundle
Fund package maintenance!
Requires
- php: ^8.5
- league/commonmark: ^2.0
- survos/kit-bundle: ^2.8
- symfony/console: ^8.1
- symfony/finder: ^8.1
- symfony/tui: ^8.1
- tempest/highlight: ^2.0
Suggests
- doctrine/dbal: For DoctrineTableSource
- survos/field-bundle: For FieldDescriptor-based column definitions via TuiColumn::fromFieldDescriptor()
This package is auto-updated.
Last update: 2026-08-20 16:47:39 UTC
README
Extra TUI widgets and data-source abstractions for symfony/tui — the terminal UI component shipping in Symfony 8.1.
Status: 0.1 — beta. Tracks
symfony/tui ^8.1which is itself experimental. Widgets are usable and the file browser works end-to-end. APIs may shift before 1.0.
What's in the box
Widgets
| Widget | What it does |
|---|---|
DataTableWidget |
Paged, searchable, sortable data table. Live search, FTS5-aware. |
TreeWidget |
Collapsible tree — ▼/► branches, ── leaves. Keyboard navigate. |
DetailPanelWidget |
Read-only text/code pane with title and separator. |
All bundled browsers opt into mouse reporting. The scroll wheel moves through
the focused TreeWidget or DataTableWidget; keyboard navigation remains
available. Mouse mode is disabled in a finally block when the TUI exits so
normal terminal scrollback and text selection are restored.
Applications can enable the same behavior for custom widgets by implementing
MouseAwareInterface and running the TUI through MouseInput:
$tui = new Tui(); $tui->add($mouseAwareWidget); $tui->setFocus($mouseAwareWidget); (new MouseInput())->run($tui);
Data sources (TuiTableSourceInterface)
| Source | Backed by |
|---|---|
ArrayTableSource |
Plain PHP array, in-memory filter/sort |
SqliteTableSource |
PDO + SQLite with optional FTS5 full-text search |
FileSource |
Symfony Finder — respects .gitignore by default |
Syntax highlighting (SyntaxHighlighter)
- Uses
bat/batcatif installed (200+ languages, themes) - PHP fallback via
token_get_all()— zero extra deps - JSON fallback via stdlib pretty-print + hand-rolled tokenizer
- Markdown via
MarkdownWidget(league/commonmark + tempest/highlight)
Requirements
- PHP 8.1+
symfony/tui ^8.1(currently8.1.x-dev)league/commonmark ^2.0(for Markdown rendering)tempest/highlight ^2.0(for code blocks within Markdown)
Installation
composer require survos/tui-extras-bundle
Register in your config/bundles.php (or let Flex do it):
Survos\TuiExtrasBundle\SurvosTuiExtrasBundle::class => ['all' => true],
HTTP-less apps (
AbstractKernel+KernelTrait+ConsoleBundle, noFrameworkBundle): the bundle works without an HTTP kernel. See thedemo/directory for a minimal setup.
The file browser
The fastest way to see the bundle in action:
cd demo/ composer install php bin/console browse:files # tree of current directory php bin/console browse:files ../src # browse the bundle source php bin/console browse:files . --pre-expand=2 # open 2 levels on start php bin/console browse:files . --raw # no syntax highlighting php bin/console browse:files . --no-gitignore # include ignored files
▼ src/
── ► Event/
▼ Highlighter/
──── SyntaxHighlighter.php
▼ Model/
──── TreeNode.php
──── TuiColumn.php
▼ Widget/
──── DataTableWidget.php │ <?php
──── DetailPanelWidget.php │
──── TreeWidget.php │ declare(strict_types=1);
▼ Source/ │
──── ArrayTableSource.php │ namespace Survos\TuiExtrasBundle\Highlighter;
──── FileSource.php │
──── SqliteTableSource.php │ /**
│ * Syntax highlighter that emits ANSI-colored
│ * lines compatible with DetailPanelWidget.
Keybindings:
| Key | Action |
|---|---|
↑ / ↓ / j / k |
Navigate |
→ |
Expand directory |
← |
Collapse (or jump to parent) |
Enter / Space |
Toggle directory / preview file |
q / ctrl+c |
Quit |
Preview updates instantly as you navigate — no Enter required for files. PHP and JSON files are syntax-highlighted. Markdown files render with full formatting.
FTS5 full-text search demo
php bin/console browse:functions # ~1300 PHP internal functions, SQLite FTS5
Type / then str_ to filter to all string functions instantly. Uses an in-memory
SQLite database with an FTS5 virtual table — the same pattern FolioRowTableSource
uses in survos/folio-bundle.
Building a split-pane browser
use Survos\TuiExtrasBundle\Model\TreeNode; use Survos\TuiExtrasBundle\Widget\DetailPanelWidget; use Survos\TuiExtrasBundle\Widget\TreeWidget; use Symfony\Component\Tui\Style\Direction; use Symfony\Component\Tui\Style\Style; use Symfony\Component\Tui\Style\StyleSheet; use Symfony\Component\Tui\Tui; use Symfony\Component\Tui\Widget\ContainerWidget; $tree = new TreeWidget(); $tree->addRoot(TreeNode::branch('src/', null, true) ->addChild(TreeNode::leaf('Kernel.php', 'src/Kernel.php')) ->addChild(TreeNode::branch('Command/') ->addChild(TreeNode::leaf('MyCommand.php', 'src/Command/MyCommand.php')) ) ); $detail = new DetailPanelWidget(); $tree->onCursorChange(fn($e) => $detail->setContent( file_get_contents($e->node->data ?? ''), (string) $e->node->data, )); $split = (new ContainerWidget())->setStyle(new Style(direction: Direction::Horizontal, gap: 1)); $split->add($tree->setStyle(new Style(maxColumns: 40))); $split->add($detail); $tui = new Tui(new StyleSheet()); $tui->add($split); $tui->setFocus($tree); $tui->run();
Building a DataTable with SQLite FTS5
use Survos\TuiExtrasBundle\Model\TuiColumn; use Survos\TuiExtrasBundle\Source\SqliteTableSource; use Survos\TuiExtrasBundle\Widget\DataTableWidget; $pdo = new \PDO('sqlite:/path/to/data.sqlite'); // FTS5 virtual table: CREATE VIRTUAL TABLE fts_items USING fts5(name, description, content=items, content_rowid=id) $source = new SqliteTableSource( pdo: $pdo, table: 'items', ftsTable: 'fts_items', columns: [ new TuiColumn(key: 'name', label: 'Name', sortable: true, searchable: true), new TuiColumn(key: 'description', label: 'Description', searchable: true), new TuiColumn(key: 'created_at', label: 'Created', width: 12, format: 'date', sortable: true), ], ); $table = new DataTableWidget($source); // Press / to search with FTS5, ↑↓ navigate, s sort, q quit
TuiTableSourceInterface
Implement this to make any data source browsable:
interface TuiTableSourceInterface { /** @return TuiColumn[] */ public function columns(): array; public function count(?string $search = null): int; /** @return iterable<array<string,mixed>> */ public function rows(int $offset = 0, int $limit = 25, ?string $search = null, ?string $sortBy = null, string $sortDir = 'ASC'): iterable; }
Built-in implementations: ArrayTableSource, SqliteTableSource, FileSource.
Adapters in other bundles: FolioRowTableSource (survos/folio-bundle), JsonlTableSource (survos/jsonl-bundle, planned).
Roadmap
-
browse:commands—vendor/bin/browsecommand browser (tree of namespaces + full--helpin detail pane) -
FolioRowTableSource— FTS5-backed browser for survos/folio-bundle -
MeilisearchTableSource+browse:meili— live Meilisearch browser - Generic SQLite schema browser (squall-style: table tree + row DataTable)
- PHAR packaging via humbug/box (
vendor/bin/browse)
License
MIT