|
10 | 10 | [](https://github.com/computerdaddyguy/jfiletreeprettyprinter/blob/main/LICENSE) |
11 | 11 |
|
12 | 12 | **A lightweight Java library for printing directory structures in a clean, tree-like format.** |
13 | | -- Sorting & filtering |
| 13 | + |
| 14 | +Supports various [options](#options) to customize the directories scanning and rendering: |
| 15 | +- Filtering & sorting |
14 | 16 | - Emoji support 🎉 |
15 | 17 | - Limit displayed children (fixed value or dynamically) |
| 18 | +- Custom line extension (comment, file details, etc.) |
16 | 19 | - Compact directory chains |
17 | 20 | - Maximum depth |
18 | | -- Custom line extension (comment, file details, etc.) |
19 | 21 | - Various styles for tree rendering |
20 | 22 |
|
| 23 | +<p align="center"> |
| 24 | + JFileTreePrettyPrint project structure, pretty printed using JFileTreePrettyPrint (see <a href="https://github.com/ComputerDaddyGuy/JFileTreePrettyPrinter/blob/develop/src/example/java/io/github/computerdaddyguy/jfiletreeprettyprinter/example/CompleteExample.java">CompleteExample.java</a>) |
| 25 | + <img src="https://raw.githubusercontent.com/ComputerDaddyGuy/JFileTreePrettyPrinter/refs/heads/develop/assets/project-structure.png" alt="JFileTreePrettyPrint project structure, using JFileTreePrettyPrint"/> |
| 26 | +</p> |
| 27 | + |
21 | 28 | > [!CAUTION] |
22 | 29 | > This lib was developed just for fun, and has not been thoroughly tested! |
23 | 30 | > May not be suitable for production code 😊 |
24 | 31 |
|
25 | 32 | > [!IMPORTANT] |
26 | 33 | > Complete documentation available in [wiki](https://github.com/ComputerDaddyGuy/JFileTreePrettyPrinter/wiki). |
27 | 34 |
|
28 | | -<p align="center"> |
29 | | - <img src="https://github.com/ComputerDaddyGuy/JFileTreePrettyPrinter/blob/develop/assets/JfileTreePrettyPrinter-structure.png?raw=true" alt="JFileTreePrettyPrint structure, using JFileTreePrettyPrint"/> |
30 | | -</p> |
31 | | - |
32 | 35 | * [Import dependency](#import-dependency) |
33 | 36 | * [Usage](#usage) |
34 | 37 | * [Options](#options) |
@@ -84,38 +87,73 @@ base/ |
84 | 87 |
|
85 | 88 | # Options |
86 | 89 |
|
87 | | -* [Tree format](#tree-format) |
| 90 | +* [Filtering](#filtering) |
| 91 | +* [Sorting](#sorting) |
88 | 92 | * [Emojis ❤️](#emojis-%EF%B8%8F) |
89 | 93 | * [Child limit](#child-limit) |
| 94 | +* [Line extension](#line-extension) |
90 | 95 | * [Compact directories](#compact-directories) |
91 | 96 | * [Max depth](#max-depth) |
92 | | -* [Sorting](#sorting) |
93 | | -* [Filtering](#filtering) |
94 | | -* [Line extension](#line-extension) |
| 97 | +* [Tree format](#tree-format) |
95 | 98 |
|
96 | | -## Tree format |
97 | | -Choose between different tree formats. |
98 | | -The default is `UNICODE_BOX_DRAWING`, supported by all terminals, but you can also switch to use `CLASSIC_ASCII`. |
| 99 | +## Filtering |
| 100 | +Files and directories can be selectively included or excluded using a custom `PathMatcher`. |
| 101 | + |
| 102 | +Filtering is independant for files & directories. Files are filtered only if their parent directory pass the directory filter. |
| 103 | +If none of some directory's children match, the directory is still displayed. |
| 104 | + |
| 105 | +The `PathMatchers` class provides several ready-to-use methods for creating and combining common matchers. |
99 | 106 |
|
100 | 107 | ```java |
101 | | -// Example: FileTreeFormat.java |
| 108 | +// Example: Filtering.java |
| 109 | +var excludeDirWithNoJavaFiles = PathMatchers.not(PathMatchers.hasNameEndingWith("no_java_file")); |
| 110 | +var hasJavaExtension = PathMatchers.hasExtension("java"); |
| 111 | + |
102 | 112 | var prettyPrinter = FileTreePrettyPrinter.builder() |
103 | | - .customizeOptions(options -> options.withTreeFormat(TreeFormat.CLASSIC_ASCII)) |
104 | | - .build(); |
| 113 | + .customizeOptions( |
| 114 | + options -> options |
| 115 | + .filterDirectories(excludeDirWithNoJavaFiles) |
| 116 | + .filterFiles(hasJavaExtension) |
| 117 | + ) |
| 118 | + .build(); |
105 | 119 | ``` |
106 | | - |
107 | 120 | ``` |
108 | | -tree_format/ |
109 | | -|-- file_1 |
110 | | -|-- file_2 |
111 | | -`-- subFolder/ |
112 | | - |-- subFile_1 |
113 | | - `-- subFile_2 |
| 121 | +filtering/ |
| 122 | +├─ dir_with_java_files/ |
| 123 | +│ ├─ file_B.java |
| 124 | +│ └─ file_E.java |
| 125 | +├─ dir_with_nested_java_files/ |
| 126 | +│ └─ nested_dir_with_java_files/ |
| 127 | +│ ├─ file_G.java |
| 128 | +│ └─ file_J.java |
| 129 | +└─ file_A.java |
114 | 130 | ``` |
115 | 131 |
|
116 | | -> [!TIP] |
117 | | -> *Idea for a future version: option to allow usage of custom format* |
| 132 | +## Sorting |
| 133 | +Files and directories can be sorted using a custom comparator (default is alphabetical order). |
| 134 | +If the provided comparator considers two paths equal (i.e., returns `0`), an alphabetical comparator is applied as a tie-breaker to ensure consistent results across all systems. |
| 135 | + |
| 136 | +The `PrettyPrintOptions.Sorts` class provides a set of basic, ready-to-use comparators. |
118 | 137 |
|
| 138 | +```java |
| 139 | +// Example: Sorting.java |
| 140 | +var prettyPrinter = FileTreePrettyPrinter.builder() |
| 141 | + .customizeOptions(options -> options.sort(PrettyPrintOptions.Sorts.DIRECTORY_FIRST)) |
| 142 | + .build(); |
| 143 | +``` |
| 144 | +``` |
| 145 | +sorting/ |
| 146 | +├─ c_dir/ |
| 147 | +│ └─ c_file |
| 148 | +├─ d_dir/ |
| 149 | +│ ├─ d_b_dir/ |
| 150 | +│ │ └─ d_b_file |
| 151 | +│ └─ d_a_file |
| 152 | +├─ a_file |
| 153 | +├─ b_file |
| 154 | +├─ x_file |
| 155 | +└─ y_file |
| 156 | +``` |
119 | 157 |
|
120 | 158 | ## Emojis ❤️ |
121 | 159 | If your terminal supports them, you can choose to use emojis. |
@@ -207,6 +245,52 @@ child_limit_dynamic/ |
207 | 245 | > [!TIP] |
208 | 246 | > *Idea for a future version: helper for custom basic functions (by name, prefix, regex, etc.)* |
209 | 247 |
|
| 248 | + |
| 249 | +## Line extension |
| 250 | +You can extend each displayed path with additional information by providing a custom `Function<Path, String>`. |
| 251 | +This is useful to annotate your tree with comments, display file sizes, or add domain-specific notes. |
| 252 | + |
| 253 | +The function receives the current path and returns an optional string to append. |
| 254 | +If the function returns `null`, nothing is added. |
| 255 | + |
| 256 | +```java |
| 257 | +// Example: LineExtension.java |
| 258 | +var printedPath = Path.of("src/example/resources/line_extension"); |
| 259 | + |
| 260 | +Function<Path, String> lineExtension = path -> { |
| 261 | + if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/api", printedPath).matches(path)) { |
| 262 | + return "\t\t\t// All API code: controllers, etc."; |
| 263 | + } |
| 264 | + if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/domain", printedPath).matches(path)) { |
| 265 | + return "\t\t\t// All domain code: value objects, etc."; |
| 266 | + } |
| 267 | + if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/infra", printedPath).matches(path)) { |
| 268 | + return "\t\t\t// All infra code: database, email service, etc."; |
| 269 | + } |
| 270 | + if (PathMatchers.hasNameMatchingGlob("*.properties").matches(path)) { |
| 271 | + return "\t// Config file"; |
| 272 | + } |
| 273 | + return null; |
| 274 | +}; |
| 275 | +var prettyPrinter = FileTreePrettyPrinter.builder() |
| 276 | + .customizeOptions(options -> options.withLineExtension(lineExtension)) |
| 277 | + .build(); |
| 278 | +``` |
| 279 | +``` |
| 280 | +line_extension/ |
| 281 | +└─ src/ |
| 282 | + └─ main/ |
| 283 | + ├─ java/ |
| 284 | + │ ├─ api/ // All API code: controllers, etc. |
| 285 | + │ │ └─ Controller.java |
| 286 | + │ ├─ domain/ // All domain code: value objects, etc. |
| 287 | + │ │ └─ ValueObject.java |
| 288 | + │ └─ infra/ // All infra code: database, email service, etc. |
| 289 | + │ └─ Repository.java |
| 290 | + └─ resources/ |
| 291 | + └─ application.properties // Config file |
| 292 | +``` |
| 293 | + |
210 | 294 | ## Compact directories |
211 | 295 | Directories chain with single directory child are fully expanded by default, but you can compact them into a single tree entry. |
212 | 296 |
|
@@ -247,109 +331,28 @@ max_depth/ |
247 | 331 | └─ ... (max depth reached) |
248 | 332 | ``` |
249 | 333 |
|
250 | | -## Sorting |
251 | | -Files and directories can be sorted using a custom comparator (default is alphabetical order). |
252 | | -If the provided comparator considers two paths equal (i.e., returns `0`), an alphabetical comparator is applied as a tie-breaker to ensure consistent results across all systems. |
253 | | - |
254 | | -The `PrettyPrintOptions.Sorts` class provides a set of basic, ready-to-use comparators. |
| 334 | +## Tree format |
| 335 | +Choose between different tree formats. |
| 336 | +The default is `UNICODE_BOX_DRAWING`, supported by all terminals, but you can also switch to use `CLASSIC_ASCII`. |
255 | 337 |
|
256 | 338 | ```java |
257 | | -// Example: Sorting.java |
| 339 | +// Example: FileTreeFormat.java |
258 | 340 | var prettyPrinter = FileTreePrettyPrinter.builder() |
259 | | - .customizeOptions(options -> options.sort(PrettyPrintOptions.Sorts.DIRECTORY_FIRST)) |
| 341 | + .customizeOptions(options -> options.withTreeFormat(TreeFormat.CLASSIC_ASCII)) |
260 | 342 | .build(); |
261 | 343 | ``` |
262 | | -``` |
263 | | -sorting/ |
264 | | -├─ c_dir/ |
265 | | -│ └─ c_file |
266 | | -├─ d_dir/ |
267 | | -│ ├─ d_b_dir/ |
268 | | -│ │ └─ d_b_file |
269 | | -│ └─ d_a_file |
270 | | -├─ a_file |
271 | | -├─ b_file |
272 | | -├─ x_file |
273 | | -└─ y_file |
274 | | -``` |
275 | | - |
276 | | -## Filtering |
277 | | -Files and directories can be selectively included or excluded using a custom `PathMatcher`. |
278 | 344 |
|
279 | | -Filtering is independant for files & directories. Files are filtered only if their parent directory pass the directory filter. |
280 | | -If none of some directory's children match, the directory is still displayed. |
281 | | - |
282 | | -The `PathMatchers` class provides several ready-to-use methods for creating and combining common matchers. |
283 | | - |
284 | | -```java |
285 | | -// Example: Filtering.java |
286 | | -var excludeDirWithNoJavaFiles = PathMatchers.not(PathMatchers.hasNameEndingWith("no_java_file")); |
287 | | -var hasJavaExtension = PathMatchers.hasExtension("java"); |
288 | | - |
289 | | -var prettyPrinter = FileTreePrettyPrinter.builder() |
290 | | - .customizeOptions( |
291 | | - options -> options |
292 | | - .filterDirectories(excludeDirWithNoJavaFiles) |
293 | | - .filterFiles(hasJavaExtension) |
294 | | - ) |
295 | | - .build(); |
296 | | -``` |
297 | 345 | ``` |
298 | | -filtering/ |
299 | | -├─ dir_with_java_files/ |
300 | | -│ ├─ file_B.java |
301 | | -│ └─ file_E.java |
302 | | -├─ dir_with_nested_java_files/ |
303 | | -│ └─ nested_dir_with_java_files/ |
304 | | -│ ├─ file_G.java |
305 | | -│ └─ file_J.java |
306 | | -└─ file_A.java |
| 346 | +tree_format/ |
| 347 | +|-- file_1 |
| 348 | +|-- file_2 |
| 349 | +`-- subFolder/ |
| 350 | + |-- subFile_1 |
| 351 | + `-- subFile_2 |
307 | 352 | ``` |
308 | 353 |
|
309 | | -## Line extension |
310 | | -You can extend each displayed path with additional information by providing a custom `Function<Path, String>`. |
311 | | -This is useful to annotate your tree with comments, display file sizes, or add domain-specific notes. |
312 | | - |
313 | | -The function receives the current path and returns an optional string to append. |
314 | | -If the function returns `null`, nothing is added. |
315 | | - |
316 | | -```java |
317 | | -// Example: LineExtension.java |
318 | | -var printedPath = Path.of("src/example/resources/line_extension"); |
319 | | - |
320 | | -Function<Path, String> lineExtension = path -> { |
321 | | - if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/api", printedPath).matches(path)) { |
322 | | - return "\t\t\t// All API code: controllers, etc."; |
323 | | - } |
324 | | - if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/domain", printedPath).matches(path)) { |
325 | | - return "\t\t\t// All domain code: value objects, etc."; |
326 | | - } |
327 | | - if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/infra", printedPath).matches(path)) { |
328 | | - return "\t\t\t// All infra code: database, email service, etc."; |
329 | | - } |
330 | | - if (PathMatchers.hasNameMatchingGlob("*.properties").matches(path)) { |
331 | | - return "\t// Config file"; |
332 | | - } |
333 | | - return null; |
334 | | -}; |
335 | | -var prettyPrinter = FileTreePrettyPrinter.builder() |
336 | | - .customizeOptions(options -> options.withLineExtension(lineExtension)) |
337 | | - .build(); |
338 | | -``` |
339 | | -``` |
340 | | -line_extension/ |
341 | | -└─ src/ |
342 | | - └─ main/ |
343 | | - ├─ java/ |
344 | | - │ ├─ api/ // All API code: controllers, etc. |
345 | | - │ │ └─ Controller.java |
346 | | - │ ├─ domain/ // All domain code: value objects, etc. |
347 | | - │ │ └─ ValueObject.java |
348 | | - │ └─ infra/ // All infra code: database, email service, etc. |
349 | | - │ └─ Repository.java |
350 | | - └─ resources/ |
351 | | - └─ application.properties // Config file |
352 | | -``` |
| 354 | +> [!TIP] |
| 355 | +> *Idea for a future version: option to allow usage of custom format* |
353 | 356 |
|
354 | 357 | # Changelog |
355 | 358 | See [CHANGELOG.md](CHANGELOG.md) for released versions. |
|
0 commit comments