# Textual Jumper
A keyboard-driven navigation widget for Textual TUI applications. Jump to any focusable widget instantly using intuitive keyboard shortcuts!
## Features
- Instant Navigation - Jump to any widget with 1-2 keystrokes
- Multi-Character Keys - Automatically generates key combinations for many widgets
- Visual Feedback - Real-time highlighting shows typed characters
- Customizable - Define your own key mappings or use defaults
- Zero Dependencies - Only requires Textual
- Easy Integration - Add to existing apps in minutes
## Installation
Using uv:
```bash
uv add textual-jumper
```
Using pip:
```bash
pip install textual-jumper
```
## Try the Demo
Run the interactive demo to see Textual Jumper in action:
```bash
uvx textual-jumper
```
Press `Ctrl+O` to activate jump mode, then press a key to jump to that widget!
## Quick Start
```python
from textual.app import App, ComposeResult
from textual.widgets import Input, Header, Footer
from textual_jumper import Jumper
class MyApp(App):
BINDINGS = [("ctrl+o", "show_overlay", "Jump")]
def compose(self) -> ComposeResult:
yield Header()
yield Jumper()
name_input = Input(placeholder="Name")
name_input.jumpable = True
yield name_input
email_input = Input(placeholder="Email")
email_input.jumpable = True
yield email_input
yield Footer()
def action_show_overlay(self) -> None:
self.query_one(Jumper).show()
if __name__ == "__main__":
MyApp().run()
```
## How It Works
### Single-Character Keys
For 8 or fewer widgets, each gets a single character:
```
Input Field 1 [a]
Input Field 2 [s]
Button [d]
```
Press `a` to jump to Input Field 1.
### Multi-Character Keys
For 9+ widgets, the system generates combinations with no conflicts:
```
Input 1 [a] Input 5 [ha] Input 9 [js]
Input 2 [s] Input 6 [hs] Input 10 [jd]
Input 3 [d] Input 7 [hd] Input 11 [jw]
Input 4 [w] Input 8 [ja]
```
Smart allocation strategy ensures no conflicts between single and multi-character keys.
## Configuration
### Custom Key Mappings
```python
jumper = Jumper(ids_to_keys={
"username": "u",
"password": "p",
"submit": "s"
})
```
### Custom Available Keys
```python
jumper = Jumper(keys=["a", "s", "d", "f", "j", "k", "l", ";"])
```
## Requirements
- Python 3.10+
- Textual 6.3.0+
## Development
```bash
# Clone repository
git clone https://github.com/zaloog/textual-jumper.git
cd textual-jumper
# Install with dev dependencies
uv sync --extra dev
# Install pre-commit hooks
uv run pre-commit install
# Run tests
uv run pytest
# Run linting
uv run pre-commit run --all-files
```
## Publishing
The package is automatically published to PyPI when a new release is created on GitHub:
1. Update version in `pyproject.toml`
2. Create a new tag: `git tag v0.1.0 && git push origin v0.1.0`
3. Create a GitHub release from the tag
4. The publish workflow will automatically build and upload to PyPI
Note: PyPI publishing uses [Trusted Publishers](https://docs.pypi.org/trusted-publishers/) (no API token needed). Configure this in your PyPI project settings before the first release.
## License
MIT License
## Acknowledgments
Inspired by Vim's EasyMotion plugin.
Built with Textual by Textualize.io.
Created with Claude Code.
Raw data
{
"_id": null,
"home_page": null,
"name": "textual-jumper",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "textual, tui, terminal, navigation, keyboard, vim, easymotion",
"author": "Zaloog",
"author_email": "Zaloog <gramslars@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/ed/5a/c94dcccfde08d6ee5540f9f4d29544027fda1c5813d5ce4064050aeaeb3d/textual_jumper-0.1.0.tar.gz",
"platform": null,
"description": "# Textual Jumper\n\nA keyboard-driven navigation widget for Textual TUI applications. Jump to any focusable widget instantly using intuitive keyboard shortcuts!\n\n## Features\n\n- Instant Navigation - Jump to any widget with 1-2 keystrokes\n- Multi-Character Keys - Automatically generates key combinations for many widgets\n- Visual Feedback - Real-time highlighting shows typed characters\n- Customizable - Define your own key mappings or use defaults\n- Zero Dependencies - Only requires Textual\n- Easy Integration - Add to existing apps in minutes\n\n## Installation\n\nUsing uv:\n\n```bash\nuv add textual-jumper\n```\n\nUsing pip:\n\n```bash\npip install textual-jumper\n```\n\n## Try the Demo\n\nRun the interactive demo to see Textual Jumper in action:\n\n```bash\nuvx textual-jumper\n```\n\nPress `Ctrl+O` to activate jump mode, then press a key to jump to that widget!\n\n## Quick Start\n\n```python\nfrom textual.app import App, ComposeResult\nfrom textual.widgets import Input, Header, Footer\nfrom textual_jumper import Jumper\n\nclass MyApp(App):\n BINDINGS = [(\"ctrl+o\", \"show_overlay\", \"Jump\")]\n\n def compose(self) -> ComposeResult:\n yield Header()\n yield Jumper()\n\n name_input = Input(placeholder=\"Name\")\n name_input.jumpable = True\n yield name_input\n\n email_input = Input(placeholder=\"Email\")\n email_input.jumpable = True\n yield email_input\n\n yield Footer()\n\n def action_show_overlay(self) -> None:\n self.query_one(Jumper).show()\n\nif __name__ == \"__main__\":\n MyApp().run()\n```\n\n## How It Works\n\n### Single-Character Keys\n\nFor 8 or fewer widgets, each gets a single character:\n\n```\nInput Field 1 [a]\nInput Field 2 [s]\nButton [d]\n```\n\nPress `a` to jump to Input Field 1.\n\n### Multi-Character Keys\n\nFor 9+ widgets, the system generates combinations with no conflicts:\n\n```\nInput 1 [a] Input 5 [ha] Input 9 [js]\nInput 2 [s] Input 6 [hs] Input 10 [jd]\nInput 3 [d] Input 7 [hd] Input 11 [jw]\nInput 4 [w] Input 8 [ja]\n```\n\nSmart allocation strategy ensures no conflicts between single and multi-character keys.\n\n## Configuration\n\n### Custom Key Mappings\n\n```python\njumper = Jumper(ids_to_keys={\n \"username\": \"u\",\n \"password\": \"p\",\n \"submit\": \"s\"\n})\n```\n\n### Custom Available Keys\n\n```python\njumper = Jumper(keys=[\"a\", \"s\", \"d\", \"f\", \"j\", \"k\", \"l\", \";\"])\n```\n\n## Requirements\n\n- Python 3.10+\n- Textual 6.3.0+\n\n## Development\n\n```bash\n# Clone repository\ngit clone https://github.com/zaloog/textual-jumper.git\ncd textual-jumper\n\n# Install with dev dependencies\nuv sync --extra dev\n\n# Install pre-commit hooks\nuv run pre-commit install\n\n# Run tests\nuv run pytest\n\n# Run linting\nuv run pre-commit run --all-files\n```\n\n## Publishing\n\nThe package is automatically published to PyPI when a new release is created on GitHub:\n\n1. Update version in `pyproject.toml`\n2. Create a new tag: `git tag v0.1.0 && git push origin v0.1.0`\n3. Create a GitHub release from the tag\n4. The publish workflow will automatically build and upload to PyPI\n\nNote: PyPI publishing uses [Trusted Publishers](https://docs.pypi.org/trusted-publishers/) (no API token needed). Configure this in your PyPI project settings before the first release.\n\n## License\n\nMIT License\n\n## Acknowledgments\n\nInspired by Vim's EasyMotion plugin.\nBuilt with Textual by Textualize.io.\nCreated with Claude Code.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A keyboard-driven navigation widget for Textual TUI applications",
"version": "0.1.0",
"project_urls": {
"Homepage": "https://github.com/zaloog/textual-jumper",
"Issues": "https://github.com/zaloog/textual-jumper/issues",
"Repository": "https://github.com/zaloog/textual-jumper"
},
"split_keywords": [
"textual",
" tui",
" terminal",
" navigation",
" keyboard",
" vim",
" easymotion"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8c59d73d5a56d6764147c2ce7a6cb09279c633ce18ee75a9a45e9a265cd6c007",
"md5": "93a4377957d63a9b9d5841faa2ea0a54",
"sha256": "a9bc3d2d65974cbc916ae4ac0a8fd3dd91885ea9dd9904087229389fd89543b6"
},
"downloads": -1,
"filename": "textual_jumper-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "93a4377957d63a9b9d5841faa2ea0a54",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 8072,
"upload_time": "2025-10-19T20:38:00",
"upload_time_iso_8601": "2025-10-19T20:38:00.553483Z",
"url": "https://files.pythonhosted.org/packages/8c/59/d73d5a56d6764147c2ce7a6cb09279c633ce18ee75a9a45e9a265cd6c007/textual_jumper-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "ed5ac94dcccfde08d6ee5540f9f4d29544027fda1c5813d5ce4064050aeaeb3d",
"md5": "55c013de931069926680805bab42491e",
"sha256": "07b74e44b17aa16eb57b7a974964b15a551ca64637652c0bbfbf394ec26eca2d"
},
"downloads": -1,
"filename": "textual_jumper-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "55c013de931069926680805bab42491e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 6703,
"upload_time": "2025-10-19T20:38:01",
"upload_time_iso_8601": "2025-10-19T20:38:01.984469Z",
"url": "https://files.pythonhosted.org/packages/ed/5a/c94dcccfde08d6ee5540f9f4d29544027fda1c5813d5ce4064050aeaeb3d/textual_jumper-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-19 20:38:01",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "zaloog",
"github_project": "textual-jumper",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "textual-jumper"
}