A modular PyQt6 file viewer + lightweight editor with an AI agent that knows your workspace.
Open anything — code in 60+ languages, markdown, LaTeX (with on-demand PDF compile), PDF, DOCX, Jupyter notebooks, CSVs, Excel / OpenDocument / SQLite / archives (zip/tar/7z), scientific data (NumPy, MATLAB, Parquet, HDF5, NetCDF), certificates, fonts, images, video AND audio — with live theming, syntax highlighting, LSP integration, and an embedded Jupyter kernel. Save As is format-aware — Markdown → DOCX, JSON ↔ YAML ↔ TOML, CSV → JSON/XLSX, and more. Edit PDFs: rotate / delete / extract / merge / split pages, add highlights and annotations (dialog or mouse-driven), replace text spans, find-and-replace, cryptographically sign (PAdES via pyHanko), or round-trip via Markdown / DOCX for free-form edits. Then talk to a chat agent with first-class tools for every supported format.
The agent in this shot has searched the workspace, picked five ranked citations (left), and explained what
BusyIndicatordoes and where it's called. Click any citation to jump straight to the right line.
- Workspace RAG with citations. A BM25 index over the whole project
(code, markdown, PDFs, notebooks, images by name) with optional
embedding re-rank. Every agent answer comes back as
(file, line/page/cell)citations the user can click to jump to. →docs/workspace-rag.md - An agent that can extend the app. When TextView opens a file it
doesn't recognise, it identifies the file by magic bytes and offers
the chat agent. The agent can search the web, install a Python
package, write an extension handler script, or write a full plugin
— each gated by a separate per-tool safety flag. →
docs/unknown-files.md - Multimodal chat. Drop images directly into the chat input — they
go to the model as Anthropic-shape image content blocks. →
docs/chat.md - Many formats, one window. Text, code (~60 languages), markdown,
LaTeX, JSON / YAML / TOML / TSV / NDJSON / GeoJSON, CSV (sortable
table mode with stats and chart picker), XLSX / ODS / SQLite /
archives (zip/tar/7z) all share the table view via F4 sheet/table
switcher; NumPy / MATLAB / Parquet / Feather / HDF5 / NetCDF for
scientific data; PDF, DOCX / RTF / EPUB / ODT, images (incl.
animated WebP / TIFF / GIF), video + audio with ID3 metadata,
Jupyter notebooks, certificates (.pem/.crt/.cer/.key), fonts
(.ttf/.otf/.woff/.woff2). →
docs/file-formats.md - PDF editing as first-class (v3.5 — five tiers).
Pages: rotate / delete / extract / reorder / insert blank /
merge / split. Annotations: sticky / free-text / highlight /
underline / strikeout / rectangle / circle / ink — dialog or
mouse-driven. Text: span replacement + find-and-replace + click-
to-edit. Cryptographic signing with PAdES + optional TSA
timestamps; verification with cert-chain + tamper detection.
Edit via round-trip: convert PDF → Markdown / DOCX, edit,
re-export through the existing Save As pipelines. Source PDF is
never mutated — every operation writes a new file. →
docs/file-formats.md - Templates + format-aware Save As. New from template… (Ctrl+Alt+N) with ~25 starter files (README, LaTeX article, Python script, Dockerfile, …). Save As offers conversion when the chosen extension implies a different format — Markdown → DOCX, JSON ↔ YAML ↔ TOML, CSV → JSON/JSONL/XLSX/Markdown/HTML. After save the file re-opens so view-mode flips correctly.
- Built-in format reference. A curated database of 40+ file
formats — descriptions, magic bytes, tools, how-to-open / convert
notes — searchable from Help → File formats database… (Ctrl+Shift+B).
The unknown-file inspector auto-attaches the matching entry; the
chat agent has lookup / search / extend tools.
→
docs/file-formats-db.md - Security at open-time. Heuristic scan of every file before it
loads — dangerous extensions, magic-byte mismatches, Office macros,
PDF JavaScript / Launch triggers, suspicious shell patterns
(
curl … | bash, base64-decode-pipe-shell, PowerShell evasion). Findings prompt with Open / Quarantine / Cancel. Optional ClamAV passthrough; optionalsandbox-exec/firejailfor the runner. →docs/security.md - LSP support for Python (pyright), TypeScript, Go (gopls), Rust
(rust-analyzer), C/C++ (clangd) — hover, go-to-definition, find
references, diagnostics panel. →
docs/lsp.md - Embedded Jupyter: notebook viewer / editor / runner with rich
output (HTML, SVG, images, markdown), plus Python REPL and qtconsole.
Single-kernel auto-start when you hit Run. →
docs/notebook.md - Live everything. Theme, font, layout, line spacing — every display option is reactive. 10 built-in palettes (Dracula, Nord, Solarized, Sepia, …) switch without restart.
- Modular by construction. Every source file under 500 lines, one
concern each, 826-test regression suite running in under 15
seconds. →
INTERFACE.md,docs/architecture.md
# conda (recommended on macOS — pins sqlite>=3.45 to avoid the
# anaconda+macOS ABI mismatch that breaks ipykernel and qtconsole)
conda env create -f environment.yml
conda activate textview
python main.py # opens with welcome screen
python main.py path/to/file # opens that file# pip (Linux / Windows / advanced macOS)
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python main.pyYou can also drag-and-drop files onto the window to open them.
| Topic | File |
|---|---|
| First-time orientation | docs/overview.md |
| Every supported format | docs/file-formats.md |
| Workspace RAG (deep dive) | docs/workspace-rag.md |
| Unknown-file workflow + safety gates | docs/unknown-files.md |
| File-formats database | docs/file-formats-db.md |
| Security & sandboxing | docs/security.md |
| Chat / LLM panel | docs/chat.md |
| LSP setup per language | docs/lsp.md |
| Notebook viewer / runner | docs/notebook.md |
| Agent scripts | docs/scripts.md |
| Plugin loader | docs/plugins.md |
| Lifecycle hooks | docs/hooks.md |
| Agent / LLM tool surface | docs/agent-api.md |
| External control protocol | docs/control-server.md |
| Code map (where things live) | docs/architecture.md |
| Keyboard reference | docs/shortcuts.md |
| Troubleshooting | docs/troubleshooting.md |
The same files power the in-app Help menu and the chat agent's
list_docs / read_doc / search_docs tools, so user docs and
agent context stay in sync.
MainWindow (src/app.py) owns a tabbed TextViewer and a small
constellation of dock widgets and controllers — each in its own focused
module. Display options live in DisplaySettings (a frozen-ish
dataclass) and propagate live through SettingsManager.changed. Data
flows file → file_loader → optional document extractor → format-aware
viewer (CodeViewer, QPdfView, WebView, TableView, ImageView,
NotebookView) → optional Pygments / markdown renderer.
LLM tools share a stable AppAPI façade so internal refactors don't
break user scripts. Plugins (~/.config/TextView/plugins/), agent
scripts (~/.config/TextView/agent_scripts/), format handlers
(~/.config/TextView/format_handlers.json), and lifecycle hooks
(~/.config/TextView/hooks/) are loaded at startup and reload
on demand.
INTERFACE.md is the navigation map; every module's
responsibility is one row in a table there.
python -m pytest # full (~15s, 826 cases)
python -m pytest -m "not slow" # CI subset (skips Jupyter subprocess tests)
python -m pytest tests/test_X.py # one fileGitHub Actions runs the fast subset on every push and pull request
via tests.yml. The README's
last commit badge is auto-bumped by the same workflow on every
green push to main.
| Shortcut | Action |
|---|---|
Ctrl+P |
Quick open file (fuzzy) |
Ctrl+K |
Command palette (every action) |
Ctrl+Alt+N |
New from template… (Markdown / Python / LaTeX / …) |
Ctrl+Shift+F |
Find in project |
Ctrl+F |
Find / replace (regex toggle) |
Ctrl+J |
Chat panel |
Ctrl+Shift+Z |
Citations panel |
Ctrl+I |
Metadata panel |
| `Ctrl+`` | Terminal (PTY-backed) |
Ctrl+Alt+J |
Jupyter qtconsole |
F4 |
Switch sheet / table / array / variable / dataset… |
F5 |
Run current file (notebook: run cell) |
F6 |
Compile LaTeX → PDF |
Ctrl+] / Ctrl+[ |
Rotate current PDF page CW / CCW |
Ctrl+Shift+Q |
Run SQL on the open SQLite |
Alt+/ |
LLM inline completion |
F2 |
Go to definition (LSP) |
Shift+F12 |
Find references (LSP) |
Ctrl+; |
Insert snippet |
Ctrl+? |
Show every shortcut (cheat sheet) |
Run → Choose Python interpreter… discovers system / conda / pyenv
Pythons; the selection persists and is reused by F5, the Python REPL,
qtconsole, and notebook kernel auto-start.
Private — see SESSION_LOG.md for development
history and ROADMAP.md for shipped + parked features.






