{"id":47680679,"url":"https://github.com/mikeleppane/tursotui","last_synced_at":"2026-04-02T13:58:54.135Z","repository":{"id":346122108,"uuid":"1187298962","full_name":"mikeleppane/tursotui","owner":"mikeleppane","description":"A keyboard-driven terminal UI for browsing, querying, and administering Turso and SQLite databases — built with Rust, ratatui, and vim-inspired navigation.","archived":false,"fork":false,"pushed_at":"2026-04-01T06:10:34.000Z","size":6510,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-01T08:54:29.292Z","etag":null,"topics":["cli","crossterm","database","ratatui","rust","sqlite","terminal","terminal-ui","tui","tui-app","turso","tursodb","vim"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikeleppane.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-20T15:08:48.000Z","updated_at":"2026-04-01T06:10:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mikeleppane/tursotui","commit_stats":null,"previous_names":["mikeleppane/tursotui"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/mikeleppane/tursotui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeleppane%2Ftursotui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeleppane%2Ftursotui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeleppane%2Ftursotui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeleppane%2Ftursotui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikeleppane","download_url":"https://codeload.github.com/mikeleppane/tursotui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeleppane%2Ftursotui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31307429,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","crossterm","database","ratatui","rust","sqlite","terminal","terminal-ui","tui","tui-app","turso","tursodb","vim"],"created_at":"2026-04-02T13:58:53.176Z","updated_at":"2026-04-02T13:58:54.128Z","avatar_url":"https://github.com/mikeleppane.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/logo.png\" alt=\"tursotui logo\" width=\"600\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  A keyboard-driven terminal UI for browsing, querying, and administering Turso and SQLite databases.\n  \u003cbr\u003e\n  Built with Rust, \u003ca href=\"https://ratatui.rs\"\u003eratatui\u003c/a\u003e, and vim-inspired navigation.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/mikeleppane/tursotui/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.rust-lang.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/rust-1.85%2B-orange.svg\" alt=\"Rust: 1.85+\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/mikeleppane/tursotui\"\u003e\u003cimg src=\"https://img.shields.io/badge/turso--first-SQLite--compatible-teal\" alt=\"Turso-first\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Table of Contents\n\n- [Demo](#demo)\n- [Screenshots](#screenshots)\n- [Features](#features)\n- [Turso Compatibility](#turso-compatibility)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Keybindings](#keybindings)\n- [Configuration](#configuration)\n- [Architecture](#architecture)\n- [Tech Stack](#tech-stack)\n- [License](#license)\n- [Acknowledgments](#acknowledgments)\n- [Contact](#contact)\n\n## Demo\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://youtu.be/bo3zhI8sRZY\"\u003e\n    \u003cimg src=\"https://img.youtube.com/vi/bo3zhI8sRZY/maxresdefault.jpg\" alt=\"tursotui demo video\" width=\"700\"\u003e\n  \u003c/a\u003e\n  \u003cbr\u003e\n  \u003cem\u003eClick the image to watch the demo on YouTube\u003c/em\u003e\n\u003c/p\u003e\n\n## Screenshots\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/screenshot1.png\" alt=\"Schema browser, SQL editor, and results table\" width=\"700\"\u003e\n  \u003cbr\u003e\n  \u003cem\u003eSchema browser with row counts, SQL editor with syntax highlighting, and sortable results table\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/screenshot2.png\" alt=\"DML Preview popup showing generated SQL statements\" width=\"700\"\u003e\n  \u003cbr\u003e\n  \u003cem\u003eDML Preview — review generated INSERT, UPDATE, and DELETE statements before committing\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/screenshot3.png\" alt=\"Bookmarks overlay with saved queries and SQL preview\" width=\"700\"\u003e\n  \u003cbr\u003e\n  \u003cem\u003eSaved Bookmarks — name, search, and recall frequently-used queries\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/screenshot4.png\" alt=\"ER Diagram with table relationships and FK edges\" width=\"700\"\u003e\n  \u003cbr\u003e\n  \u003cem\u003eER Diagram — visual entity-relationship view with FK edges, PK/FK markers, and cycle detection\u003c/em\u003e\n\u003c/p\u003e\n\n## Features\n\n**Multi-Database Tabs** — open multiple databases simultaneously with a tab bar. Switch between them with `Ctrl+PgDn`/`Ctrl+PgUp`, open new databases with `Ctrl+O` file picker, close with `Ctrl+W`. Each database has independent schema, editor, and results state.\n\n**Schema Browser** — color-coded tree view of tables, views, indexes, triggers, and columns with inline search filtering, async row counts, and DDL viewing. Each entity type has a distinct color for quick visual scanning.\n\n**SQL Editor** — syntax-highlighted editor with undo/redo, text selection, auto-save, active line highlighting, and statement-at-cursor execution. Supports parameterized queries with bound parameters.\n\n**Parameterized Queries** — when the editor detects SQL parameters (`?1`, `:name`, `$name`), a parameter bar appears below the editor. Tab between fields, type values, use `Ctrl+N` for NULL. Parameters are bound safely via the database driver — no string interpolation. Values persist across restarts and are logged in query history.\n\n**Schema-Aware Autocomplete** — context-sensitive completions for table names, columns, SQL keywords, and qualified references with alias resolution.\n\n**Results Table** — sortable, resizable columns with alternating row colors, cell/row clipboard copy, JSON pretty-printing, and configurable NULL display. Indexed columns are marked with a `·` indicator in the header for quick identification of indexed vs. non-indexed columns.\n\n**Index Awareness** — columns that are the leading key of a database index are marked with `·` in the results header. When filtering on a non-indexed column (via the `w` WHERE filter) on a table with \u003e1,000 rows, a brief hint warns that the query may be slow.\n\n**Inline Data Editor** — edit table data directly in the results view. Add, modify, and delete rows with full change tracking. Preview generated DML (INSERT/UPDATE/DELETE) before committing. Transactional submission with automatic rollback on failure.\n\n**Foreign Key Navigation** — follow FK references from any cell to the referenced row. Breadcrumb trail with back-navigation to retrace your path through related tables.\n\n**Record Detail** — vertical key-value view for inspecting a single row across all columns, with JSON syntax coloring for structured values.\n\n**ER Diagram** — visual entity-relationship diagram built from foreign key definitions. Grid layout with box-drawing borders, PK/FK markers, relationship edges, cycle detection with dashed lines, and adjustable spacing.\n\n**Go to Object** — fuzzy search across all open databases (`Ctrl+P`). Instantly navigate to any table, view, index, trigger, or column with ranked results.\n\n**Enhanced EXPLAIN View** — bytecode table and query plan tree, toggled with a single key. Query plan lines are color-coded by scan type (red for full table scans, yellow for temp B-trees, green for index seeks). Warnings section highlights performance issues and suggests CREATE INDEX statements based on WHERE/ORDER BY columns. Press Enter on a suggestion to send it to the editor, or `y` to copy to clipboard.\n\n**Data Profiling** — press `5` to open the Profile tab, then `Enter` to generate. Two-column layout: left shows columns with colored completeness indicators (`●` green = no nulls, `◐` yellow = \u003c50% nulls, `○` red = ≥50% nulls, `∅` dim = all null), right shows per-column statistics including null count, distinct count, uniqueness ratio, min/max, and for numeric columns: avg, sum, stddev (Turso). Text columns show length statistics. Top-5 value frequency with bar chart visualization (hidden for high-cardinality columns with \u003e50 distinct values). Automatic sampling for tables over 10,000 rows (configurable via `[profile] sample_threshold` in config). Profile auto-invalidates on DML operations — stale indicator (`*`) appears on the tab. Press `r` to refresh, `Ctrl+Up/Down` to scroll stats.\n\n**Schema Diffing** — press `F7` to compare schemas between two open databases. Visual diff overlay shows added (+), removed (-), modified (~), and identical (=) objects with color-coded status icons. Expand modified tables to see column-level diffs including type changes. Copy DDL or auto-generated migration SQL (ALTER TABLE for added columns, 12-step rebuild guidance for type changes) to clipboard. Toggle visibility of identical objects with `i`.\n\n**Slow Query Tracking** — execution time in the status bar is color-coded against a configurable threshold (`[performance] slow_query_ms` in config, default 500ms): yellow for slow, red for very slow. Query history overlay adds `s` to filter slow queries only and `S` to sort by execution time descending. Slow entries are marked with a `⏱` icon.\n\n**Export** — save results as CSV, JSON, or SQL INSERT statements to file or clipboard. Quick TSV copy with a shortcut.\n\n**Saved Bookmarks** — name and save frequently-used queries (`F3`). Database-scoped with search, rename, delete, and one-key recall or execute. Backed by SQLite for persistence across sessions.\n\n**Quick Table Filter** — press `w` on the results panel to type a WHERE clause and instantly filter table data without touching the editor. Two-phase dismiss (defocus then clear).\n\n**DDL Viewer** — press `Shift+D` on any schema object to view its full CREATE statement with syntax highlighting, scrolling, and clipboard copy.\n\n**Query History** — SQLite-backed per-database history with search, recall, re-execute, auto-prune, slow-query filtering, and execution time sorting.\n\n**Admin Tab** — database info (file stats, WAL status, journal mode), PRAGMA dashboard with inline editing, WAL checkpoint, and integrity checks.\n\n**Theming** — Catppuccin Mocha (dark) and Catppuccin Latte (light) themes with rounded borders, toggled at runtime.\n\n## Turso Compatibility\n\ntursotui is **Turso-first** — all features are tested and designed to work within Turso's compatibility surface. It also works with standard SQLite databases.\n\n**Turso-aware highlights:**\n\n- Schema introspection uses Turso-compatible PRAGMAs (`table_info`, `index_list`, etc.)\n- Foreign key metadata parsed from `CREATE TABLE` SQL (works around Turso's missing `PRAGMA foreign_key_list`)\n- Syntax highlighting and autocomplete include Turso-specific functions: UUID (`uuid4()`, `uuid7()`), vector search (`vector_distance_cos()`, `vector_top_k()`), FTS (`fts_match()`, `fts_score()`), time functions, regexp, and more\n- DB Info panel recognizes MVCC journal mode with Turso-specific labeling\n- Data editor uses `PRAGMA defer_foreign_keys` inside transactions for safe FK handling\n\n**Known Turso limitations** (not tursotui bugs — these are upstream gaps):\n\n- No `RIGHT JOIN`, `CROSS JOIN`, or ranking window functions (`ROW_NUMBER`, `RANK`, etc.)\n- No `SAVEPOINT`/`RELEASE`, `VACUUM`, `REINDEX`, `GENERATED` columns, or recursive CTEs\n- Views and Triggers are experimental features requiring enablement flags\n- FTS uses different syntax than SQLite FTS5 (`fts_match()` instead of `MATCH`)\n\nSee [COMPAT.md](https://github.com/tursodatabase/turso/blob/main/COMPAT.md) for the full Turso compatibility matrix.\n\n## Installation\n\n### From source\n\nRequires [Rust](https://rustup.rs/) (edition 2024, Rust 1.85+).\n\n```sh\ngit clone https://github.com/mikeleppane/tursotui.git\ncd tursotui\ncargo build --release\n```\n\nThe binary is at `target/release/tursotui`.\n\n## Usage\n\n```sh\n# Open a Turso/SQLite database file\ntursotui mydb.db\n\n# Open an in-memory database\ntursotui\n\n# Open multiple databases in tabs\ntursotui db1.db db2.db\n```\n\n## Keybindings\n\n### Global\n\n| Key | Action |\n|-----|--------|\n| `Ctrl+Q` | Quit |\n| `Ctrl+Tab` | Cycle focus between panels |\n| `Ctrl+B` | Toggle schema sidebar |\n| `Alt+1` / `Alt+2` | Switch Query / Admin tab |\n| `Ctrl+T` | Toggle dark/light theme |\n| `F1` / `?` | Help overlay |\n| `Ctrl+O` | Open database file |\n| `Ctrl+P` | Go to Object (fuzzy search) |\n| `Ctrl+PgDn` / `Ctrl+PgUp` | Next / previous database tab |\n| `Ctrl+W` | Close current database tab |\n| `Ctrl+Left` / `Ctrl+Right` | Resize sidebar (narrower / wider) |\n| `Ctrl+Up` / `Ctrl+Down` | Resize editor (shorter / taller) |\n| `F3` | Bookmarks overlay |\n| `Ctrl+Shift+E` | Export results |\n| `Ctrl+Shift+C` | Quick copy results (TSV) |\n\n### Query Editor\n\n| Key | Action |\n|-----|--------|\n| `F5` / `Ctrl+Enter` | Execute query |\n| `Ctrl+Shift+Enter` | Execute selection or statement at cursor |\n| `Ctrl+Space` | Trigger autocomplete |\n| `Tab` | Accept completion |\n| `Ctrl+Z` / `Ctrl+Y` | Undo / Redo |\n| `Ctrl+L` | Clear buffer |\n| `Ctrl+H` | Query history |\n| `Shift+Arrow` | Extend selection |\n| `Ctrl+Shift+A` | Select all |\n\n### Schema Explorer\n\n| Key | Action |\n|-----|--------|\n| `j` / `k` | Navigate up/down |\n| `Enter` / `Space` / `l` | Expand / collapse |\n| `h` | Collapse / go to parent |\n| `o` | Query table (`SELECT *`) |\n| `Shift+D` | View DDL (CREATE statement) |\n| `/` | Filter by name |\n\n### Results Table\n\n| Key | Action |\n|-----|--------|\n| `j` / `k` | Navigate rows |\n| `h` / `l` | Navigate columns |\n| `g` / `G` | First / last row |\n| `s` | Cycle sort on column |\n| `\u003c` / `\u003e` | Shrink / grow column |\n| `w` | WHERE filter bar |\n| `y` | Copy cell |\n| `Y` | Copy row |\n\n### Data Editor (when results are editable)\n\n| Key | Action |\n|-----|--------|\n| `e` / `F2` | Edit current cell |\n| `Enter` | Confirm cell edit |\n| `Esc` | Cancel cell edit |\n| `Ctrl+N` | Set cell to NULL |\n| `Ctrl+Enter` / `F10` | Confirm modal edit |\n| `a` | Add new row |\n| `d` | Toggle delete mark |\n| `c` | Clone row |\n| `u` / `U` | Revert cell / row |\n| `Ctrl+U` | Revert all changes |\n| `Ctrl+D` | Preview DML |\n| `Ctrl+S` | Submit changes |\n| `f` | Follow FK reference |\n| `Alt+Left` | FK back-navigation |\n\n### Bottom Panels\n\n| Key | Action |\n|-----|--------|\n| `1` / `2` / `3` / `4` | Results / Explain / Detail / ER Diagram |\n| `Tab` (Explain) | Toggle Bytecode / Query Plan |\n| `Enter` (Explain) | Generate EXPLAIN |\n| `Tab` (ER Diagram) | Cycle focus between tables |\n| `Enter` (ER Diagram) | Expand / collapse table columns |\n| `h/j/k/l` (ER Diagram) | Pan viewport |\n| `+` / `-` (ER Diagram) | Adjust spacing |\n| `c` (ER Diagram) | Toggle compact mode |\n| `o` (ER Diagram) | Query focused table |\n\n### Admin Tab\n\n| Key | Action |\n|-----|--------|\n| `r` | Refresh |\n| `c` | WAL checkpoint |\n| `i` | Integrity check |\n| `Enter` (Pragmas) | Edit selected pragma |\n\nPress `Esc` in any panel to release focus.\n\n## Configuration\n\nConfig file location: `~/.config/tursotui/config.toml`\n\n```toml\n[editor]\ntab_size = 4\nautocomplete = true\nautocomplete_min_chars = 1\n\n[results]\nmax_column_width = 40\nnull_display = \"NULL\"\n\n[history]\nmax_entries = 5000\n\n[theme]\nmode = \"dark\"    # \"dark\" or \"light\"\n```\n\n## Architecture\n\ntursotui uses a **unidirectional data flow** architecture inspired by Elm/Redux. Components emit `Action`s, `AppState` processes state changes, and results route back through a two-phase dispatch.\n\n### System Overview\n\n```mermaid\ngraph TB\n    subgraph Terminal\n        CT[Crossterm Events\u003cbr\u003e\u003ci\u003ekey, mouse, resize\u003c/i\u003e]\n    end\n\n    subgraph EventLoop[\"Event Loop (main.rs)\"]\n        DRAIN[Drain async channel]\n        POLL[Poll crossterm — 16ms]\n        ROUTE[Route to focused component]\n        GLOBAL[Global key fallback]\n        RENDER[Render frame]\n    end\n\n    subgraph State[\"Application State (app.rs)\"]\n        AS[AppState]\n        AC[Action enum\u003cbr\u003e\u003ci\u003e50+ variants\u003c/i\u003e]\n        SC[SchemaCache]\n        DC[DatabaseContext\u003cbr\u003e\u003ci\u003eper-tab state\u003c/i\u003e]\n    end\n\n    subgraph Components[\"Components (Component trait)\"]\n        direction LR\n        SE[Schema\u003cbr\u003eExplorer]\n        QE[Query\u003cbr\u003eEditor]\n        RT[Results\u003cbr\u003eTable]\n        DE[Data\u003cbr\u003eEditor]\n        EV[Explain\u003cbr\u003eView]\n        RD[Record\u003cbr\u003eDetail]\n        ER[ER\u003cbr\u003eDiagram]\n        AI[Admin\u003cbr\u003eInfo]\n        PD[Pragma\u003cbr\u003eDashboard]\n    end\n\n    subgraph Overlays\n        direction LR\n        HLP[Help]\n        HST[History]\n        BK[Bookmarks]\n        EXP[Export]\n        DML[DML Preview]\n        FP[File Picker]\n        GTO[Go to Object]\n        DDL[DDL Viewer]\n    end\n\n    subgraph Async[\"Async I/O (tokio)\"]\n        DH[DatabaseHandle\u003cbr\u003e\u003ci\u003eArc\u0026lt;Database\u0026gt;\u003c/i\u003e]\n        SPAWN[\"tokio::spawn\u003cbr\u003e\u003ci\u003efresh connection per query\u003c/i\u003e\"]\n        MPSC[mpsc channel]\n    end\n\n    subgraph Persistence\n        CFG[Config\u003cbr\u003e\u003ci\u003eTOML\u003c/i\u003e]\n        HDB[History DB\u003cbr\u003e\u003ci\u003eSQLite\u003c/i\u003e]\n        BUF[Editor Buffer\u003cbr\u003e\u003ci\u003eauto-save\u003c/i\u003e]\n    end\n\n    CT --\u003e POLL\n    DRAIN --\u003e ROUTE\n    POLL --\u003e ROUTE\n    ROUTE --\u003e Components\n    ROUTE --\u003e Overlays\n    Components --\u003e|emit Action| AC\n    Overlays --\u003e|emit Action| AC\n    AC --\u003e|\"phase 1: state\"| AS\n    AC --\u003e|\"phase 2: dispatch\"| Components\n    AC --\u003e|\"phase 2: I/O\"| DH\n    DH --\u003e SPAWN\n    SPAWN --\u003e MPSC\n    MPSC --\u003e DRAIN\n    AS --- SC\n    AS --- DC\n    RENDER --\u003e Components\n    RENDER --\u003e Overlays\n    CFG -.-\u003e AS\n    HDB -.-\u003e HST\n    BUF -.-\u003e QE\n\n    ROUTE -.-\u003e|unhandled| GLOBAL\n```\n\n### Event Loop \u0026 Data Flow\n\n```mermaid\nsequenceDiagram\n    participant T as Terminal\n    participant EL as Event Loop\n    participant C as Component\n    participant AS as AppState\n    participant DB as DatabaseHandle\n    participant TK as tokio task\n\n    Note over EL: Each frame (~60fps)\n\n    EL-\u003e\u003eEL: Drain async results (try_recv)\n    EL-\u003e\u003eT: Poll crossterm (16ms timeout)\n    T--\u003e\u003eEL: KeyEvent\n\n    EL-\u003e\u003eC: handle_key(event)\n    C--\u003e\u003eEL: Action\n\n    rect rgb(40, 40, 60)\n        Note over EL,AS: Two-phase dispatch\n        EL-\u003e\u003eAS: update(action) — state mutations\n        EL-\u003e\u003eC: dispatch — route to components \u0026 I/O\n    end\n\n    alt Database action (e.g. ExecuteQuery)\n        EL-\u003e\u003eDB: execute_query(sql)\n        DB-\u003e\u003eTK: tokio::spawn with fresh connection\n        TK--\u003e\u003eEL: QueryResult via mpsc\n        EL-\u003e\u003eAS: update(QueryCompleted)\n        EL-\u003e\u003eC: dispatch(QueryCompleted)\n    end\n\n    EL-\u003e\u003eC: render(frame, area)\n```\n\n### UI Layout\n\n```text\n┌──────────────────────────────────────────────────────────────────┐\n│  Tab Bar: [db1.sqlite] [db2.sqlite] [:memory:]                  │\n├────────────────┬─────────────────────────────────────────────────┤\n│                │                                                 │\n│  Schema        │  Query Editor                                   │\n│  Explorer      │  ┌─────────────────────────────────────────┐   │\n│                │  │ SELECT * FROM users                      │   │\n│  ▸ Tables (5)  │  │ WHERE active = 1;                        │   │\n│    users       │  └─────────────────────────────────────────┘   │\n│    orders      ├─────────────────────────────────────────────────┤\n│    products    │                                                 │\n│  ▸ Views (2)   │  Results Table / Explain / Detail / ER Diagram  │\n│  ▸ Indexes (3) │  ┌────────┬──────────┬─────────┬────────────┐  │\n│                │  │ id     │ name     │ email   │ active     │  │\n│                │  ├────────┼──────────┼─────────┼────────────┤  │\n│                │  │ 1      │ Alice    │ a@b.com │ 1          │  │\n│                │  │ 2      │ Bob      │ b@c.com │ 1          │  │\n│                │  └────────┴──────────┴─────────┴────────────┘  │\n├────────────────┴─────────────────────────────────────────────────┤\n│  Status: users │ 2 rows │ 4 cols                        F1 Help │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n### Key Design Decisions\n\n- **Unidirectional data flow** — components emit `Action`s, `AppState` processes state changes, results route back to components via two-phase dispatch.\n- **Async queries** — `tokio::spawn` with fresh connections per query, results delivered via `mpsc` channel. No shared connection state between tasks.\n- **Component trait** — each panel implements `handle_key`, `update`, `render` with consistent `panel_block` / `overlay_block` helpers for styled borders.\n- **Catppuccin theme system** — full Mocha (dark) and Latte (light) palettes with semantic color roles for schema types, editor highlighting, and data editing states.\n- **Transactional data editing** — change log with one-entry-per-PK invariant, DML generation, and `PRAGMA defer_foreign_keys` for safe FK handling.\n- **No unsafe code** — `#[forbid(unsafe_code)]` enforced project-wide.\n\n## Tech Stack\n\n| Crate | Purpose |\n| ------- | --------- |\n| [turso](https://crates.io/crates/turso) | Database engine (libSQL/SQLite) |\n| [ratatui](https://crates.io/crates/ratatui) | Terminal UI framework |\n| [tokio](https://crates.io/crates/tokio) | Async runtime |\n| [clap](https://crates.io/crates/clap) | CLI argument parsing |\n| [arboard](https://crates.io/crates/arboard) | Clipboard access |\n| [unicode-width](https://crates.io/crates/unicode-width) | Display-column width measurement |\n| [serde](https://crates.io/crates/serde) / [toml](https://crates.io/crates/toml) | Configuration serialization |\n| [serde_json](https://crates.io/crates/serde_json) | JSON detection and pretty-printing |\n| [dirs](https://crates.io/crates/dirs) | Platform config/data directories |\n\n## License\n\nMIT\n\n## Acknowledgments\n\n- Built with [Rust](https://www.rust-lang.org/)\n- TUI powered by [ratatui](https://ratatui.rs)\n- Cross-platform terminal handling by [crossterm](https://github.com/crossterm-rs/crossterm)\n- Theme palette by [Catppuccin](https://github.com/catppuccin/catppuccin)\n\n## Contact\n\n**Author:** Mikko Leppänen\n**Email:** \u003cmleppan23@gmail.com\u003e\n**GitHub:** [@mikeleppane](https://github.com/mikeleppane)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeleppane%2Ftursotui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikeleppane%2Ftursotui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeleppane%2Ftursotui/lists"}