discovery-fast-text 1.0.0__tar.gz
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.
- discovery_fast_text-1.0.0/LICENSE +5 -0
- discovery_fast_text-1.0.0/PKG-INFO +31 -0
- discovery_fast_text-1.0.0/README.md +12 -0
- discovery_fast_text-1.0.0/discovery_fast_text.egg-info/PKG-INFO +31 -0
- discovery_fast_text-1.0.0/discovery_fast_text.egg-info/SOURCES.txt +12 -0
- discovery_fast_text-1.0.0/discovery_fast_text.egg-info/dependency_links.txt +1 -0
- discovery_fast_text-1.0.0/discovery_fast_text.egg-info/entry_points.txt +2 -0
- discovery_fast_text-1.0.0/discovery_fast_text.egg-info/requires.txt +3 -0
- discovery_fast_text-1.0.0/discovery_fast_text.egg-info/top_level.txt +1 -0
- discovery_fast_text-1.0.0/fast_text/__init__.py +1 -0
- discovery_fast_text-1.0.0/fast_text/editor.py +199 -0
- discovery_fast_text-1.0.0/pyproject.toml +27 -0
- discovery_fast_text-1.0.0/setup.cfg +4 -0
- discovery_fast_text-1.0.0/setup.py +22 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: discovery-fast-text
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Vim-speed CLI editor with Nano ease and Incognito mode.
|
|
5
|
+
Author: Discovery Open Source Foundation
|
|
6
|
+
Author-email: Discovery Open Source Foundation <discovery@fast-txt.com>
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: textual>=0.40.0
|
|
14
|
+
Requires-Dist: pygments>=2.15.0
|
|
15
|
+
Requires-Dist: cryptography>=41.0.0
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
Dynamic: requires-python
|
|
19
|
+
|
|
20
|
+
# Fast-Text Pro
|
|
21
|
+
A high-performance CLI editor by **Discovery Open Source Foundation**.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
- **Fast**: Vim-like navigation and lightweight.
|
|
25
|
+
- **Secure**: Incognito mode with AES encryption for backups.
|
|
26
|
+
- **Retro**: Classic MS-DOS Edit TUI.
|
|
27
|
+
- **Smart**: Syntax highlighting and Auto-complete.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
```bash
|
|
31
|
+
pip install .
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Fast-Text Pro
|
|
2
|
+
A high-performance CLI editor by **Discovery Open Source Foundation**.
|
|
3
|
+
|
|
4
|
+
## Features
|
|
5
|
+
- **Fast**: Vim-like navigation and lightweight.
|
|
6
|
+
- **Secure**: Incognito mode with AES encryption for backups.
|
|
7
|
+
- **Retro**: Classic MS-DOS Edit TUI.
|
|
8
|
+
- **Smart**: Syntax highlighting and Auto-complete.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
```bash
|
|
12
|
+
pip install .
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: discovery-fast-text
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Vim-speed CLI editor with Nano ease and Incognito mode.
|
|
5
|
+
Author: Discovery Open Source Foundation
|
|
6
|
+
Author-email: Discovery Open Source Foundation <discovery@fast-txt.com>
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: textual>=0.40.0
|
|
14
|
+
Requires-Dist: pygments>=2.15.0
|
|
15
|
+
Requires-Dist: cryptography>=41.0.0
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
Dynamic: requires-python
|
|
19
|
+
|
|
20
|
+
# Fast-Text Pro
|
|
21
|
+
A high-performance CLI editor by **Discovery Open Source Foundation**.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
- **Fast**: Vim-like navigation and lightweight.
|
|
25
|
+
- **Secure**: Incognito mode with AES encryption for backups.
|
|
26
|
+
- **Retro**: Classic MS-DOS Edit TUI.
|
|
27
|
+
- **Smart**: Syntax highlighting and Auto-complete.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
```bash
|
|
31
|
+
pip install .
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
discovery_fast_text.egg-info/PKG-INFO
|
|
6
|
+
discovery_fast_text.egg-info/SOURCES.txt
|
|
7
|
+
discovery_fast_text.egg-info/dependency_links.txt
|
|
8
|
+
discovery_fast_text.egg-info/entry_points.txt
|
|
9
|
+
discovery_fast_text.egg-info/requires.txt
|
|
10
|
+
discovery_fast_text.egg-info/top_level.txt
|
|
11
|
+
fast_text/__init__.py
|
|
12
|
+
fast_text/editor.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fast_text
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .editor import main
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
from cryptography.fernet import Fernet
|
|
5
|
+
from textual.app import App, ComposeResult
|
|
6
|
+
from textual.widgets import TextArea, Footer, Header, TabbedContent, TabPane, Static, Input
|
|
7
|
+
from textual.binding import Binding
|
|
8
|
+
from textual.screen import ModalScreen
|
|
9
|
+
from textual.containers import Grid
|
|
10
|
+
|
|
11
|
+
# --- GLOBAL SETTINGS & PATHS ---
|
|
12
|
+
HOME = os.path.expanduser("~")
|
|
13
|
+
CONFIG_PATH = os.path.join(HOME, ".ftrc")
|
|
14
|
+
BACKUP_DIR = os.path.join(HOME, ".fast_text_backups")
|
|
15
|
+
|
|
16
|
+
# Ensure our backup folder exists
|
|
17
|
+
os.makedirs(BACKUP_DIR, exist_ok=True)
|
|
18
|
+
|
|
19
|
+
# Generate or load a key for Incognito mode
|
|
20
|
+
# In a real dev environment, we'd store this in a keychain, but this works for now!
|
|
21
|
+
KEY_FILE = os.path.join(HOME, ".ft_key")
|
|
22
|
+
if not os.path.exists(KEY_FILE):
|
|
23
|
+
with open(KEY_FILE, "wb") as kf:
|
|
24
|
+
kf.write(Fernet.generate_key())
|
|
25
|
+
with open(KEY_FILE, "rb") as kf:
|
|
26
|
+
CIPHER = Fernet(kf.read())
|
|
27
|
+
|
|
28
|
+
class AboutScreen(ModalScreen):
|
|
29
|
+
"""The 'Easter Egg' screen for credits."""
|
|
30
|
+
def compose(self) -> ComposeResult:
|
|
31
|
+
yield Grid(
|
|
32
|
+
Static("🚀 FAST-TEXT PRO\n\n"
|
|
33
|
+
"A Discovery Open Source Foundation Project\n"
|
|
34
|
+
"Built for speed, security, and nostalgia.\n\n"
|
|
35
|
+
"[Press ESC to Return]", id="egg-content"),
|
|
36
|
+
id="egg-box"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
class FastText(App):
|
|
40
|
+
"""
|
|
41
|
+
Main Editor Class.
|
|
42
|
+
Design Goal: Combine Nano's UI, Vim's Speed, and MS-Edit's Look.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
# Define our custom 'Discovery' blue theme
|
|
46
|
+
CSS = """
|
|
47
|
+
Screen { background: #0000AA; }
|
|
48
|
+
Header { background: #AAAAAA; color: #000000; }
|
|
49
|
+
Footer { background: #AAAAAA; color: #000000; }
|
|
50
|
+
#status-bar { background: #AAAAAA; color: #000000; height: 1; dock: bottom; padding: 0 1; }
|
|
51
|
+
TextArea { background: #0000AA; color: #FFFFFF; border: none; }
|
|
52
|
+
Input { dock: top; background: #0000AA; color: #FFFFFF; border: double #FFFFFF; display: none; }
|
|
53
|
+
.show-palette { display: block !important; }
|
|
54
|
+
|
|
55
|
+
#egg-box { align: center middle; }
|
|
56
|
+
#egg-content {
|
|
57
|
+
width: 50; height: 15;
|
|
58
|
+
background: #000088;
|
|
59
|
+
border: double #FFFF00;
|
|
60
|
+
color: #FFFF00;
|
|
61
|
+
padding: 2;
|
|
62
|
+
text-align: center;
|
|
63
|
+
}
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
BINDINGS = [
|
|
67
|
+
Binding("ctrl+s", "save", "Save"),
|
|
68
|
+
Binding("ctrl+p", "palette", "Cmd"),
|
|
69
|
+
Binding("ctrl+i", "toggle_incognito", "Incognito"),
|
|
70
|
+
Binding("ctrl+e", "credits", "About"),
|
|
71
|
+
Binding("ctrl+q", "quit", "Exit"),
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
def __init__(self, target_files):
|
|
75
|
+
super().__init__()
|
|
76
|
+
self.target_files = target_files if target_files else ["untitled.txt"]
|
|
77
|
+
self.incognito = False
|
|
78
|
+
self.user_config = self.load_config()
|
|
79
|
+
|
|
80
|
+
def load_config(self):
|
|
81
|
+
"""Load user preferences like theme or default language."""
|
|
82
|
+
if os.path.exists(CONFIG_PATH):
|
|
83
|
+
with open(CONFIG_PATH, "r") as f:
|
|
84
|
+
return json.load(f)
|
|
85
|
+
return {"theme": "monokai", "incognito_default": False}
|
|
86
|
+
|
|
87
|
+
def compose(self) -> ComposeResult:
|
|
88
|
+
yield Header(show_clock=True)
|
|
89
|
+
yield Input(placeholder="Commands: find <text> | replace <old> <new> | goto <line>")
|
|
90
|
+
|
|
91
|
+
with TabbedContent() as self.tabs:
|
|
92
|
+
for i, filename in enumerate(self.target_files):
|
|
93
|
+
with TabPane(filename, id=f"tab-{i}"):
|
|
94
|
+
# Initialize the editor for each file
|
|
95
|
+
editor = TextArea(id=f"editor-{i}", show_line_numbers=True)
|
|
96
|
+
editor.theme = self.user_config.get("theme", "monokai")
|
|
97
|
+
|
|
98
|
+
if os.path.exists(filename):
|
|
99
|
+
with open(filename, "r") as f:
|
|
100
|
+
editor.text = f.read()
|
|
101
|
+
yield editor
|
|
102
|
+
|
|
103
|
+
yield Static("Initializing...", id="status-bar")
|
|
104
|
+
yield Footer()
|
|
105
|
+
|
|
106
|
+
def on_mount(self) -> None:
|
|
107
|
+
# Every 30 seconds, run the background backup
|
|
108
|
+
self.set_interval(30, self.run_backup_cycle)
|
|
109
|
+
self.update_ui_state()
|
|
110
|
+
|
|
111
|
+
def run_backup_cycle(self):
|
|
112
|
+
"""The 'Memory Protection' loop."""
|
|
113
|
+
for i, fname in enumerate(self.target_files):
|
|
114
|
+
try:
|
|
115
|
+
editor = self.query_one(f"#editor-{i}", TextArea)
|
|
116
|
+
content = editor.text.encode()
|
|
117
|
+
|
|
118
|
+
# If Incognito is ON, encrypt the disk backup
|
|
119
|
+
if self.incognito:
|
|
120
|
+
content = CIPHER.encrypt(content)
|
|
121
|
+
|
|
122
|
+
backup_name = f"{os.path.basename(fname)}.bak"
|
|
123
|
+
with open(os.path.join(BACKUP_DIR, backup_name), "wb") as f:
|
|
124
|
+
f.write(content)
|
|
125
|
+
except:
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
def action_palette(self):
|
|
129
|
+
"""Toggle the command bar."""
|
|
130
|
+
p = self.query_one(Input)
|
|
131
|
+
p.toggle_class("show-palette")
|
|
132
|
+
if "show-palette" in p.classes:
|
|
133
|
+
p.focus()
|
|
134
|
+
|
|
135
|
+
def on_input_submitted(self, event: Input.Submitted):
|
|
136
|
+
"""Logic for the Command Palette."""
|
|
137
|
+
args = event.value.strip().split()
|
|
138
|
+
if not args: return
|
|
139
|
+
|
|
140
|
+
cmd = args[0].lower()
|
|
141
|
+
editor = self.tabs.active_pane.query_one(TextArea)
|
|
142
|
+
|
|
143
|
+
if cmd == "goto" and len(args) > 1:
|
|
144
|
+
line_idx = int(args[1]) - 1
|
|
145
|
+
editor.move_cursor((line_idx, 0))
|
|
146
|
+
editor.scroll_to_line(line_idx)
|
|
147
|
+
|
|
148
|
+
elif cmd == "replace" and len(args) > 2:
|
|
149
|
+
editor.text = editor.text.replace(args[1], args[2])
|
|
150
|
+
self.notify(f"Replaced all {args[1]} with {args[2]}")
|
|
151
|
+
|
|
152
|
+
event.input.remove_class("show-palette")
|
|
153
|
+
editor.focus()
|
|
154
|
+
|
|
155
|
+
def action_credits(self):
|
|
156
|
+
self.push_screen(AboutScreen())
|
|
157
|
+
|
|
158
|
+
def action_toggle_incognito(self):
|
|
159
|
+
self.incognito = not self.incognito
|
|
160
|
+
self.notify(f"Incognito Mode: {'ON' if self.incognito else 'OFF'}")
|
|
161
|
+
|
|
162
|
+
def update_ui_state(self):
|
|
163
|
+
"""Keep our custom [line/total] and {tab/total} status current."""
|
|
164
|
+
active = self.tabs.active_pane
|
|
165
|
+
if active:
|
|
166
|
+
ed = active.query_one(TextArea)
|
|
167
|
+
y, x = ed.cursor_location
|
|
168
|
+
tab_num = int(self.tabs.active.split("-")[-1]) + 1
|
|
169
|
+
inc_status = "🔒" if self.incognito else ""
|
|
170
|
+
|
|
171
|
+
status_text = (
|
|
172
|
+
f" {inc_status} [{y+1}/{ed.document.line_count}] "
|
|
173
|
+
f"{{{tab_num}/{len(self.target_files)}}} | "
|
|
174
|
+
f"File: {active.label}"
|
|
175
|
+
)
|
|
176
|
+
self.query_one("#status-bar").update(status_text)
|
|
177
|
+
|
|
178
|
+
def on_text_area_selection_changed(self):
|
|
179
|
+
self.update_ui_state()
|
|
180
|
+
|
|
181
|
+
def action_save(self):
|
|
182
|
+
"""Standard save with error handling."""
|
|
183
|
+
active = self.tabs.active_pane
|
|
184
|
+
fname = active.label.plain
|
|
185
|
+
content = active.query_one(TextArea).text
|
|
186
|
+
try:
|
|
187
|
+
with open(fname, "w") as f:
|
|
188
|
+
f.write(content)
|
|
189
|
+
self.notify(f"Saved: {fname}")
|
|
190
|
+
except Exception as e:
|
|
191
|
+
self.notify(f"Save failed: {e}", severity="error")
|
|
192
|
+
|
|
193
|
+
def main():
|
|
194
|
+
# Pass all command line args (files) to the App
|
|
195
|
+
app = FastText(sys.argv[1:])
|
|
196
|
+
app.run()
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
main()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "discovery-fast-text"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Discovery Open Source Foundation", email="discovery@fast-txt.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "Vim-speed CLI editor with Nano ease and Incognito mode."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"textual>=0.40.0",
|
|
21
|
+
"pygments>=2.15.0",
|
|
22
|
+
"cryptography>=41.0.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.scripts]
|
|
26
|
+
ft = "fast_text.editor:main"
|
|
27
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="fast-text-pro",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
author="Discovery Open Source Foundation",
|
|
7
|
+
description="Vim-speed CLI editor with Nano ease and Incognito mode.",
|
|
8
|
+
long_description=open("README.md").read(),
|
|
9
|
+
long_description_content_type="text/markdown",
|
|
10
|
+
packages=find_packages(),
|
|
11
|
+
install_requires=[
|
|
12
|
+
"textual>=0.40.0",
|
|
13
|
+
"pygments>=2.15.0",
|
|
14
|
+
"cryptography>=41.0.0",
|
|
15
|
+
],
|
|
16
|
+
entry_points={
|
|
17
|
+
"console_scripts": [
|
|
18
|
+
"ft=fast_text.editor:main", # This creates the 'ft' command
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
python_requires=">=3.8",
|
|
22
|
+
)
|