fillmyfile 0.1.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.
- fillmyfile-0.1.0/LICENSE +22 -0
- fillmyfile-0.1.0/PKG-INFO +116 -0
- fillmyfile-0.1.0/README.md +86 -0
- fillmyfile-0.1.0/fillmyfile/__init__.py +8 -0
- fillmyfile-0.1.0/fillmyfile/cli/__init__.py +0 -0
- fillmyfile-0.1.0/fillmyfile/cli/main.py +429 -0
- fillmyfile-0.1.0/fillmyfile/engine/__init__.py +0 -0
- fillmyfile-0.1.0/fillmyfile/engine/auto_indexer.py +9 -0
- fillmyfile-0.1.0/fillmyfile/engine/category_engine.py +28 -0
- fillmyfile-0.1.0/fillmyfile/engine/database_engine.py +92 -0
- fillmyfile-0.1.0/fillmyfile/engine/db_search_engine.py +63 -0
- fillmyfile-0.1.0/fillmyfile/engine/favorites_engine.py +77 -0
- fillmyfile-0.1.0/fillmyfile/engine/file_picker.py +32 -0
- fillmyfile-0.1.0/fillmyfile/engine/indexer_engine.py +141 -0
- fillmyfile-0.1.0/fillmyfile/engine/installer.py +18 -0
- fillmyfile-0.1.0/fillmyfile/engine/metadata_engine.py +41 -0
- fillmyfile-0.1.0/fillmyfile/engine/pack_manager.py +89 -0
- fillmyfile-0.1.0/fillmyfile/engine/paths.py +178 -0
- fillmyfile-0.1.0/fillmyfile/engine/preview_engine.py +48 -0
- fillmyfile-0.1.0/fillmyfile/engine/project_engine.py +86 -0
- fillmyfile-0.1.0/fillmyfile/engine/recents_engine.py +51 -0
- fillmyfile-0.1.0/fillmyfile/engine/search_engine.py +36 -0
- fillmyfile-0.1.0/fillmyfile/engine/snippet_engine.py +133 -0
- fillmyfile-0.1.0/fillmyfile/engine/statistics_engine.py +44 -0
- fillmyfile-0.1.0/fillmyfile/engine/template_creator.py +99 -0
- fillmyfile-0.1.0/fillmyfile/engine/template_deleter.py +61 -0
- fillmyfile-0.1.0/fillmyfile/engine/template_editor.py +27 -0
- fillmyfile-0.1.0/fillmyfile/engine/template_exporter.py +47 -0
- fillmyfile-0.1.0/fillmyfile/engine/template_importer.py +19 -0
- fillmyfile-0.1.0/fillmyfile/engine/variable_engine.py +6 -0
- fillmyfile-0.1.0/fillmyfile/engine/variable_prompt_engine.py +26 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/click-cli-app/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/click-cli-app/template/README.md +3 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/click-cli-app/template/pyproject.toml +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/click-cli-app/template/src/{{package_name}}/__init__.py +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/click-cli-app/template/src/{{package_name}}/main.py +15 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/fastapi-service/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/fastapi-service/template/README.md +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/fastapi-service/template/app/__init__.py +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/fastapi-service/template/app/main.py +8 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/fastapi-service/template/requirements.txt +2 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/pytest-project/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/pytest-project/template/pyproject.toml +10 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/pytest-project/template/tests/test_smoke.py +2 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-module/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-module/template/README.md +63 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-module/template/pyproject.toml +17 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-module/template/src/{{package_name}}/__init__.py +5 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-module/template/tests/test_hello.py +19 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-package/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-package/template/README.md +3 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-package/template/pyproject.toml +10 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/python-package/template/src/{{package_name}}/__init__.py +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/sqlite-cli-tool/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/sqlite-cli-tool/template/main.py +40 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/sqlite-cli-tool/template/requirements.txt +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/textual-tui/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/textual-tui/template/app.py +15 -0
- fillmyfile-0.1.0/fillmyfile/templates/projects/textual-tui/template/requirements.txt +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/ambulance-distance-time-fuel/meta.json +12 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/ambulance-distance-time-fuel/template.py +54 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/anime-file-menu/meta.json +12 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/anime-file-menu/template.py +101 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/argparse-cli/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/argparse-cli/template.py +17 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/bfs-graph/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/bfs-graph/template.py +18 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/binary-file-stack/meta.json +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/binary-file-stack/template.py +263 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/binary-search/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/binary-search/template.py +16 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/book-stack-manager/meta.json +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/book-stack-manager/template.py +182 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/bubble-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/bubble-sort/template.py +15 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/bucket-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/bucket-sort/template.py +22 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/chudnovsky-pi/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/chudnovsky-pi/template.py +28 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/click-command/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/click-command/template.py +16 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/counting-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/counting-sort/template.py +17 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/decimal-to-binary-stack/meta.json +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/decimal-to-binary-stack/tenplate.py +126 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/dfs-graph/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/dfs-graph/template.py +16 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/dijkstra/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/dijkstra/template.py +21 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/edit-distance/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/edit-distance/template.py +21 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/euclid-gcd/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/euclid-gcd/template.py +12 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/fastapi-route/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/fastapi-route/template.py +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/gamer-management-system/meta.json +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/gamer-management-system/template.py +516 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/heap-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/heap-sort/template.py +8 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/insertion-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/insertion-sort/template.py +14 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/kadane/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/kadane/template.py +12 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/kmp-search/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/kmp-search/template.py +39 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/lcs/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/lcs/template.py +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/logger/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/logger/template.py +8 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/lru-cache/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/lru-cache/template.py +9 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/merge-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/merge-sort/template.py +25 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/pathlib-json/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/pathlib-json/template.py +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/pydantic-model/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/pydantic-model/template.py +9 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/pytest-test/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/pytest-test/template.py +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/quick-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/quick-sort/template.py +12 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/radix-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/radix-sort/template.py +21 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/remove-position-character/meta.json +11 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/remove-position-character/template.py +18 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/requests-call/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/requests-call/template.py +9 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/rich-table/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/rich-table/template.py +18 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/selection-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/selection-sort/template.py +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/shell-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/shell-sort/template.py +18 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/sieve-primes/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/sieve-primes/template.py +14 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/sliding-window/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/sliding-window/template.py +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/smallest-digit-number/meta.json +11 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/smallest-digit-number/template.py +22 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/techfest-pass-manager/meta.json +13 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/techfest-pass-manager/template.py +616 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/textual-app/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/textual-app/template.py +17 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/top-k-heap/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/top-k-heap/template.py +8 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/topological-sort/meta.json +1 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/topological-sort/template.py +27 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/trie/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/trie/template.py +39 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/two-pointers/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/two-pointers/template.py +16 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/union-find/meta.json +7 -0
- fillmyfile-0.1.0/fillmyfile/templates/snippets/union-find/template.py +27 -0
- fillmyfile-0.1.0/fillmyfile/tui/__init__.py +0 -0
- fillmyfile-0.1.0/fillmyfile/tui/app.py +358 -0
- fillmyfile-0.1.0/fillmyfile/tui/preview_panel.py +21 -0
- fillmyfile-0.1.0/fillmyfile/tui/sidebar.py +38 -0
- fillmyfile-0.1.0/fillmyfile/tui/status_bar.py +8 -0
- fillmyfile-0.1.0/fillmyfile/tui/theme.py +46 -0
- fillmyfile-0.1.0/fillmyfile.egg-info/PKG-INFO +116 -0
- fillmyfile-0.1.0/fillmyfile.egg-info/SOURCES.txt +165 -0
- fillmyfile-0.1.0/fillmyfile.egg-info/dependency_links.txt +1 -0
- fillmyfile-0.1.0/fillmyfile.egg-info/entry_points.txt +2 -0
- fillmyfile-0.1.0/fillmyfile.egg-info/requires.txt +7 -0
- fillmyfile-0.1.0/fillmyfile.egg-info/top_level.txt +1 -0
- fillmyfile-0.1.0/pyproject.toml +51 -0
- fillmyfile-0.1.0/setup.cfg +4 -0
fillmyfile-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vishnu. Made with Python.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fillmyfile
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Offline developer snippet and project engine
|
|
5
|
+
Author: Vishnu
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: snippets,templates,cli,tui,developer-tools
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
18
|
+
Classifier: Topic :: Utilities
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: click
|
|
23
|
+
Requires-Dist: rich
|
|
24
|
+
Requires-Dist: jinja2
|
|
25
|
+
Requires-Dist: rapidfuzz
|
|
26
|
+
Requires-Dist: pyperclip
|
|
27
|
+
Requires-Dist: textual
|
|
28
|
+
Requires-Dist: platformdirs
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# FillMyFile
|
|
32
|
+
|
|
33
|
+
FillMyFile is an offline snippet and project-template manager for developers.
|
|
34
|
+
It lets you save reusable code snippets, create projects from local templates,
|
|
35
|
+
search them from the CLI or TUI, and share libraries as zip packs.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install fillmyfile
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For local development:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install -e .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
fillmyfile init
|
|
53
|
+
fillmyfile list
|
|
54
|
+
fillmyfile search logger
|
|
55
|
+
fillmyfile use logger ./scratch.py
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Add Your Own Snippets
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
fillmyfile add snippet click-command ./command.py \
|
|
62
|
+
--description "Click command skeleton" \
|
|
63
|
+
--category python \
|
|
64
|
+
--tags cli,click
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Project templates work the same way:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
fillmyfile add project fastapi-service ./my-fastapi-folder \
|
|
71
|
+
--description "FastAPI service starter" \
|
|
72
|
+
--category web \
|
|
73
|
+
--tags fastapi,api
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Share Packs
|
|
77
|
+
|
|
78
|
+
Install a pack folder:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
fillmyfile pack install ./my-pack
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Export your local library:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
fillmyfile pack export my-team-pack
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Useful Commands
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
fillmyfile init
|
|
94
|
+
fillmyfile list --type snippet
|
|
95
|
+
fillmyfile list --type project
|
|
96
|
+
fillmyfile search auth
|
|
97
|
+
fillmyfile dbsearch api
|
|
98
|
+
fillmyfile info logger
|
|
99
|
+
fillmyfile use logger ./app.py
|
|
100
|
+
fillmyfile create click-cli-app my-tool
|
|
101
|
+
fillmyfile export logger
|
|
102
|
+
fillmyfile import ./logger.zip
|
|
103
|
+
fillmyfile tui ./app.py
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Where Data Lives
|
|
107
|
+
|
|
108
|
+
FillMyFile keeps user snippets, projects, packs, and its SQLite index in the
|
|
109
|
+
operating system's user data directory. The installed Python package stays
|
|
110
|
+
read-only and safe to upgrade.
|
|
111
|
+
|
|
112
|
+
## License & Credits
|
|
113
|
+
|
|
114
|
+
© 2026 Vishnu. Made with Python.
|
|
115
|
+
Licensed under the [MIT License](LICENSE).
|
|
116
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# FillMyFile
|
|
2
|
+
|
|
3
|
+
FillMyFile is an offline snippet and project-template manager for developers.
|
|
4
|
+
It lets you save reusable code snippets, create projects from local templates,
|
|
5
|
+
search them from the CLI or TUI, and share libraries as zip packs.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install fillmyfile
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For local development:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install -e .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
fillmyfile init
|
|
23
|
+
fillmyfile list
|
|
24
|
+
fillmyfile search logger
|
|
25
|
+
fillmyfile use logger ./scratch.py
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Add Your Own Snippets
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
fillmyfile add snippet click-command ./command.py \
|
|
32
|
+
--description "Click command skeleton" \
|
|
33
|
+
--category python \
|
|
34
|
+
--tags cli,click
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Project templates work the same way:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
fillmyfile add project fastapi-service ./my-fastapi-folder \
|
|
41
|
+
--description "FastAPI service starter" \
|
|
42
|
+
--category web \
|
|
43
|
+
--tags fastapi,api
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Share Packs
|
|
47
|
+
|
|
48
|
+
Install a pack folder:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
fillmyfile pack install ./my-pack
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Export your local library:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
fillmyfile pack export my-team-pack
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Useful Commands
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
fillmyfile init
|
|
64
|
+
fillmyfile list --type snippet
|
|
65
|
+
fillmyfile list --type project
|
|
66
|
+
fillmyfile search auth
|
|
67
|
+
fillmyfile dbsearch api
|
|
68
|
+
fillmyfile info logger
|
|
69
|
+
fillmyfile use logger ./app.py
|
|
70
|
+
fillmyfile create click-cli-app my-tool
|
|
71
|
+
fillmyfile export logger
|
|
72
|
+
fillmyfile import ./logger.zip
|
|
73
|
+
fillmyfile tui ./app.py
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Where Data Lives
|
|
77
|
+
|
|
78
|
+
FillMyFile keeps user snippets, projects, packs, and its SQLite index in the
|
|
79
|
+
operating system's user data directory. The installed Python package stays
|
|
80
|
+
read-only and safe to upgrade.
|
|
81
|
+
|
|
82
|
+
## License & Credits
|
|
83
|
+
|
|
84
|
+
© 2026 Vishnu. Made with Python.
|
|
85
|
+
Licensed under the [MIT License](LICENSE).
|
|
86
|
+
|
|
File without changes
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from rich import print
|
|
3
|
+
|
|
4
|
+
from fillmyfile.engine.database_engine import DatabaseEngine
|
|
5
|
+
from fillmyfile.engine.db_search_engine import DBSearchEngine
|
|
6
|
+
from fillmyfile.engine.favorites_engine import FavoritesEngine
|
|
7
|
+
from fillmyfile.engine.file_picker import FilePicker
|
|
8
|
+
from fillmyfile.engine.indexer_engine import IndexerEngine
|
|
9
|
+
from fillmyfile.engine.installer import Installer
|
|
10
|
+
from fillmyfile.engine.metadata_engine import MetadataEngine
|
|
11
|
+
from fillmyfile.engine.pack_manager import PackManager
|
|
12
|
+
from fillmyfile.engine.paths import (
|
|
13
|
+
DATA_DIR,
|
|
14
|
+
PROJECTS_DIR,
|
|
15
|
+
SNIPPETS_DIR,
|
|
16
|
+
copy_starter_templates,
|
|
17
|
+
ensure_app_dirs,
|
|
18
|
+
)
|
|
19
|
+
from fillmyfile.engine.project_engine import ProjectEngine
|
|
20
|
+
from fillmyfile.engine.recents_engine import RecentsEngine
|
|
21
|
+
from fillmyfile.engine.search_engine import SearchEngine
|
|
22
|
+
from fillmyfile.engine.snippet_engine import SnippetEngine
|
|
23
|
+
from fillmyfile.engine.statistics_engine import StatisticsEngine
|
|
24
|
+
from fillmyfile.engine.template_creator import TemplateCreator
|
|
25
|
+
from fillmyfile.engine.template_deleter import TemplateDeleter
|
|
26
|
+
from fillmyfile.engine.template_editor import TemplateEditor
|
|
27
|
+
from fillmyfile.engine.template_exporter import TemplateExporter
|
|
28
|
+
from fillmyfile.engine.template_importer import TemplateImporter
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def bootstrap(seed=False, force_seed=False):
|
|
32
|
+
ensure_app_dirs()
|
|
33
|
+
DatabaseEngine.initialize()
|
|
34
|
+
|
|
35
|
+
library_is_empty = not any(SNIPPETS_DIR.iterdir()) and not any(
|
|
36
|
+
PROJECTS_DIR.iterdir()
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if seed or library_is_empty:
|
|
40
|
+
copy_starter_templates(force_seed)
|
|
41
|
+
else:
|
|
42
|
+
copy_starter_templates(False)
|
|
43
|
+
|
|
44
|
+
IndexerEngine.rebuild_index()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def parse_tags(tags):
|
|
48
|
+
return [
|
|
49
|
+
tag.strip()
|
|
50
|
+
for tag in tags.split(",")
|
|
51
|
+
if tag.strip()
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@click.group()
|
|
56
|
+
def cli():
|
|
57
|
+
"""Offline snippet and project template manager."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@cli.command()
|
|
61
|
+
@click.option("--force", is_flag=True, help="Overwrite bundled starter templates.")
|
|
62
|
+
def init(force):
|
|
63
|
+
"""Create the FillMyFile library and seed starter templates."""
|
|
64
|
+
|
|
65
|
+
bootstrap(seed=True, force_seed=force)
|
|
66
|
+
print(f"[green]FillMyFile is ready at {DATA_DIR}[/green]")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@cli.command("list")
|
|
70
|
+
@click.option(
|
|
71
|
+
"--type",
|
|
72
|
+
"template_type",
|
|
73
|
+
type=click.Choice(["snippet", "project"]),
|
|
74
|
+
default="snippet",
|
|
75
|
+
)
|
|
76
|
+
def list_templates(template_type):
|
|
77
|
+
"""List templates in the local library."""
|
|
78
|
+
|
|
79
|
+
bootstrap()
|
|
80
|
+
|
|
81
|
+
if template_type == "snippet":
|
|
82
|
+
items = SnippetEngine.list_snippets()
|
|
83
|
+
else:
|
|
84
|
+
items = [
|
|
85
|
+
item["name"]
|
|
86
|
+
for item in MetadataEngine.load_all_metadata("project")
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
print(f"\n[bold white]Available {template_type.title()}s[/bold white]\n")
|
|
90
|
+
|
|
91
|
+
for item in items:
|
|
92
|
+
print(f"- {item}")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@cli.command()
|
|
96
|
+
@click.argument("name")
|
|
97
|
+
@click.argument("target")
|
|
98
|
+
def use(name, target):
|
|
99
|
+
"""Render a snippet into a target file."""
|
|
100
|
+
|
|
101
|
+
bootstrap()
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
SnippetEngine.insert_snippet(name, target)
|
|
105
|
+
print(f"[green]Inserted '{name}' into {target}[/green]")
|
|
106
|
+
except Exception as error:
|
|
107
|
+
print(f"[red]{error}[/red]")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@cli.command()
|
|
111
|
+
@click.argument("template")
|
|
112
|
+
@click.argument("project_name")
|
|
113
|
+
@click.option(
|
|
114
|
+
"--install/--no-install",
|
|
115
|
+
default=False,
|
|
116
|
+
help="Install requirements.txt after creating the project.",
|
|
117
|
+
)
|
|
118
|
+
def create(template, project_name, install):
|
|
119
|
+
"""Create a project from a saved project template."""
|
|
120
|
+
|
|
121
|
+
bootstrap()
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
project_path = ProjectEngine.create_project(template, project_name)
|
|
125
|
+
|
|
126
|
+
if install:
|
|
127
|
+
Installer.install_requirements(project_path)
|
|
128
|
+
|
|
129
|
+
print(f"[green]Project '{project_name}' created at {project_path}[/green]")
|
|
130
|
+
except Exception as error:
|
|
131
|
+
print(f"[red]{error}[/red]")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@cli.command()
|
|
135
|
+
@click.argument("query")
|
|
136
|
+
@click.option(
|
|
137
|
+
"--type",
|
|
138
|
+
"template_type",
|
|
139
|
+
type=click.Choice(["snippet", "project"]),
|
|
140
|
+
default=None,
|
|
141
|
+
)
|
|
142
|
+
def search(query, template_type):
|
|
143
|
+
"""Search templates from metadata files."""
|
|
144
|
+
|
|
145
|
+
bootstrap()
|
|
146
|
+
results = SearchEngine.search(query, template_type)
|
|
147
|
+
|
|
148
|
+
print(f"\n[bold white]Results for '{query}'[/bold white]\n")
|
|
149
|
+
|
|
150
|
+
if not results:
|
|
151
|
+
print("[red]No results found[/red]")
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
for result in results:
|
|
155
|
+
print(f"- {result['name']} [white]({result['category']})[/white]")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@cli.command()
|
|
159
|
+
@click.argument("query")
|
|
160
|
+
@click.option(
|
|
161
|
+
"--type",
|
|
162
|
+
"template_type",
|
|
163
|
+
type=click.Choice(["snippet", "project"]),
|
|
164
|
+
default=None,
|
|
165
|
+
)
|
|
166
|
+
def dbsearch(query, template_type):
|
|
167
|
+
"""Search templates from the local SQLite index."""
|
|
168
|
+
|
|
169
|
+
bootstrap()
|
|
170
|
+
results = DBSearchEngine.search(query, template_type)
|
|
171
|
+
|
|
172
|
+
print(f"\n[bold white]Database Results for '{query}'[/bold white]\n")
|
|
173
|
+
|
|
174
|
+
if not results:
|
|
175
|
+
print("[red]No results found[/red]")
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
for result in results:
|
|
179
|
+
print(f"- {result['name']} [white]({result['category']})[/white]")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@cli.command()
|
|
183
|
+
@click.argument("name")
|
|
184
|
+
def info(name):
|
|
185
|
+
"""Show metadata for one template."""
|
|
186
|
+
|
|
187
|
+
bootstrap()
|
|
188
|
+
templates = MetadataEngine.load_all_metadata()
|
|
189
|
+
|
|
190
|
+
for template in templates:
|
|
191
|
+
if template["name"] == name:
|
|
192
|
+
print()
|
|
193
|
+
print(f"[bold white]{template['name']}[/bold white]")
|
|
194
|
+
print(f"[white]Type:[/white] {template.get('type', '')}")
|
|
195
|
+
print(f"[white]Category:[/white] {template.get('category', '')}")
|
|
196
|
+
print(f"[white]Description:[/white] {template.get('description', '')}")
|
|
197
|
+
print(f"[white]Tags:[/white] {', '.join(template.get('tags', []))}")
|
|
198
|
+
print()
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
print(f"[red]Template '{name}' not found[/red]")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@cli.command()
|
|
205
|
+
def index():
|
|
206
|
+
"""Rebuild the SQLite template index."""
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
bootstrap()
|
|
210
|
+
print("[green]Template index rebuilt successfully[/green]")
|
|
211
|
+
except Exception as error:
|
|
212
|
+
print(f"[red]{error}[/red]")
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@cli.group()
|
|
216
|
+
def add():
|
|
217
|
+
"""Add snippets or project templates to your library."""
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@add.command("snippet")
|
|
221
|
+
@click.argument("name")
|
|
222
|
+
@click.argument("source_file", required=False)
|
|
223
|
+
@click.option("--description", prompt=True)
|
|
224
|
+
@click.option("--category", prompt=True)
|
|
225
|
+
@click.option("--tags", prompt="Tags (comma separated)", default="")
|
|
226
|
+
def add_snippet(name, source_file, description, category, tags):
|
|
227
|
+
"""Add a snippet from a source file."""
|
|
228
|
+
|
|
229
|
+
bootstrap()
|
|
230
|
+
|
|
231
|
+
if not source_file:
|
|
232
|
+
print("Choose snippet file...")
|
|
233
|
+
source_file = FilePicker.pick_file()
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
TemplateCreator.create_snippet(
|
|
237
|
+
name,
|
|
238
|
+
source_file,
|
|
239
|
+
description,
|
|
240
|
+
category,
|
|
241
|
+
parse_tags(tags),
|
|
242
|
+
)
|
|
243
|
+
print(f"[green]Snippet '{name}' added[/green]")
|
|
244
|
+
except Exception as error:
|
|
245
|
+
print(f"[red]{error}[/red]")
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
@add.command("project")
|
|
249
|
+
@click.argument("name")
|
|
250
|
+
@click.argument("source_folder", required=False)
|
|
251
|
+
@click.option("--description", prompt=True)
|
|
252
|
+
@click.option("--category", prompt=True)
|
|
253
|
+
@click.option("--tags", prompt="Tags (comma separated)", default="")
|
|
254
|
+
def add_project(name, source_folder, description, category, tags):
|
|
255
|
+
"""Add a project template from a folder."""
|
|
256
|
+
|
|
257
|
+
bootstrap()
|
|
258
|
+
|
|
259
|
+
if not source_folder:
|
|
260
|
+
print("Choose project folder...")
|
|
261
|
+
source_folder = FilePicker.pick_folder()
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
TemplateCreator.create_project(
|
|
265
|
+
name,
|
|
266
|
+
source_folder,
|
|
267
|
+
description,
|
|
268
|
+
category,
|
|
269
|
+
parse_tags(tags),
|
|
270
|
+
)
|
|
271
|
+
print(f"[green]Project template '{name}' added[/green]")
|
|
272
|
+
except Exception as error:
|
|
273
|
+
print(f"[red]{error}[/red]")
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@cli.group()
|
|
277
|
+
def new():
|
|
278
|
+
"""Backward-compatible alias for add."""
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
new.add_command(add_snippet, "snippet")
|
|
282
|
+
new.add_command(add_project, "project")
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@cli.command()
|
|
286
|
+
@click.argument("name")
|
|
287
|
+
def remove(name):
|
|
288
|
+
"""Remove a template from the local library."""
|
|
289
|
+
|
|
290
|
+
bootstrap()
|
|
291
|
+
|
|
292
|
+
try:
|
|
293
|
+
if TemplateDeleter.delete(name):
|
|
294
|
+
print(f"[green]Removed '{name}'[/green]")
|
|
295
|
+
else:
|
|
296
|
+
print(f"[red]Template '{name}' not found[/red]")
|
|
297
|
+
except Exception as error:
|
|
298
|
+
print(f"[red]{error}[/red]")
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@cli.command()
|
|
302
|
+
@click.argument("name")
|
|
303
|
+
def edit(name):
|
|
304
|
+
"""Open a template folder in the OS file browser."""
|
|
305
|
+
|
|
306
|
+
bootstrap()
|
|
307
|
+
|
|
308
|
+
if not TemplateEditor.edit(name):
|
|
309
|
+
print(f"[red]Template '{name}' not found[/red]")
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
@cli.command("export")
|
|
313
|
+
@click.argument("name")
|
|
314
|
+
@click.option("--destination", default=None, help="Folder for the exported zip.")
|
|
315
|
+
def export_template(name, destination):
|
|
316
|
+
"""Export one template as a zip file."""
|
|
317
|
+
|
|
318
|
+
bootstrap()
|
|
319
|
+
|
|
320
|
+
try:
|
|
321
|
+
archive = TemplateExporter.export(name, destination)
|
|
322
|
+
if archive:
|
|
323
|
+
print(f"[green]Exported to {archive}[/green]")
|
|
324
|
+
else:
|
|
325
|
+
print(f"[red]Template '{name}' not found[/red]")
|
|
326
|
+
except Exception as error:
|
|
327
|
+
print(f"[red]{error}[/red]")
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@cli.command("import")
|
|
331
|
+
@click.argument("zip_path")
|
|
332
|
+
def import_template(zip_path):
|
|
333
|
+
"""Import a template or pack zip."""
|
|
334
|
+
|
|
335
|
+
bootstrap()
|
|
336
|
+
|
|
337
|
+
try:
|
|
338
|
+
TemplateImporter.import_zip(zip_path)
|
|
339
|
+
print("[green]Import complete[/green]")
|
|
340
|
+
except Exception as error:
|
|
341
|
+
print(f"[red]{error}[/red]")
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
@cli.group()
|
|
345
|
+
def pack():
|
|
346
|
+
"""Install or export snippet packs."""
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@pack.command("install")
|
|
350
|
+
@click.argument("folder_path")
|
|
351
|
+
def pack_install(folder_path):
|
|
352
|
+
"""Install a pack folder containing snippets/ and/or projects/."""
|
|
353
|
+
|
|
354
|
+
bootstrap()
|
|
355
|
+
|
|
356
|
+
try:
|
|
357
|
+
PackManager.install_pack(folder_path)
|
|
358
|
+
print("[green]Pack installed[/green]")
|
|
359
|
+
except Exception as error:
|
|
360
|
+
print(f"[red]{error}[/red]")
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@pack.command("export")
|
|
364
|
+
@click.argument("name", default="fillmyfile-pack")
|
|
365
|
+
@click.option("--destination", default=None, help="Folder for the exported pack zip.")
|
|
366
|
+
def pack_export(name, destination):
|
|
367
|
+
"""Export the whole local library as a pack zip."""
|
|
368
|
+
|
|
369
|
+
bootstrap()
|
|
370
|
+
|
|
371
|
+
try:
|
|
372
|
+
archive = PackManager.export_pack(name, destination)
|
|
373
|
+
print(f"[green]Exported pack to {archive}[/green]")
|
|
374
|
+
except Exception as error:
|
|
375
|
+
print(f"[red]{error}[/red]")
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@cli.command()
|
|
379
|
+
@click.argument("name")
|
|
380
|
+
def favorite(name):
|
|
381
|
+
"""Mark a template as a favorite."""
|
|
382
|
+
|
|
383
|
+
bootstrap()
|
|
384
|
+
FavoritesEngine.add(name)
|
|
385
|
+
FavoritesEngine.mark(name, True)
|
|
386
|
+
print(f"[green]'{name}' added to favorites[/green]")
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
@cli.command()
|
|
390
|
+
def recent():
|
|
391
|
+
"""Show recently used snippets."""
|
|
392
|
+
|
|
393
|
+
bootstrap()
|
|
394
|
+
items = RecentsEngine.get_recent()
|
|
395
|
+
|
|
396
|
+
print("\n[bold white]Recent Templates[/bold white]\n")
|
|
397
|
+
|
|
398
|
+
for item in items:
|
|
399
|
+
print(f"- {item}")
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
@cli.command()
|
|
403
|
+
def top():
|
|
404
|
+
"""Show most-used snippets."""
|
|
405
|
+
|
|
406
|
+
bootstrap()
|
|
407
|
+
rows = StatisticsEngine.get_top_used()
|
|
408
|
+
|
|
409
|
+
print("\n[bold white]Top Used Templates[/bold white]\n")
|
|
410
|
+
|
|
411
|
+
for row in rows:
|
|
412
|
+
print(f"- {row[0]} ({row[1]} uses)")
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
@cli.command()
|
|
416
|
+
@click.argument("target_file", required=False)
|
|
417
|
+
def tui(target_file):
|
|
418
|
+
"""Launch the terminal UI."""
|
|
419
|
+
|
|
420
|
+
bootstrap()
|
|
421
|
+
|
|
422
|
+
from fillmyfile.tui.app import FillMyFileApp
|
|
423
|
+
|
|
424
|
+
app = FillMyFileApp(target_file)
|
|
425
|
+
app.run()
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
if __name__ == "__main__":
|
|
429
|
+
cli()
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from fillmyfile.engine.database_engine import DatabaseEngine
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CategoryEngine:
|
|
5
|
+
|
|
6
|
+
@staticmethod
|
|
7
|
+
def get_categories(template_type=None):
|
|
8
|
+
|
|
9
|
+
conn = DatabaseEngine.connect()
|
|
10
|
+
cursor = conn.cursor()
|
|
11
|
+
|
|
12
|
+
cursor.execute(
|
|
13
|
+
"""
|
|
14
|
+
SELECT DISTINCT category
|
|
15
|
+
FROM templates
|
|
16
|
+
WHERE (? IS NULL OR type = ?)
|
|
17
|
+
"""
|
|
18
|
+
,
|
|
19
|
+
(template_type, template_type)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
rows = cursor.fetchall()
|
|
23
|
+
|
|
24
|
+
conn.close()
|
|
25
|
+
|
|
26
|
+
return sorted(
|
|
27
|
+
[row[0] for row in rows if row[0]]
|
|
28
|
+
)
|