Skip to content

Commit ebf91e6

Browse files
Line extension
1 parent 8484ce6 commit ebf91e6

File tree

15 files changed

+366
-27
lines changed

15 files changed

+366
-27
lines changed

CHANGELOG.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
---
89
## [0.0.4] - Unreleased
910

11+
### Added
12+
- Line extension: append any String after a path (comment, file details, etc.)
13+
1014
### Changed
1115
- Filtering: moved to options
16+
- Compact dirs: root dir is now never compacted
1217

1318
### Removed
1419
- Error handling: exceptions are now thrown instead of being handled by the renderer
1520

16-
21+
---
1722
## [0.0.3] - 2025-09-21
1823

1924
### Added
@@ -25,14 +30,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2530
- Sorting: option method `withFileSort` renamed in `sort`
2631
- Child limit: various renaming and refactor
2732

28-
33+
---
2934
## [0.0.2] - 2025-09-16
3035

3136
### Added
3237
- Option: sorting files and directories
3338
- 39 new default files & extension mappings for emojis
3439

35-
40+
---
3641
## [0.0.1] - 2025-09-14
3742

3843
### Added

README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Limit displayed children (fixed value or dynamically)
1616
- Compact directory chains
1717
- Maximum depth
18+
- Custom line extension (comment, file details, etc.)
1819
- Various styles for tree rendering
1920

