A Textual TUI coding workspace with file explorer and syntax highlighting
Project description
nanoCode
A Textual-based TUI editor/workspace with tabs, project search, git controls, markdown preview, and an integrated terminal.
Features
- File explorer sidebar with git-aware decorations and context-menu file actions
- Project text search sidebar with clickable file/line results
- Git control sidebar for staging, unstaging, discard, commit, sync, and branch checkout
- Tabbed editor with preview tabs, persistent tabs, and git status badges
- Markdown source/rendered preview workflow
- External formatter framework with Ruff-backed Python formatting
- Footer language selector for syntax overrides and footer branch selector for quick checkout
- Integrated PTY terminal with session handoff support
- Quick switcher for open tabs and recent files
- Workspace session restore for open files and key UI state
- Mouse support for splitters, tabs, search results, recent files, and git controls
Installation
Install from PyPI:
pip install nanoc
This installs the nanoc command and textual[syntax], which includes tree-sitter support for syntax highlighting.
Usage
Launch the app from the current directory:
nanoc
Launch against a specific workspace:
nanoc /path/to/project
Run through the Python module entry point:
python -m nanocode.app /path/to/project
Keyboard Shortcuts
| Key | Action |
|---|---|
Ctrl+S |
Save file |
Ctrl+Shift+S |
Save file as |
Ctrl+P |
Quick open files and tabs |
Ctrl+Shift+P |
Open command palette |
Ctrl+Shift+M |
Toggle Markdown preview |
Ctrl+/ |
Toggle line comment |
Ctrl+Shift+F |
Format document |
Ctrl+O |
Focus file tree |
Ctrl+E |
Focus editor |
Ctrl+Option+Left |
Switch to tab on the left |
Ctrl+Option+Right |
Switch to tab on the right |
Ctrl+T |
Toggle terminal |
Ctrl+N |
New untitled file |
Ctrl+Q |
Quit |
Additional actions such as Editor: Format Document, Editor: Toggle Format On Save, View: Search, View: Git, Settings: Keybindings, and theme switching are available from the command palette.
App-level shortcuts can be overridden with ~/.config/nanoCode/keybindings.json.
Only NanoCode app bindings are configurable; widget and modal bindings keep their built-in defaults.
Use the command palette and run Settings: Keybindings to create or open that file in the editor.
Modifier names in overrides use Textual syntax; macOS-friendly aliases like command and option are also accepted.
Example:
{
"bindings": {
"file.save": "ctrl+alt+s",
"view.files": "ctrl+shift+o"
}
}
UI Overview
- Sidebar tabs switch between
Explorer,Search, andGit Control. - The editor area shows recent files when no tabs are open.
- Files normally open as preview tabs first; editing or double-clicking promotes them to regular tabs.
- The bottom panel hosts the integrated terminal and can be toggled with
Ctrl+T. - The footer exposes the current branch and language mode. Both controls are clickable.
- The footer branch selector labels local-only branches as
local, labels same-name tracking branches that are no longer on the remote asnot on remote, and marks branches whose changes are already present on the default branch asin main. If the remote cannot be reached, it falls back to local tracking state such as Git's[gone]marker. - The footer branch selector hides old branch groups by default, can show them on demand, asks before switching to one, and can create and switch to a new branch from its
New Branchbutton.
Search, Git, and Markdown Workflows
- Project search scans the workspace, skips common generated directories, and jumps the cursor to the selected match.
- The git sidebar shows staged and unstaged changes, supports file-level and bulk actions, and can switch its primary button from
CommittoSync Changeswhen the tree is clean but ahead of remote. - Some discard operations are intentionally destructive and may remove untracked files as part of restoring the worktree.
- Clicking a changed file in the git sidebar opens it and can show an inline fullscreen diff view.
- Markdown preview opens a rendered companion tab for Markdown files rather than replacing the source tab.
Terminal
The terminal is a built-in PTY emulator based on pyte.
Features:
- Interactive shell support (
bash,zsh, etc.) - 256-color ANSI rendering
- Mouse tracking support
- Running interactive terminal programs
- Session handoff: when a file is opened with
nanoc path/to/filefrom inside the integrated terminal, the request is forwarded into the already-running app session instead of spawning a second instance
Persistence & Config
nanoCode stores user state under ~/.config/nanoCode/.
Current files:
recent.json: recent files shown on startup and used by the quick switcherrecent_actions.json: recent command-palette actionssessions.json: per-workspace open tabs, active tab, explorer state, selected sidebar panel, and terminal visibilitykeybindings.json: app-level keybinding overridessettings.json: app-level editor settings such asformat_on_save
Workspace restore intentionally skips untitled tabs, but it does restore file-backed tabs and rendered Markdown tabs.
Supported Languages
Syntax highlighting is supported for Textual's built-in languages:
- Bash (
.sh,.bash,.zsh,.command) - Go (
.go) - Java (
.java) - JavaScript (
.js,.mjs,.cjs,.jsx) - Python (
.py) - HTML (
.html,.htm) - CSS (
.css) - JSON (
.json) - Markdown (
.md) - Regex (
.regex,.regexp) - Rust (
.rs) - YAML (
.yaml,.yml) - TOML (
.toml) - SQL (
.sql) - XML (
.xml,.xsd,.xsl,.xslt,.svg)
Use the footer language selector to override the active tab's language for the current tab session.
Choose Auto to return to extension-based detection, or Plain Text to disable syntax highlighting.
Comment toggling is implemented for common languages including Bash, Go, HTML, Java, JavaScript, Markdown, Python, Rust, SQL, TOML, XML, and YAML.
Formatting is provided through external tools. Python formatting uses Ruff to organize imports and then run ruff format, so install Ruff separately and make sure ruff is on PATH before running Editor: Format Document or pressing Ctrl+Shift+F. Format-on-save is off by default and can be toggled from the command palette with Editor: Toggle Format On Save.
Development
Install development dependencies:
pip install -e ".[dev]"
Run the full test suite:
python -m pytest
Run a focused test module while iterating:
python -m pytest tests/test_workspace_sessions.py -q
Publishing
The PyPI project and distribution name is nanoc; the app name remains nanoCode, the import package remains nanocode, and the installed command is nanoc.
PyPI releases are published by .github/workflows/publish.yml using PyPI Trusted Publishing. Configure a pending GitHub Actions publisher on PyPI with:
- PyPI project name:
nanoc - Owner:
mmcguffi - Repository name:
nanoCode - Workflow name:
publish.yml - Environment name:
pypi
Version numbers use a major-only scheme: 0, 1, 2, and so on. The first release is 0.
Create the initial 0 release manually after the major-only version and publishing workflow changes are on main. After version 0 is available on PyPI, .github/workflows/release.yml handles normal releases without bypassing branch rules. When a non-release pull request is merged into main, GitHub Actions opens a release/N pull request that bumps version in pyproject.toml and nanocode.__version__ to the next major number. When that release pull request is merged, GitHub Actions creates a GitHub release with the same numeric tag and generated notes, then dispatches publish.yml.
The repository Actions setting must allow workflows to read and write repository contents so the release workflow can create release branches, open release pull requests, create releases, and dispatch publish runs. If GitHub Actions pull request creation is disabled in repository settings, the workflow leaves the release/N branch in place and logs a warning instead of failing. publish.yml runs the tests, builds the source and wheel distributions, and uploads them to PyPI without a PYPI_TOKEN secret. It can also be run manually from GitHub Actions if a failed publish needs to be retried before files have reached PyPI.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nanoc-0.tar.gz.
File metadata
- Download URL: nanoc-0.tar.gz
- Upload date:
- Size: 114.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18bda9a773f34c06aec05c79718d9922309e5ab50693178352c923d93a9af4ea
|
|
| MD5 |
31358e8e6804efd8ce7b1db6ab7dd514
|
|
| BLAKE2b-256 |
47da55ab905893bc5f19965db4e4a00661d5a15757cc83b81bbba405d45f1df8
|
Provenance
The following attestation bundles were made for nanoc-0.tar.gz:
Publisher:
publish.yml on mmcguffi/nanoCode
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nanoc-0.tar.gz -
Subject digest:
18bda9a773f34c06aec05c79718d9922309e5ab50693178352c923d93a9af4ea - Sigstore transparency entry: 1631565302
- Sigstore integration time:
-
Permalink:
mmcguffi/nanoCode@8e2f94c766769daf54d982d95e821d15f64c91f7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mmcguffi
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8e2f94c766769daf54d982d95e821d15f64c91f7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file nanoc-0-py3-none-any.whl.
File metadata
- Download URL: nanoc-0-py3-none-any.whl
- Upload date:
- Size: 117.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ddd7d454729b9a7acb553ba8ea1a346f41cc32c781e176780d853b97e3d4a7c
|
|
| MD5 |
58d3b95f816d5c0de6b3d01ff5ae01d2
|
|
| BLAKE2b-256 |
8e1754c17c9b5afcd857d0184df1fd13304784f9936786c06bdfd6fb93a858f5
|
Provenance
The following attestation bundles were made for nanoc-0-py3-none-any.whl:
Publisher:
publish.yml on mmcguffi/nanoCode
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nanoc-0-py3-none-any.whl -
Subject digest:
5ddd7d454729b9a7acb553ba8ea1a346f41cc32c781e176780d853b97e3d4a7c - Sigstore transparency entry: 1631565305
- Sigstore integration time:
-
Permalink:
mmcguffi/nanoCode@8e2f94c766769daf54d982d95e821d15f64c91f7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mmcguffi
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8e2f94c766769daf54d982d95e821d15f64c91f7 -
Trigger Event:
workflow_dispatch
-
Statement type: