termjump 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- termjump/__init__.py +4 -0
- termjump/cli.py +45 -0
- termjump/editor.py +137 -0
- termjump/shell.py +35 -0
- termjump-0.1.0.dist-info/METADATA +164 -0
- termjump-0.1.0.dist-info/RECORD +9 -0
- termjump-0.1.0.dist-info/WHEEL +5 -0
- termjump-0.1.0.dist-info/entry_points.txt +3 -0
- termjump-0.1.0.dist-info/top_level.txt +1 -0
termjump/__init__.py
ADDED
termjump/cli.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
termjump CLI
|
|
3
|
+
|
|
4
|
+
termjump init → print zsh shell integration snippet
|
|
5
|
+
termjump-edit <cmd> → open TUI editor, print result to stdout
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def termjump_main():
|
|
12
|
+
"""Entry point for the `termjump` command."""
|
|
13
|
+
args = sys.argv[1:]
|
|
14
|
+
|
|
15
|
+
if not args or args[0] in ("-h", "--help"):
|
|
16
|
+
print("Usage:")
|
|
17
|
+
print(" termjump init Print shell integration snippet")
|
|
18
|
+
print(" termjump-edit <command> Open command editor")
|
|
19
|
+
print()
|
|
20
|
+
print("Quick setup (add to ~/.zshrc):")
|
|
21
|
+
print(' eval "$(termjump init)"')
|
|
22
|
+
sys.exit(0)
|
|
23
|
+
|
|
24
|
+
if args[0] == "init":
|
|
25
|
+
from termjump.shell import print_init_script
|
|
26
|
+
print_init_script("zsh")
|
|
27
|
+
sys.exit(0)
|
|
28
|
+
|
|
29
|
+
if args[0] == "version":
|
|
30
|
+
from termjump import __version__
|
|
31
|
+
print(f"termjump {__version__}")
|
|
32
|
+
sys.exit(0)
|
|
33
|
+
|
|
34
|
+
print(f"Unknown command: {args[0]}", file=sys.stderr)
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def termjump_edit_main():
|
|
39
|
+
"""Entry point for `termjump-edit` — opens the TUI editor."""
|
|
40
|
+
from termjump.editor import main
|
|
41
|
+
main()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
termjump_main()
|
termjump/editor.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
termjump editor — click any character to jump cursor there.
|
|
3
|
+
Built on prompt_toolkit for full terminal/mouse support.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from prompt_toolkit import Application
|
|
7
|
+
from prompt_toolkit.buffer import Buffer
|
|
8
|
+
from prompt_toolkit.layout.containers import HSplit, Window
|
|
9
|
+
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
|
|
10
|
+
from prompt_toolkit.layout.layout import Layout
|
|
11
|
+
from prompt_toolkit.key_binding import KeyBindings
|
|
12
|
+
from prompt_toolkit.formatted_text import HTML
|
|
13
|
+
from prompt_toolkit.styles import Style
|
|
14
|
+
from prompt_toolkit.mouse_events import MouseEventType
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
STYLE = Style.from_dict({
|
|
19
|
+
"status": "bg:#1a1a2e fg:#7c83fd bold",
|
|
20
|
+
"status.key": "bg:#1a1a2e fg:#e2e8f0",
|
|
21
|
+
"token.cmd": "fg:#ffa657 bold",
|
|
22
|
+
"token.flag": "fg:#3fb950",
|
|
23
|
+
"token.string": "fg:#d2a8ff",
|
|
24
|
+
"token.path": "fg:#79c0ff",
|
|
25
|
+
"token.default": "fg:#e6edf3",
|
|
26
|
+
"header": "bg:#0d1117 fg:#484f58",
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def tokenize_command(text):
|
|
31
|
+
import re
|
|
32
|
+
tokens = []
|
|
33
|
+
pattern = re.compile(
|
|
34
|
+
r'("(?:[^"\\]|\\.)*")'
|
|
35
|
+
r"|('(?:[^'\\]|\\.)*')"
|
|
36
|
+
r"|(--?[a-zA-Z][a-zA-Z0-9_-]*)"
|
|
37
|
+
r"|([^\s]+)"
|
|
38
|
+
)
|
|
39
|
+
first = True
|
|
40
|
+
for m in pattern.finditer(text):
|
|
41
|
+
s, e = m.start(), m.end()
|
|
42
|
+
tok = m.group(0)
|
|
43
|
+
if m.group(1) or m.group(2):
|
|
44
|
+
cls = "token.string"
|
|
45
|
+
elif m.group(3):
|
|
46
|
+
cls = "token.flag"
|
|
47
|
+
elif "/" in tok or tok.endswith((".conf", ".json", ".yaml", ".toml", ".sh", ".py")):
|
|
48
|
+
cls = "token.path"
|
|
49
|
+
elif first:
|
|
50
|
+
cls = "token.cmd"
|
|
51
|
+
else:
|
|
52
|
+
cls = "token.default"
|
|
53
|
+
tokens.append((s, e, cls))
|
|
54
|
+
first = False
|
|
55
|
+
return tokens
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def run_editor(initial_command: str) -> str | None:
|
|
59
|
+
result_holder = {"command": None, "cancelled": False}
|
|
60
|
+
|
|
61
|
+
from prompt_toolkit.document import Document
|
|
62
|
+
buf = Buffer(
|
|
63
|
+
name="main",
|
|
64
|
+
initial_document=Document(initial_command, cursor_position=len(initial_command)),
|
|
65
|
+
multiline=False,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
kb = KeyBindings()
|
|
69
|
+
|
|
70
|
+
@kb.add("enter")
|
|
71
|
+
def accept(event):
|
|
72
|
+
result_holder["command"] = buf.text
|
|
73
|
+
event.app.exit()
|
|
74
|
+
|
|
75
|
+
@kb.add("escape")
|
|
76
|
+
@kb.add("c-c")
|
|
77
|
+
def cancel(event):
|
|
78
|
+
result_holder["cancelled"] = True
|
|
79
|
+
event.app.exit()
|
|
80
|
+
|
|
81
|
+
@kb.add("c-a")
|
|
82
|
+
def go_home(event):
|
|
83
|
+
buf.cursor_position = 0
|
|
84
|
+
|
|
85
|
+
@kb.add("c-e")
|
|
86
|
+
def go_end(event):
|
|
87
|
+
buf.cursor_position = len(buf.text)
|
|
88
|
+
|
|
89
|
+
def get_status():
|
|
90
|
+
pos = buf.cursor_position
|
|
91
|
+
total = len(buf.text)
|
|
92
|
+
return HTML(
|
|
93
|
+
f'<status> termjump </status>'
|
|
94
|
+
f'<status.key> col <b>{pos}</b>/{total} </status.key>'
|
|
95
|
+
f'<status.key> ENTER confirm · ESC cancel · click to jump </status.key>'
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def mouse_handler(mouse_event):
|
|
99
|
+
if mouse_event.event_type == MouseEventType.MOUSE_UP:
|
|
100
|
+
col = mouse_event.position.x
|
|
101
|
+
buf.cursor_position = min(col, len(buf.text))
|
|
102
|
+
|
|
103
|
+
layout = Layout(
|
|
104
|
+
HSplit([
|
|
105
|
+
Window(FormattedTextControl(HTML('<header> ● termjump — smart command editor</header>')), height=1),
|
|
106
|
+
Window(BufferControl(buffer=buf, focusable=True, mouse_handler=mouse_handler), height=1, style="bg:#0d1117 fg:#e6edf3"),
|
|
107
|
+
Window(FormattedTextControl(get_status), height=1),
|
|
108
|
+
])
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
from prompt_toolkit.output.color_depth import ColorDepth
|
|
112
|
+
app = Application(
|
|
113
|
+
layout=layout,
|
|
114
|
+
key_bindings=kb,
|
|
115
|
+
style=STYLE,
|
|
116
|
+
mouse_support=True,
|
|
117
|
+
full_screen=False,
|
|
118
|
+
color_depth=ColorDepth.TRUE_COLOR,
|
|
119
|
+
)
|
|
120
|
+
app.run()
|
|
121
|
+
|
|
122
|
+
if result_holder["cancelled"]:
|
|
123
|
+
return None
|
|
124
|
+
return result_holder["command"]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main():
|
|
128
|
+
initial = " ".join(sys.argv[1:]) if len(sys.argv) >= 2 else ""
|
|
129
|
+
edited = run_editor(initial)
|
|
130
|
+
if edited is None:
|
|
131
|
+
sys.exit(1)
|
|
132
|
+
print(edited, end="")
|
|
133
|
+
sys.exit(0)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if __name__ == "__main__":
|
|
137
|
+
main()
|
termjump/shell.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generates shell integration scripts for termjump.
|
|
3
|
+
Usage: termjump init → prints zsh snippet to eval
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
ZSH_WIDGET = r"""
|
|
7
|
+
# ── termjump zsh integration ─────────────────────────────────────────────────
|
|
8
|
+
_termjump_widget() {
|
|
9
|
+
local current_cmd="$BUFFER"
|
|
10
|
+
|
|
11
|
+
# Run the editor; capture output
|
|
12
|
+
local edited
|
|
13
|
+
edited=$(termjump-edit "$current_cmd" </dev/tty 2>/dev/tty)
|
|
14
|
+
local exit_code=$?
|
|
15
|
+
|
|
16
|
+
if [[ $exit_code -eq 0 && -n "$edited" ]]; then
|
|
17
|
+
BUFFER="$edited"
|
|
18
|
+
CURSOR=${#BUFFER}
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
zle redisplay
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
zle -N _termjump_widget
|
|
25
|
+
# Bind to Ctrl+E (change to taste)
|
|
26
|
+
bindkey '^E' _termjump_widget
|
|
27
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def print_init_script(shell: str = "zsh") -> None:
|
|
32
|
+
if shell == "zsh":
|
|
33
|
+
print(ZSH_WIDGET)
|
|
34
|
+
else:
|
|
35
|
+
raise ValueError(f"Unsupported shell: {shell}. Currently only zsh is supported.")
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: termjump
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Click-to-position terminal command editor for zsh
|
|
5
|
+
Author-email: Your Name <you@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/srisowmya2000/termjump
|
|
8
|
+
Project-URL: Repository, https://github.com/srisowmya2000/termjump
|
|
9
|
+
Keywords: terminal,cli,zsh,editor,readline,cursor
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: prompt_toolkit>=3.0.0
|
|
13
|
+
|
|
14
|
+
<div align="center">
|
|
15
|
+
|
|
16
|
+
# ⚡ termjump
|
|
17
|
+
|
|
18
|
+
### Stop pressing `←` 47 times. Just click.
|
|
19
|
+
|
|
20
|
+
**A tiny TUI editor that lets you click any character in your terminal command to jump your cursor there instantly.**
|
|
21
|
+
|
|
22
|
+
[](https://pypi.org/project/termjump/)
|
|
23
|
+
[](https://www.python.org/)
|
|
24
|
+
[](https://www.zsh.org/)
|
|
25
|
+
[](LICENSE)
|
|
26
|
+
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 😤 The Problem
|
|
32
|
+
|
|
33
|
+
Every terminal user knows this pain:
|
|
34
|
+
```
|
|
35
|
+
$ docker run -it --rm -v /home/user/projects:/workspace -p 8080:8080 myimage:latest
|
|
36
|
+
^^^^^^^^
|
|
37
|
+
typo is here 😭
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Your options?
|
|
41
|
+
|
|
42
|
+
| Option | Reality |
|
|
43
|
+
|--------|---------|
|
|
44
|
+
| Press `←` repeatedly | 37 keypresses for one typo |
|
|
45
|
+
| `Alt+B` / `Alt+F` | How many words back? Who knows |
|
|
46
|
+
| `Ctrl+X Ctrl+E` | Opens full vim. For one character. |
|
|
47
|
+
| Retype the whole thing | 😤 |
|
|
48
|
+
|
|
49
|
+
**There is no way to just click where you want to edit. Until now.**
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## ✅ The Solution
|
|
54
|
+
|
|
55
|
+
**termjump** opens a lightweight inline editor right in your terminal.
|
|
56
|
+
Press `Ctrl+E` → the editor pops up → **click any character** → cursor jumps there → fix it → `Enter`.
|
|
57
|
+
```
|
|
58
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
59
|
+
│ ● termjump — smart command editor │
|
|
60
|
+
│ │
|
|
61
|
+
│ docker run -it --rm -v /home/user/projects:/workspace -p 8080:8080 │
|
|
62
|
+
│ ^ │
|
|
63
|
+
│ click here │
|
|
64
|
+
│ │
|
|
65
|
+
│ termjump col 36/72 ENTER confirm · ESC cancel · click to jump │
|
|
66
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 🚀 Quick Start
|
|
72
|
+
|
|
73
|
+
**1. Install**
|
|
74
|
+
```bash
|
|
75
|
+
pip install termjump
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**2. Add to your `~/.zshrc`**
|
|
79
|
+
```zsh
|
|
80
|
+
eval "$(termjump init)"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**3. Reload your shell**
|
|
84
|
+
```bash
|
|
85
|
+
source ~/.zshrc
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**4. Use it**
|
|
89
|
+
> Type any command → press `Ctrl+E` → click any character → edit → `Enter`
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 🎮 How It Works
|
|
94
|
+
```
|
|
95
|
+
You type a command Press Ctrl+E Click a character
|
|
96
|
+
───────────────── ──────────── ─────────────────
|
|
97
|
+
|
|
98
|
+
$ git commit -m ┌────────────┐ ┌────────────────┐
|
|
99
|
+
"fix autentication" ──► │ termjump │ ──────► │ cursor jumps │
|
|
100
|
+
│ editor │ click! │ exactly there │
|
|
101
|
+
└────────────┘ └────────────────┘
|
|
102
|
+
│
|
|
103
|
+
▼
|
|
104
|
+
Fix typo → Enter
|
|
105
|
+
Command runs ✓
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## ⌨️ Keyboard Shortcuts
|
|
111
|
+
|
|
112
|
+
| Key | Action |
|
|
113
|
+
|-----|--------|
|
|
114
|
+
| 🖱️ **Click** | Jump cursor instantly to any character |
|
|
115
|
+
| `←` / `→` | Move one character at a time |
|
|
116
|
+
| `Alt+←` / `Alt+→` | Jump one word |
|
|
117
|
+
| `Ctrl+A` | Jump to beginning of command |
|
|
118
|
+
| `Ctrl+E` | Jump to end of command |
|
|
119
|
+
| `Enter` | Confirm and run the command |
|
|
120
|
+
| `Esc` / `Ctrl+C` | Cancel — original command stays untouched |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## ⚙️ Configuration
|
|
125
|
+
|
|
126
|
+
**Change the trigger key** (default is `Ctrl+E`):
|
|
127
|
+
```zsh
|
|
128
|
+
# In your ~/.zshrc, after the eval line:
|
|
129
|
+
eval "$(termjump init)"
|
|
130
|
+
bindkey '^F' _termjump_widget # Ctrl+F instead
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 📋 Requirements
|
|
136
|
+
|
|
137
|
+
- **Python** 3.10+
|
|
138
|
+
- **Shell** — zsh (default on macOS since Catalina)
|
|
139
|
+
- **Terminal** with mouse support:
|
|
140
|
+
- ✅ iTerm2
|
|
141
|
+
- ✅ Kitty
|
|
142
|
+
- ✅ WezTerm
|
|
143
|
+
- ✅ macOS Terminal.app
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 🤝 Contributing
|
|
148
|
+
|
|
149
|
+
PRs and issues are very welcome!
|
|
150
|
+
```bash
|
|
151
|
+
git clone https://github.com/srisowmya2000/termjump
|
|
152
|
+
cd termjump
|
|
153
|
+
pip install -e ".[dev]"
|
|
154
|
+
python tests/test_termjump.py
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
<div align="center">
|
|
160
|
+
<br>
|
|
161
|
+
<b>termjump</b> — because arrow keys are not a navigation strategy.
|
|
162
|
+
<br><br>
|
|
163
|
+
Made with 🖱️ for everyone who has ever rage-retyped a long command.
|
|
164
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
termjump/__init__.py,sha256=HaH-KEbIe-SFY0qA8mId0EKDPNqMM3MTT4JHk6ck6ME,104
|
|
2
|
+
termjump/cli.py,sha256=B53_dn70nV6kgXE4xkVivQDNstxIjdykf__YM1za2fE,1142
|
|
3
|
+
termjump/editor.py,sha256=okqhrYSwNAzIMdyYVVFGmpzw7CkIkR2-MPIkOOHAOcs,3952
|
|
4
|
+
termjump/shell.py,sha256=Qwmu2-dRs_QbLSa-3VMB0xZkCk9XS1c-RiwO1JKJTc0,1147
|
|
5
|
+
termjump-0.1.0.dist-info/METADATA,sha256=Wp8Cfyj7cLBUuIBm5rZ9Sn7cfeV8A7cyF3Bk4uqvRYc,5307
|
|
6
|
+
termjump-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
+
termjump-0.1.0.dist-info/entry_points.txt,sha256=IX0KPDjZNAUDCdqJgf1HAZN_jBqc92JvUE0h4GJiQ8s,104
|
|
8
|
+
termjump-0.1.0.dist-info/top_level.txt,sha256=mAOl5ThHC2Bi8ltOdCcYpX15-uvpIfbDNgTNGj-u4o0,9
|
|
9
|
+
termjump-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
termjump
|