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 ADDED
@@ -0,0 +1,4 @@
1
+ """termjump — click-to-position terminal command editor."""
2
+
3
+ __version__ = "0.1.0"
4
+ __author__ = "Sri"
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
+ [![PyPI version](https://img.shields.io/pypi/v/termjump?color=blueviolet)](https://pypi.org/project/termjump/)
23
+ [![Python](https://img.shields.io/badge/python-3.10+-blue)](https://www.python.org/)
24
+ [![Shell](https://img.shields.io/badge/shell-zsh-green)](https://www.zsh.org/)
25
+ [![License](https://img.shields.io/badge/license-MIT-orange)](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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ termjump = termjump.cli:termjump_main
3
+ termjump-edit = termjump.cli:termjump_edit_main
@@ -0,0 +1 @@
1
+ termjump