2021
> [!CAUTION]
@@ -90,6 +91,7 @@ base/
9091
* [Max depth](#max-depth)
9192
* [Sorting](#sorting)
9293
* [Filtering](#filtering)
94+
* [Line extension](#line-extension)
9395

9496
## Tree format
9597
Choose between different tree formats.
@@ -296,6 +298,49 @@ filtering/
296298
└─ file_A.java
297299
```
298300

301+
## Line extension
302+
You can extend each displayed path with additional information by providing a custom `Function<Path, String>`.
303+
This is useful to annotate your tree with comments, display file sizes, or add domain-specific notes.
304+
305+
The function receives the current path and returns an optional string to append.
306+
If the function returns `null`, nothing is added.
307+
308+
```java
309+
// Example: LineExtension.java
310+
Function<Path, String> lineExtension = path -> {
311+
if (PathUtils.isDirectory(path) && PathUtils.hasName(path, "api")) {
312+
return "\t\t\t// All API code: controllers, etc.";
313+
}
314+
if (PathUtils.isDirectory(path) && PathUtils.hasName(path, "domain")) {
315+
return "\t\t\t// All domain code: value objects, etc.";
316+
}
317+
if (PathUtils.isDirectory(path) && PathUtils.hasName(path, "infra")) {
318+
return "\t\t\t// All infra code: database, email service, etc.";
319+
}
320+
if (PathUtils.isFile(path) && PathUtils.hasName(path, "application.properties")) {
321+
return "\t// Config file";
322+
}
323+
return null;
324+
};
325+
var prettyPrinter = FileTreePrettyPrinter.builder()
326+
.customizeOptions(options -> options.withLineExtension(lineExtension))
327+
.build();
328+
```
329+
```
330+
line_extension/
331+
└─ src/
332+
└─ main/
333+
├─ java/
334+
│ ├─ api/ // All API code: controllers, etc.
335+
│ │ └─ Controller.java
336+
│ ├─ domain/ // All domain code: value objects, etc.
337+
│ │ └─ ValueObject.java
338+
│ └─ infra/ // All infra code: database, email service, etc.
339+
│ └─ Repository.java
340+
└─ resources/
341+
└─ application.properties // Config file
342+
```
343+
299344
# Changelog
300345
See [CHANGELOG.md](CHANGELOG.md) for released versions.
301346

ROADMAP.md

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,14 @@
2020
## To do
2121
- [x] Use Github wiki to document options instead of readme
2222
- [x] Jacoco coverage report
23-
- [ ] Option: Line extension (=additional text after the file name)
24-
- [ ] Option: Filename decorator
23+
- [x] Option: Line extension (=additional text after the file name)
2524

26-
## Backlog
25+
## Backlog / To analyze / To implement if requested
26+
- [ ] More `PathPredicates` functions!
2727
- [ ] Option: custom tree format
2828
- [ ] Option: custom emojis
29-
- [ ] Option: color
3029
- [ ] Refactor unit tests (custom assert?)
31-
- [ ] More `PathPredicates` functions!
32-
33-
## Abandoned
34-
These ideas will likely not been implemented because they do not align with JFileTreePrettyPrint vision:
35-
- File attributes LineRenderer (size, author, createAt, etc.)
36-
- Print optional legend for symlink/other file types symbols (at the end of the tree)
37-
- Follow symlink option
30+
- [ ] Option: color
31+
- [ ] Option: Filename decorator
32+
- [ ] Option: Follow symlink
33+
- [ ] Advanced line extension function (file size, author, timestamps, etc. )
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.github.computerdaddyguy.jfiletreeprettyprinter.example;
2+
3+
import io.github.computerdaddyguy.jfiletreeprettyprinter.FileTreePrettyPrinter;
4+
import io.github.computerdaddyguy.jfiletreeprettyprinter.PathUtils;
5+
import java.nio.file.Path;
6+
import java.util.function.Function;
7+
8+
public class LineExtension {
9+
10+
public static void main(String[] args) {
11+
Function<Path, String> lineExtension = path -> {
12+
if (PathUtils.isDirectory(path) && PathUtils.hasName(path, "api")) {
13+
return "\t\t\t// All API code: controllers, etc.";
14+
}
15+
if (PathUtils.isDirectory(path) && PathUtils.hasName(path, "domain")) {
16+
return "\t\t\t// All domain code: value objects, etc.";
17+
}
18+
if (PathUtils.isDirectory(path) && PathUtils.hasName(path, "infra")) {
19+
return "\t\t\t// All infra code: database, email service, etc.";
20+
}
21+
if (PathUtils.isFile(path) && PathUtils.hasName(path, "application.properties")) {
22+
return "\t// Config file";
23+
}
24+
return null;
25+
};
26+
var prettyPrinter = FileTreePrettyPrinter.builder()
27+
.customizeOptions(options -> options.withLineExtension(lineExtension))
28+
.build();
29+
var tree = prettyPrinter.prettyPrint("src/example/resources/line_extension");
30+
System.out.println(tree);
31+
}
32+
33+
}

src/example/resources/line_extension/src/main/java/api/Controller.java

Whitespace-only changes.

src/example/resources/line_extension/src/main/java/domain/ValueObject.java

Whitespace-only changes.

src/example/resources/line_extension/src/main/java/infra/Repository.java

Whitespace-only changes.

src/example/resources/line_extension/src/main/resources/application.properties

Whitespace-only changes.

src/main/java/io/github/computerdaddyguy/jfiletreeprettyprinter/PrettyPrintOptions.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.nio.file.Path;
66
import java.util.Comparator;
77
import java.util.Objects;
8+
import java.util.function.Function;
89
import java.util.function.Predicate;
910
import java.util.function.ToIntFunction;
1011
import org.jspecify.annotations.NullMarked;
@@ -313,9 +314,36 @@ public Predicate<Path> pathFilter() {
313314
314315
* @param filter The filter, <code>null</code> to disable filtering
315316
*/
316-
public PrettyPrintOptions filter(Predicate<Path> filter) {
317+
public PrettyPrintOptions filter(@Nullable Predicate<Path> filter) {
317318
this.pathFilter = filter;
318319
return this;
319320
}
320321

322+
// ---------- Line extension ----------
323+
324+
@Nullable
325+
private Function<Path, String> lineExtension;
326+
327+
@Override
328+
public Function<Path, String> getLineExtension() {
329+
return lineExtension;
330+
}
331+
332+
/**
333+
* Sets a custom line extension function that appends additional text to each
334+
* printed line, allowing you to customize the display of files or directories.
335+
* <p>
336+
* Typical use cases include adding comments, showing file sizes, or displaying metadata.
337+
* <p>
338+
* The function receives the current {@link Path} displayed on the line
339+
* and returns an optional string to be appended.
340+
* If the function returns {@code null}, nothing is added.
341+
*
342+
* @param lineExtension the custom line extension function, or {@code null} to disable
343+
*/
344+
public PrettyPrintOptions withLineExtension(@Nullable Function<Path, String> lineExtension) {
345+
this.lineExtension = lineExtension;
346+
return this;
347+
}
348+
321349
}

src/main/java/io/github/computerdaddyguy/jfiletreeprettyprinter/renderer/DefaultTreeEntryRenderer.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,20 @@ private String renderTree(TreeEntry entry, Depth depth) {
4141
private String renderDirectory(Depth depth, DirectoryEntry dirEntry, List<Path> compactPaths) {
4242

4343
if (options.areCompactDirectoriesUsed()
44+
&& !depth.isRoot()
4445
&& dirEntry.getEntries().size() == 1
4546
&& dirEntry.getEntries().get(0) instanceof DirectoryEntry childDirEntry) {
46-
var newCompactPaths = new ArrayList<>(compactPaths);
47-
newCompactPaths.add(childDirEntry.getDir());
48-
return renderDirectory(depth, childDirEntry, newCompactPaths);
47+
48+
var extension = computeLineExtension(dirEntry.getDir());
49+
if (extension.isEmpty()) {
50+
var newCompactPaths = new ArrayList<>(compactPaths);
51+
newCompactPaths.add(childDirEntry.getDir());
52+
return renderDirectory(depth, childDirEntry, newCompactPaths);
53+
}
4954
}
5055

5156
var line = lineRenderer.renderDirectoryBegin(depth, dirEntry, compactPaths);
57+
line += computeLineExtension(dirEntry.getDir());
5258

5359
var childIt = dirEntry.getEntries().iterator();
5460

@@ -70,8 +76,18 @@ private String renderDirectory(Depth depth, DirectoryEntry dirEntry, List<Path>
7076
return line + childLines;
7177
}
7278

79+
private String computeLineExtension(Path path) {
80+
if (options.getLineExtension() == null) {
81+
return "";
82+
}
83+
var extension = options.getLineExtension().apply(path);
84+
return extension == null ? "" : extension;
85+
}
86+
7387
private String renderFile(Depth depth, FileEntry fileEntry) {
74-
return lineRenderer.renderFile(depth, fileEntry);
88+
var line = lineRenderer.renderFile(depth, fileEntry);
89+
line += computeLineExtension(fileEntry.getFile());
90+
return line;
7591
}
7692

7793
private String renderSkippedChildrenEntry(Depth depth, SkippedChildrenEntry skippedChildrenEntry) {

0 commit comments

Comments
 (0)