directory-tree-printer 0.4.1__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.
- directory_tree_printer-0.4.1.dist-info/METADATA +340 -0
- directory_tree_printer-0.4.1.dist-info/RECORD +17 -0
- directory_tree_printer-0.4.1.dist-info/WHEEL +5 -0
- directory_tree_printer-0.4.1.dist-info/entry_points.txt +3 -0
- directory_tree_printer-0.4.1.dist-info/licenses/LICENSE +21 -0
- directory_tree_printer-0.4.1.dist-info/scm_file_list.json +27 -0
- directory_tree_printer-0.4.1.dist-info/scm_version.json +8 -0
- directory_tree_printer-0.4.1.dist-info/top_level.txt +1 -0
- tree_printer/__init__.py +8 -0
- tree_printer/cli.py +145 -0
- tree_printer/config.py +16 -0
- tree_printer/file_types.py +19 -0
- tree_printer/formatter.py +86 -0
- tree_printer/icons.py +21 -0
- tree_printer/models.py +8 -0
- tree_printer/printer.py +129 -0
- tree_printer/themes.py +154 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: directory-tree-printer
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: A Python CLI tool for generating clean directory tree structures.
|
|
5
|
+
Author: AmirmasoudCS
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AmirmasoudCS/Tree-Printer
|
|
8
|
+
Project-URL: Repository, https://github.com/AmirmasoudCS/Tree-Printer
|
|
9
|
+
Project-URL: Issues, https://github.com/AmirmasoudCS/Tree-Printer/issues
|
|
10
|
+
Keywords: tree,cli,directory,filesystem,terminal
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: pathspec
|
|
21
|
+
Requires-Dist: rich
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
26
|
+
Requires-Dist: twine; extra == "dev"
|
|
27
|
+
Requires-Dist: setuptools-scm[toml]>=8; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ๐ฒ Tree Printer
|
|
32
|
+
|
|
33
|
+
[](https://github.com/AmirmasoudCS/Tree-Printer/releases)
|
|
34
|
+
[](https://github.com/AmirmasoudCS/Tree-Printer/actions/workflows/tests.yml)
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
[](https://www.python.org/)
|
|
37
|
+
|
|
38
|
+
A lightweight and customizable command-line utility for generating beautiful directory tree structures directly from your terminal.
|
|
39
|
+
|
|
40
|
+
Tree Printer makes it easy to visualize project layouts, document repositories, create examples for documentation, and inspect filesystem structures with optional icons, metadata, filtering, sorting, and color themes.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## โจ Features
|
|
45
|
+
|
|
46
|
+
- ๐ณ Generate recursive directory trees
|
|
47
|
+
- ๐ Display directories only
|
|
48
|
+
- ๐๏ธ Show or hide hidden files
|
|
49
|
+
- ๐ซ Exclude files, directories, or file extensions
|
|
50
|
+
- ๐ Limit recursion depth
|
|
51
|
+
- ๐ค Sort entries by:
|
|
52
|
+
- Name
|
|
53
|
+
- Size
|
|
54
|
+
- Last modified date
|
|
55
|
+
- ๐ Display file size
|
|
56
|
+
- ๐ Display modification timestamps
|
|
57
|
+
- ๐จ Multiple color themes
|
|
58
|
+
- ๐ผ๏ธ Optional file and folder icons
|
|
59
|
+
- ๐ Export output to text files
|
|
60
|
+
- ๐ซ Respect `.gitignore`
|
|
61
|
+
- โก Fast and lightweight
|
|
62
|
+
- ๐งช Fully tested with pytest
|
|
63
|
+
- ๐ Continuous Integration using GitHub Actions
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## ๐ฆ Installation
|
|
68
|
+
|
|
69
|
+
### From PyPI (Recommended)
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install directory-tree-printer
|
|
73
|
+
````
|
|
74
|
+
|
|
75
|
+
### From source
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
git clone https://github.com/AmirmasoudCS/Tree-Printer.git
|
|
79
|
+
|
|
80
|
+
cd Tree-Printer
|
|
81
|
+
|
|
82
|
+
pip install .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## ๐ Quick Start
|
|
88
|
+
|
|
89
|
+
Print the current directory
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
tp .
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Print another directory
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
tp path/to/project
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Print only directories
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
tp --dirs-only
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Show icons
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
tp --icons
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Show file sizes
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
tp --size
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Limit depth
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
tp --max-depth 2
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Save output
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
tp --output tree.txt
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## ๐ Examples
|
|
134
|
+
|
|
135
|
+
### Basic
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
tp .
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
project
|
|
143
|
+
โโโ src
|
|
144
|
+
โ โโโ main.py
|
|
145
|
+
โ โโโ utils.py
|
|
146
|
+
โโโ README.md
|
|
147
|
+
โโโ pyproject.toml
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### Icons
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
tp --icons
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
๐ project
|
|
160
|
+
โโโ ๐ src
|
|
161
|
+
โ โโโ ๐ main.py
|
|
162
|
+
โ โโโ ๐ utils.py
|
|
163
|
+
โโโ ๐ README.md
|
|
164
|
+
โโโ โ๏ธ pyproject.toml
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### File Sizes
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
tp --size
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
README.md (5.8 KB)
|
|
177
|
+
main.py (4.2 KB)
|
|
178
|
+
config.py (831 B)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### Modified Dates
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
tp --modified
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
README.md (2026-05-12 18:42)
|
|
191
|
+
main.py (2026-05-11 14:30)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### Themes
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
tp --theme sunset
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+

|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## โ๏ธ CLI Options
|
|
207
|
+
|
|
208
|
+
| Option | Alias | Description |
|
|
209
|
+
| -------------------- | ----- | ----------------------------------- |
|
|
210
|
+
| `--max-depth` | `-md` | Limit recursion depth |
|
|
211
|
+
| `--show-hidden` | `-sh` | Include hidden files |
|
|
212
|
+
| `--dirs-only` | `-do` | Show only directories |
|
|
213
|
+
| `--exclude-dirs` | `-ed` | Exclude directories |
|
|
214
|
+
| `--exclude-files` | `-ef` | Exclude files |
|
|
215
|
+
| `--exclude-suffixes` | `-es` | Exclude file extensions |
|
|
216
|
+
| `--sort` | `-st` | Sort by name, size or modified |
|
|
217
|
+
| `--size` | `-s` | Display file sizes |
|
|
218
|
+
| `--modified` | `-m` | Display modified dates |
|
|
219
|
+
| `--icons` | `-i` | Display icons |
|
|
220
|
+
| `--theme` | `-th` | Select a color theme |
|
|
221
|
+
| `--no-color` | `-nc` | Disable colored output |
|
|
222
|
+
| `--gitignore` | `-gi` | Ignore files listed in `.gitignore` |
|
|
223
|
+
| `--output` | `-o` | Write output to a file |
|
|
224
|
+
| `--version` | `-v` | Show installed version |
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## ๐งช Development
|
|
229
|
+
|
|
230
|
+
Clone the repository
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
git clone https://github.com/AmirmasoudCS/Tree-Printer.git
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Install development dependencies
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
pip install -e ".[dev]"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Run the test suite
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
pytest
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Run tests with coverage
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
pytest --cov=tree_printer --cov-report=term-missing
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Build the package
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
python -m build
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Verify the package
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
python -m twine check dist/*
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## ๐ Project Structure
|
|
269
|
+
|
|
270
|
+
```text
|
|
271
|
+
|
|
272
|
+
โโโ ๐ images
|
|
273
|
+
โ โโโ ๐ผ๏ธ themeImage1.png
|
|
274
|
+
โโโ ๐ tests
|
|
275
|
+
โ โโโ ๐ __init__.py
|
|
276
|
+
โ โโโ ๐ test_cli.py
|
|
277
|
+
โ โโโ ๐ test_formatter.py
|
|
278
|
+
โ โโโ ๐ test_printer.py
|
|
279
|
+
โโโ ๐ tree_printer
|
|
280
|
+
โ โโโ ๐ __init__.py
|
|
281
|
+
โ โโโ ๐ cli.py
|
|
282
|
+
โ โโโ ๐ config.py
|
|
283
|
+
โ โโโ ๐ file_types.py
|
|
284
|
+
โ โโโ ๐ formatter.py
|
|
285
|
+
โ โโโ ๐ icons.py
|
|
286
|
+
โ โโโ ๐ models.py
|
|
287
|
+
โ โโโ ๐ printer.py
|
|
288
|
+
โ โโโ ๐ themes.py
|
|
289
|
+
โโโ ๐ CHANGELOG.md
|
|
290
|
+
โโโ โ๏ธ LICENSE
|
|
291
|
+
โโโ ๐ main.py
|
|
292
|
+
โโโ โ๏ธ pyproject.toml
|
|
293
|
+
โโโ ๐ README.md
|
|
294
|
+
โโโ ๐ requirements-dev.txt
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## ๐ฃ๏ธ Roadmap
|
|
300
|
+
|
|
301
|
+
Future improvements include:
|
|
302
|
+
|
|
303
|
+
* Additional export formats
|
|
304
|
+
* Custom icon packs
|
|
305
|
+
* More color themes
|
|
306
|
+
* Configuration file support
|
|
307
|
+
* Improved Windows terminal support
|
|
308
|
+
* Performance improvements for very large directories
|
|
309
|
+
|
|
310
|
+
Suggestions and pull requests are always welcome.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## ๐ค Contributing
|
|
315
|
+
|
|
316
|
+
Contributions, feature requests, and bug reports are welcome.
|
|
317
|
+
|
|
318
|
+
If you'd like to contribute:
|
|
319
|
+
|
|
320
|
+
1. Fork the repository
|
|
321
|
+
2. Create a feature branch
|
|
322
|
+
3. Make your changes
|
|
323
|
+
4. Run the test suite
|
|
324
|
+
5. Submit a Pull Request
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## ๐ Changelog
|
|
329
|
+
|
|
330
|
+
See [CHANGELOG.md](CHANGELOG.md) for release history.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## โ๏ธ License
|
|
335
|
+
|
|
336
|
+
This project is licensed under the MIT License.
|
|
337
|
+
|
|
338
|
+
See [LICENSE](LICENSE) for details.
|
|
339
|
+
|
|
340
|
+
---
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
directory_tree_printer-0.4.1.dist-info/licenses/LICENSE,sha256=lk9TUL2BhgEyBqk8cIk99ySGEo_m1qLWqnRXWDulBi4,1067
|
|
2
|
+
tree_printer/__init__.py,sha256=vpM83YWnxWMxcoMv_LYyBKscx2FBtGIsVd6ap8gbDWI,169
|
|
3
|
+
tree_printer/cli.py,sha256=rxd5HCgpIV2JB7vNtsECNEykdxI7p0xtoR_ElR9AD5A,4039
|
|
4
|
+
tree_printer/config.py,sha256=Cs2QXo4fQC2_rbw7_-t5X9Yr_16puxqsfvTzIZfS5uA,227
|
|
5
|
+
tree_printer/file_types.py,sha256=a-nNISqJKX02ZDBCYK-gZIifmnLlNcMUF0UDwglEylc,391
|
|
6
|
+
tree_printer/formatter.py,sha256=tq1_BcL3G97IoGjcjE1w695rHqDh6_XWX9gGmXfhlww,3137
|
|
7
|
+
tree_printer/icons.py,sha256=0ir8PjHpaZowNFzucbnkuJmmGZ7CvD2hKtBhVn54ODA,444
|
|
8
|
+
tree_printer/models.py,sha256=c7Ovq3XEy5O5TFs5H02QcZgpw8UWUeshob5gEgLdhSI,226
|
|
9
|
+
tree_printer/printer.py,sha256=mm4Ebgiin7MOk-rwwSmar_TkTxMQJzvErhBaRw6P2R0,4717
|
|
10
|
+
tree_printer/themes.py,sha256=OmF5bisNZBpCOyxnU433Jq8s0s1RbxWGkUamqBpJYVE,4079
|
|
11
|
+
directory_tree_printer-0.4.1.dist-info/METADATA,sha256=biB9T6UHOkmtuUCK1DA8R-UATHA9P4z4ZZDjBG3qOmQ,6987
|
|
12
|
+
directory_tree_printer-0.4.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
13
|
+
directory_tree_printer-0.4.1.dist-info/entry_points.txt,sha256=KXraYIy_PcOWs4odhwXv4thpd5WBX6kaRPAeEwN77p0,80
|
|
14
|
+
directory_tree_printer-0.4.1.dist-info/scm_file_list.json,sha256=w4cBoWsO4LNe0V6zbkbUqT0rCusn_gnPWnkM7tL2-TA,643
|
|
15
|
+
directory_tree_printer-0.4.1.dist-info/scm_version.json,sha256=BZRbRlGczaDc5grvnF8kaFHL6d5NDoL9-jgRNyX1Yc0,160
|
|
16
|
+
directory_tree_printer-0.4.1.dist-info/top_level.txt,sha256=wjkoS3ajkA1yI03t4-VJyME4ba-4qkhp-8Rcek86x3w,13
|
|
17
|
+
directory_tree_printer-0.4.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amirmasoud
|
|
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.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": [
|
|
3
|
+
"README.md",
|
|
4
|
+
"LICENSE",
|
|
5
|
+
"pyproject.toml",
|
|
6
|
+
"CHANGELOG.md",
|
|
7
|
+
"main.py",
|
|
8
|
+
".gitignore",
|
|
9
|
+
"requirements-dev.txt",
|
|
10
|
+
"images/themeImage1.png",
|
|
11
|
+
"tree_printer/icons.py",
|
|
12
|
+
"tree_printer/formatter.py",
|
|
13
|
+
"tree_printer/__init__.py",
|
|
14
|
+
"tree_printer/config.py",
|
|
15
|
+
"tree_printer/models.py",
|
|
16
|
+
"tree_printer/themes.py",
|
|
17
|
+
"tree_printer/cli.py",
|
|
18
|
+
"tree_printer/printer.py",
|
|
19
|
+
"tree_printer/file_types.py",
|
|
20
|
+
"tests/__init__.py",
|
|
21
|
+
"tests/test_printer.py",
|
|
22
|
+
"tests/test_formatter.py",
|
|
23
|
+
"tests/test_cli.py",
|
|
24
|
+
".github/workflows/release.yml",
|
|
25
|
+
".github/workflows/tests.yml"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tree_printer
|
tree_printer/__init__.py
ADDED
tree_printer/cli.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
#from rich_argparse import RichHelpFormatter
|
|
3
|
+
from importlib.metadata import version
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from .themes import THEMES
|
|
6
|
+
__version__ = version("directory-tree-printer")
|
|
7
|
+
from .printer import TreePrinter
|
|
8
|
+
from .formatter import TreeFormatter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
12
|
+
parser = argparse.ArgumentParser(
|
|
13
|
+
description="Generate and print directory tree structures"
|
|
14
|
+
)
|
|
15
|
+
parser.add_argument(
|
|
16
|
+
"path",
|
|
17
|
+
nargs="?",
|
|
18
|
+
default=".",
|
|
19
|
+
help="Root directory to generate the tree on"
|
|
20
|
+
)
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"--max-depth",
|
|
23
|
+
"-md",
|
|
24
|
+
type=int,
|
|
25
|
+
default=None,
|
|
26
|
+
help="Maximum directory depth that will be generated"
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"--output",
|
|
30
|
+
"-o",
|
|
31
|
+
help = "Write tree output to a file instead of printing"
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--show-hidden",
|
|
35
|
+
"-sh",
|
|
36
|
+
action="store_true",
|
|
37
|
+
help="Include hidden files and directories"
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--dirs-only",
|
|
41
|
+
"-do",
|
|
42
|
+
action="store_true",
|
|
43
|
+
help="Show directories only"
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"--exclude-dirs",
|
|
47
|
+
"-ed",
|
|
48
|
+
nargs="+",
|
|
49
|
+
default=None,
|
|
50
|
+
help="Exclude directories by name"
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--exclude-files",
|
|
54
|
+
"-ef",
|
|
55
|
+
nargs="+",
|
|
56
|
+
default=None,
|
|
57
|
+
help="Exclude files by name"
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--exclude-suffixes",
|
|
61
|
+
"-es",
|
|
62
|
+
nargs="+",
|
|
63
|
+
default=None,
|
|
64
|
+
help="Exclude files by suffixes"
|
|
65
|
+
)
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
"--size",
|
|
68
|
+
"-s",
|
|
69
|
+
action="store_true",
|
|
70
|
+
help="Show file size"
|
|
71
|
+
)
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"--modified",
|
|
74
|
+
"-m",
|
|
75
|
+
action="store_true",
|
|
76
|
+
help="Show last modified time"
|
|
77
|
+
)
|
|
78
|
+
parser.add_argument(
|
|
79
|
+
"--icons",
|
|
80
|
+
"-i",
|
|
81
|
+
action="store_true",
|
|
82
|
+
help="Show icons next to files and directories"
|
|
83
|
+
)
|
|
84
|
+
parser.add_argument(
|
|
85
|
+
"--sort",
|
|
86
|
+
"-st",
|
|
87
|
+
choices=["name", "size", "modified"],
|
|
88
|
+
default = "name",
|
|
89
|
+
help = "Sort files by name, size or modified date"
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--version",
|
|
93
|
+
"-v",
|
|
94
|
+
action="version",
|
|
95
|
+
version=f"tree-printer {__version__}"
|
|
96
|
+
)
|
|
97
|
+
parser.add_argument(
|
|
98
|
+
"--theme",
|
|
99
|
+
"-th",
|
|
100
|
+
default="default",
|
|
101
|
+
choices=THEMES.keys(),
|
|
102
|
+
help = "Choose the color theme"
|
|
103
|
+
)
|
|
104
|
+
parser.add_argument(
|
|
105
|
+
"--no-color",
|
|
106
|
+
"-nc",
|
|
107
|
+
action="store_true",
|
|
108
|
+
help="Disable colored output"
|
|
109
|
+
)
|
|
110
|
+
parser.add_argument(
|
|
111
|
+
"--gitignore",
|
|
112
|
+
"-gi",
|
|
113
|
+
action="store_true",
|
|
114
|
+
help="Respect .gitignore file patterns"
|
|
115
|
+
)
|
|
116
|
+
return parser
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def run(argv: list[str] | None = None) -> None:
|
|
120
|
+
parser = build_parser()
|
|
121
|
+
args = parser.parse_args(argv)
|
|
122
|
+
printer = TreePrinter(
|
|
123
|
+
root_path=args.path,
|
|
124
|
+
show_hidden=args.show_hidden,
|
|
125
|
+
dirs_only=args.dirs_only,
|
|
126
|
+
exclude_dirs=args.exclude_dirs,
|
|
127
|
+
exclude_files=args.exclude_files,
|
|
128
|
+
exclude_suffixes=args.exclude_suffixes,
|
|
129
|
+
show_size=args.size,
|
|
130
|
+
show_modified=args.modified,
|
|
131
|
+
sort_by=args.sort,
|
|
132
|
+
use_gitignore=args.gitignore
|
|
133
|
+
)
|
|
134
|
+
formatter = TreeFormatter(show_icons=args.icons, theme_name=args.theme)
|
|
135
|
+
tree = printer.build_tree()
|
|
136
|
+
lines = formatter.format(tree, max_depth=args.max_depth)
|
|
137
|
+
if args.output:
|
|
138
|
+
text_lines = [line.plain for line in lines]
|
|
139
|
+
with open(args.output, "w", encoding="utf-8") as file:
|
|
140
|
+
file.write("\n".join(text_lines))
|
|
141
|
+
print(f"Tree written into {args.output}")
|
|
142
|
+
else:
|
|
143
|
+
console = Console(no_color=args.no_color)
|
|
144
|
+
for line in lines:
|
|
145
|
+
console.print(line)
|
tree_printer/config.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
FILE_STYLES = {
|
|
2
|
+
".py": "python",
|
|
3
|
+
".md": "markdown",
|
|
4
|
+
".json": "json",
|
|
5
|
+
".png": "image",
|
|
6
|
+
".jpg": "image",
|
|
7
|
+
".jpeg": "image",
|
|
8
|
+
".gif": "image",
|
|
9
|
+
".csv": "data",
|
|
10
|
+
".pdf": "document",
|
|
11
|
+
".zip": "archive",
|
|
12
|
+
".mp3": "audio",
|
|
13
|
+
".mp4": "video",
|
|
14
|
+
".html": "web",
|
|
15
|
+
".css": "web",
|
|
16
|
+
".js": "javascript",
|
|
17
|
+
".toml": "config",
|
|
18
|
+
}
|
|
19
|
+
DEFAULT_FILE_STYLE = "file"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from rich.text import Text
|
|
3
|
+
from .file_types import FILE_STYLES, DEFAULT_FILE_STYLE
|
|
4
|
+
from .themes import THEMES
|
|
5
|
+
from tree_printer.models import TreeNode
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List
|
|
8
|
+
from .icons import FILE_ICONS, DEFAULT_FILE_ICON
|
|
9
|
+
|
|
10
|
+
class TreeFormatter:
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
show_icons : bool = False,
|
|
14
|
+
theme_name : str = "default"
|
|
15
|
+
):
|
|
16
|
+
self.show_icons = show_icons
|
|
17
|
+
self.theme = THEMES.get(theme_name, THEMES["default"])
|
|
18
|
+
def format_metadata(self, node : TreeNode) -> Text:
|
|
19
|
+
style_key = self.get_style_key(node)
|
|
20
|
+
style = self.theme.get(style_key, "white")
|
|
21
|
+
label = f"{self.get_icon(node)}{node.name}"
|
|
22
|
+
text = Text(label, style=style)
|
|
23
|
+
metadata = []
|
|
24
|
+
if node.size is not None:
|
|
25
|
+
metadata.append(self.format_size(node.size))
|
|
26
|
+
if node.modified is not None:
|
|
27
|
+
formatted_date = datetime.fromtimestamp(node.modified).strftime("%Y-%m-%d %H:%M")
|
|
28
|
+
metadata.append(formatted_date)
|
|
29
|
+
if metadata:
|
|
30
|
+
text.append(f" ({' | '.join(metadata)})", style="dim")
|
|
31
|
+
return text
|
|
32
|
+
def format_size(self, size_in_bytes : int) -> str:
|
|
33
|
+
if size_in_bytes < 1024:
|
|
34
|
+
return f"{size_in_bytes} B"
|
|
35
|
+
units = ["KB", "MB", "GB", "TB", "PB"]
|
|
36
|
+
size = float(size_in_bytes)
|
|
37
|
+
for unit in units :
|
|
38
|
+
size/=1024
|
|
39
|
+
if size < 1024:
|
|
40
|
+
return f"{size:.1f} {unit}"
|
|
41
|
+
return f"{size:.1f} EB"
|
|
42
|
+
def format(
|
|
43
|
+
self,
|
|
44
|
+
node : TreeNode,
|
|
45
|
+
prefix : str = "",
|
|
46
|
+
depth : int = 0,
|
|
47
|
+
max_depth : int | None = None
|
|
48
|
+
) -> list[Text]:
|
|
49
|
+
if max_depth is not None and depth > max_depth:
|
|
50
|
+
return []
|
|
51
|
+
lines = []
|
|
52
|
+
if depth == 0 :
|
|
53
|
+
lines.append(self.format_metadata(node))
|
|
54
|
+
for index, child in enumerate(node.children):
|
|
55
|
+
is_last = index == len(node.children) - 1
|
|
56
|
+
connector = "โโโ " if is_last else "โโโ "
|
|
57
|
+
line = Text(prefix + connector)
|
|
58
|
+
line.append(self.format_metadata(child))
|
|
59
|
+
lines.append(line)
|
|
60
|
+
if child.is_dir:
|
|
61
|
+
extension = " " if is_last else "โ "
|
|
62
|
+
lines.extend(
|
|
63
|
+
self.format(
|
|
64
|
+
child,
|
|
65
|
+
prefix=prefix+extension,
|
|
66
|
+
depth=depth+1,
|
|
67
|
+
max_depth=max_depth
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
return lines
|
|
71
|
+
def get_icon(self, node : TreeNode) -> str :
|
|
72
|
+
if not self.show_icons:
|
|
73
|
+
return ""
|
|
74
|
+
if node.is_dir:
|
|
75
|
+
return "๐ "
|
|
76
|
+
name = node.name.lower()
|
|
77
|
+
if name == "license":
|
|
78
|
+
return "โ๏ธ "
|
|
79
|
+
suffix = Path(node.name).suffix.lower()
|
|
80
|
+
return FILE_ICONS.get(suffix, DEFAULT_FILE_ICON)
|
|
81
|
+
def get_style_key(self, node : TreeNode) -> str:
|
|
82
|
+
if node.is_dir:
|
|
83
|
+
return "folder"
|
|
84
|
+
suffix = Path(node.name).suffix.lower()
|
|
85
|
+
return FILE_STYLES.get(suffix, DEFAULT_FILE_STYLE)
|
|
86
|
+
|
tree_printer/icons.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
FILE_ICONS = {
|
|
2
|
+
".py" : "๐ ",
|
|
3
|
+
".md" : "๐ ",
|
|
4
|
+
".json": "๐งฉ ",
|
|
5
|
+
".ipynb": "๐ ",
|
|
6
|
+
".txt" : "๐ ",
|
|
7
|
+
".png": "๐ผ๏ธ ",
|
|
8
|
+
".jpg": "๐ผ๏ธ ",
|
|
9
|
+
".jpeg": "๐ผ๏ธ ",
|
|
10
|
+
".gif": "๐๏ธ ",
|
|
11
|
+
".csv": "๐ ",
|
|
12
|
+
".pdf": "๐ ",
|
|
13
|
+
".zip": "๐๏ธ ",
|
|
14
|
+
".mp3": "๐ต ",
|
|
15
|
+
".mp4": "๐ฌ ",
|
|
16
|
+
".html": "๐ ",
|
|
17
|
+
".css": "๐จ ",
|
|
18
|
+
".js": "โจ ",
|
|
19
|
+
".toml" : "โ๏ธ "
|
|
20
|
+
}
|
|
21
|
+
DEFAULT_FILE_ICON = "๐ "
|
tree_printer/models.py
ADDED
tree_printer/printer.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import pathspec
|
|
3
|
+
from .config import DEFAULT_EXCLUDE_DIRS
|
|
4
|
+
from .config import DEFAULT_EXCLUDE_FILES
|
|
5
|
+
from .config import DEFAULT_EXCLUDE_SUFFIXES
|
|
6
|
+
from .models import TreeNode
|
|
7
|
+
from .formatter import TreeFormatter
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
class TreePrinter:
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
root_path : str | Path = ".",
|
|
13
|
+
exclude_dirs : list[str] | None = None,
|
|
14
|
+
exclude_files : list[str] | None = None,
|
|
15
|
+
exclude_suffixes : list[str] | None = None,
|
|
16
|
+
show_hidden : bool = False,
|
|
17
|
+
dirs_only : bool = False,
|
|
18
|
+
show_size : bool = False,
|
|
19
|
+
show_modified : bool = False,
|
|
20
|
+
sort_by : str = "name",
|
|
21
|
+
use_gitignore : bool = False,
|
|
22
|
+
console: Console | None = None,
|
|
23
|
+
):
|
|
24
|
+
self.root = Path(root_path)
|
|
25
|
+
self.use_gitignore = use_gitignore
|
|
26
|
+
self.gitignore_spec = self.load_gitignore() if use_gitignore else None
|
|
27
|
+
self.show_hidden = show_hidden
|
|
28
|
+
self.dirs_only = dirs_only
|
|
29
|
+
self.show_size = show_size
|
|
30
|
+
self.show_modified = show_modified
|
|
31
|
+
self.sort_by = sort_by
|
|
32
|
+
|
|
33
|
+
self.exclude_dirs = (DEFAULT_EXCLUDE_DIRS if exclude_dirs is None else exclude_dirs)
|
|
34
|
+
self.exclude_files = (DEFAULT_EXCLUDE_FILES if exclude_files is None else exclude_files)
|
|
35
|
+
self.exclude_suffixes = (DEFAULT_EXCLUDE_SUFFIXES if exclude_suffixes is None else exclude_suffixes)
|
|
36
|
+
self.console = console or Console()
|
|
37
|
+
def should_exclude(self, path: Path) -> bool:
|
|
38
|
+
if path.is_dir() and path.name in self.exclude_dirs:
|
|
39
|
+
return True
|
|
40
|
+
if path.is_file() and path.name in self.exclude_files:
|
|
41
|
+
return True
|
|
42
|
+
if path.is_file() and path.suffix in self.exclude_suffixes:
|
|
43
|
+
return True
|
|
44
|
+
|
|
45
|
+
spec = getattr(self, "gitignore_spec", None)
|
|
46
|
+
if spec is not None:
|
|
47
|
+
try:
|
|
48
|
+
rel = path.relative_to(self.root)
|
|
49
|
+
except ValueError:
|
|
50
|
+
return False
|
|
51
|
+
rel_str = rel.as_posix()
|
|
52
|
+
if path.is_dir():
|
|
53
|
+
rel_str += "/"
|
|
54
|
+
if spec.match_file(rel_str):
|
|
55
|
+
return True
|
|
56
|
+
return False
|
|
57
|
+
def load_gitignore(self) -> pathspec.PathSpec | None:
|
|
58
|
+
gitignore_path = self.root/".gitignore"
|
|
59
|
+
if not gitignore_path.exists():
|
|
60
|
+
return None
|
|
61
|
+
try:
|
|
62
|
+
with open(gitignore_path, "r", encoding="utf-8") as f:
|
|
63
|
+
return pathspec.PathSpec.from_lines("gitignore", f.readlines()) # was "gitwildmatch"
|
|
64
|
+
except (OSError, UnicodeDecodeError):
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
def render(
|
|
68
|
+
self,
|
|
69
|
+
show_icons: bool = False,
|
|
70
|
+
theme_name: str = "default",
|
|
71
|
+
max_depth: int | None = None,
|
|
72
|
+
no_color: bool = False,
|
|
73
|
+
) -> None:
|
|
74
|
+
root = self.build_tree()
|
|
75
|
+
formatter = TreeFormatter(show_icons=show_icons, theme_name=theme_name)
|
|
76
|
+
lines = formatter.format(root, max_depth=max_depth)
|
|
77
|
+
for line in lines:
|
|
78
|
+
self.console.print(line)
|
|
79
|
+
def get_items(self, path: Path) -> list[Path]:
|
|
80
|
+
return sorted(
|
|
81
|
+
[
|
|
82
|
+
item
|
|
83
|
+
for item in path.iterdir()
|
|
84
|
+
if (
|
|
85
|
+
(self.show_hidden or not item.name.startswith("."))
|
|
86
|
+
and not self.should_exclude(item)
|
|
87
|
+
and (not self.dirs_only or item.is_dir())
|
|
88
|
+
)
|
|
89
|
+
],
|
|
90
|
+
key=self.sort_key
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def build_tree(self, path: Path | None = None) -> TreeNode:
|
|
94
|
+
path = path or self.root
|
|
95
|
+
size = None
|
|
96
|
+
modified = None
|
|
97
|
+
if self.show_size or self.show_modified:
|
|
98
|
+
stat = path.stat()
|
|
99
|
+
if self.show_size and path.is_file():
|
|
100
|
+
size = stat.st_size
|
|
101
|
+
if self.show_modified:
|
|
102
|
+
modified = stat.st_mtime
|
|
103
|
+
node = TreeNode(
|
|
104
|
+
name=path.name,
|
|
105
|
+
is_dir=path.is_dir(),
|
|
106
|
+
size=size,
|
|
107
|
+
modified=modified
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if path.is_dir():
|
|
111
|
+
for item in self.get_items(path):
|
|
112
|
+
child_node = self.build_tree(item)
|
|
113
|
+
node.children.append(child_node)
|
|
114
|
+
|
|
115
|
+
return node
|
|
116
|
+
def sort_key(self, path : Path):
|
|
117
|
+
if self.sort_by == "size":
|
|
118
|
+
try:
|
|
119
|
+
size = path.stat().st_size
|
|
120
|
+
except OSError:
|
|
121
|
+
size = 0
|
|
122
|
+
return (not path.is_dir(), -size, path.name.lower())
|
|
123
|
+
elif self.sort_by == "modified":
|
|
124
|
+
try:
|
|
125
|
+
mtime = path.stat().st_mtime
|
|
126
|
+
except OSError:
|
|
127
|
+
mtime = 0
|
|
128
|
+
return (not path.is_dir(), -mtime, path.name.lower())
|
|
129
|
+
return (not path.is_dir(), path.name.lower())
|
tree_printer/themes.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
THEMES = {
|
|
2
|
+
"default": {
|
|
3
|
+
"folder": "blue",
|
|
4
|
+
"file": "white",
|
|
5
|
+
"python": "yellow",
|
|
6
|
+
"markdown": "cyan",
|
|
7
|
+
"json": "bright_yellow",
|
|
8
|
+
"image": "magenta",
|
|
9
|
+
"data": "green",
|
|
10
|
+
"document": "red",
|
|
11
|
+
"archive": "bright_black",
|
|
12
|
+
"audio": "bright_green",
|
|
13
|
+
"video": "bright_magenta",
|
|
14
|
+
"web": "bright_blue",
|
|
15
|
+
"javascript": "yellow",
|
|
16
|
+
"config": "bright_cyan",
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
"github": {
|
|
20
|
+
"folder": "bright_blue",
|
|
21
|
+
"file": "white",
|
|
22
|
+
"python": "bright_yellow",
|
|
23
|
+
"markdown": "bright_white",
|
|
24
|
+
"json": "yellow",
|
|
25
|
+
"image": "bright_magenta",
|
|
26
|
+
"data": "bright_green",
|
|
27
|
+
"document": "white",
|
|
28
|
+
"archive": "bright_black",
|
|
29
|
+
"audio": "green",
|
|
30
|
+
"video": "magenta",
|
|
31
|
+
"web": "cyan",
|
|
32
|
+
"javascript": "yellow",
|
|
33
|
+
"config": "bright_cyan",
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
"dracula": {
|
|
37
|
+
"folder": "bright_magenta",
|
|
38
|
+
"file": "white",
|
|
39
|
+
"python": "yellow",
|
|
40
|
+
"markdown": "cyan",
|
|
41
|
+
"json": "bright_yellow",
|
|
42
|
+
"image": "magenta",
|
|
43
|
+
"data": "green",
|
|
44
|
+
"document": "bright_red",
|
|
45
|
+
"archive": "bright_black",
|
|
46
|
+
"audio": "bright_green",
|
|
47
|
+
"video": "bright_magenta",
|
|
48
|
+
"web": "bright_cyan",
|
|
49
|
+
"javascript": "yellow",
|
|
50
|
+
"config": "bright_blue",
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
"monokai": {
|
|
54
|
+
"folder": "bright_blue",
|
|
55
|
+
"file": "white",
|
|
56
|
+
"python": "bright_green",
|
|
57
|
+
"markdown": "bright_cyan",
|
|
58
|
+
"json": "yellow",
|
|
59
|
+
"image": "magenta",
|
|
60
|
+
"data": "green",
|
|
61
|
+
"document": "bright_red",
|
|
62
|
+
"archive": "bright_black",
|
|
63
|
+
"audio": "cyan",
|
|
64
|
+
"video": "bright_magenta",
|
|
65
|
+
"web": "bright_blue",
|
|
66
|
+
"javascript": "bright_yellow",
|
|
67
|
+
"config": "bright_green",
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
"nord": {
|
|
71
|
+
"folder": "bright_cyan",
|
|
72
|
+
"file": "white",
|
|
73
|
+
"python": "yellow",
|
|
74
|
+
"markdown": "cyan",
|
|
75
|
+
"json": "bright_yellow",
|
|
76
|
+
"image": "magenta",
|
|
77
|
+
"data": "green",
|
|
78
|
+
"document": "bright_white",
|
|
79
|
+
"archive": "bright_black",
|
|
80
|
+
"audio": "bright_green",
|
|
81
|
+
"video": "bright_magenta",
|
|
82
|
+
"web": "blue",
|
|
83
|
+
"javascript": "yellow",
|
|
84
|
+
"config": "cyan",
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
"solarized": {
|
|
88
|
+
"folder": "blue",
|
|
89
|
+
"file": "bright_white",
|
|
90
|
+
"python": "yellow",
|
|
91
|
+
"markdown": "cyan",
|
|
92
|
+
"json": "bright_yellow",
|
|
93
|
+
"image": "magenta",
|
|
94
|
+
"data": "green",
|
|
95
|
+
"document": "red",
|
|
96
|
+
"archive": "bright_black",
|
|
97
|
+
"audio": "green",
|
|
98
|
+
"video": "bright_magenta",
|
|
99
|
+
"web": "bright_blue",
|
|
100
|
+
"javascript": "bright_yellow",
|
|
101
|
+
"config": "cyan",
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
"minimal": {
|
|
105
|
+
"folder": "white",
|
|
106
|
+
"file": "white",
|
|
107
|
+
"python": "white",
|
|
108
|
+
"markdown": "white",
|
|
109
|
+
"json": "white",
|
|
110
|
+
"image": "white",
|
|
111
|
+
"data": "white",
|
|
112
|
+
"document": "white",
|
|
113
|
+
"archive": "bright_black",
|
|
114
|
+
"audio": "white",
|
|
115
|
+
"video": "white",
|
|
116
|
+
"web": "white",
|
|
117
|
+
"javascript": "white",
|
|
118
|
+
"config": "white",
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
"neon": {
|
|
122
|
+
"folder": "bright_cyan",
|
|
123
|
+
"file": "bright_white",
|
|
124
|
+
"python": "bright_green",
|
|
125
|
+
"markdown": "bright_magenta",
|
|
126
|
+
"json": "bright_yellow",
|
|
127
|
+
"image": "bright_magenta",
|
|
128
|
+
"data": "bright_green",
|
|
129
|
+
"document": "bright_red",
|
|
130
|
+
"archive": "bright_black",
|
|
131
|
+
"audio": "bright_cyan",
|
|
132
|
+
"video": "bright_magenta",
|
|
133
|
+
"web": "bright_blue",
|
|
134
|
+
"javascript": "yellow",
|
|
135
|
+
"config": "bright_cyan",
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
"sunset": {
|
|
139
|
+
"folder": "bright_red",
|
|
140
|
+
"file": "bright_white",
|
|
141
|
+
"python": "yellow",
|
|
142
|
+
"markdown": "bright_magenta",
|
|
143
|
+
"json": "bright_yellow",
|
|
144
|
+
"image": "magenta",
|
|
145
|
+
"data": "green",
|
|
146
|
+
"document": "red",
|
|
147
|
+
"archive": "bright_black",
|
|
148
|
+
"audio": "bright_green",
|
|
149
|
+
"video": "bright_red",
|
|
150
|
+
"web": "bright_yellow",
|
|
151
|
+
"javascript": "yellow",
|
|
152
|
+
"config": "bright_magenta",
|
|
153
|
+
}
|
|
154
|
+
}
|