Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- New various path matchers
- New `LineExtensions`, `ChildLimits` and `PathSorts` helper classes (and associated builders)

### Changed
- Helpers classes `PathUtils` and `PathPredicates` removed, use `PathMatchers` instead
- Filtering: now using `PathMatcher` interface instead of `Predicate<Path>`
- Filtering: split into distinct directories and files filters for better control
- `PathUtils` and `PathPredicates` removed, use `PathMatchers` instead
- Line extension: empty string is now permitted

### Fixed
Expand Down
42 changes: 18 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,12 @@ filtering/
Files and directories can be sorted using a custom comparator (default is alphabetical order).
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.

The `PrettyPrintOptions.Sorts` class provides a set of basic, ready-to-use comparators.
The `PathSorts` class provides a set of basic, ready-to-use comparators, as well as a builder for creating your own tailor-made sorts.

```java
// Example: Sorting.java
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.sort(PrettyPrintOptions.Sorts.DIRECTORY_FIRST))
.customizeOptions(options -> options.sort(PathSorts.DIRECTORY_FIRST))
.build();
```
```
Expand Down Expand Up @@ -219,14 +219,13 @@ Use the `ChildLimitBuilder` and `PathMatchers` classes to help you build the lim

```java
// Example: ChildLimitDynamic.java
var isNodeModuleMatcher = PathMatchers.hasName("node_modules");
var childLimit = ChildLimitBuilder.builder()
.defaultLimit(ChildLimitBuilder.UNLIMITED)
.limit(isNodeModuleMatcher, 0)
var childLimit = ChildLimits.builder()
.setDefault(ChildLimits.UNLIMITED) // Unlimited children by default
.add(PathMatchers.hasName("node_modules"), 0) // Do NOT print any children in "node_modules" folder
.build();
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withChildLimit(childLimit))
.build();
.customizeOptions(options -> options.withChildLimit(childLimit))
.build();
```
```
child_limit_dynamic/
Expand All @@ -249,28 +248,23 @@ child_limit_dynamic/
You can extend each displayed path with additional information by providing a custom `Function<Path, String>`.
This is useful to annotate your tree with comments, display file sizes, or add domain-specific notes.

The function receives the current path and returns an optional string to append.
The function receives the current path and returns an optional string to append (empty string is authorized).
If the function returns `null`, nothing is added.

Use the `LineExtensions` class to help you build line extension functions.

```java
// Example: LineExtension.java
var printedPath = Path.of("src/example/resources/line_extension");

Function<Path, String> lineExtension = path -> {
if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/api", printedPath).matches(path)) {
return "\t\t\t// All API code: controllers, etc.";
}
if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/domain", printedPath).matches(path)) {
return "\t\t\t// All domain code: value objects, etc.";
}
if (PathMatchers.hasRelativePathMatchingGlob("src/main/java/infra", printedPath).matches(path)) {
return "\t\t\t// All infra code: database, email service, etc.";
}
if (PathMatchers.hasNameMatchingGlob("*.properties").matches(path)) {
return "\t// Config file";
}
return null;
};
Function<Path, String> lineExtension = LineExtensions.builder()
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/api"), "\t\t\t// All API code: controllers, etc.")
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/domain"), "\t\t\t// All domain code: value objects, etc.")
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/infra"), "\t\t\t// All infra code: database, email service, etc.")
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/api"), "\t\t\t// All API code: controllers, etc.")
.add(PathMatchers.hasNameMatchingGlob("*.properties"), "\t// Config file")
.build();

var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withLineExtension(lineExtension))
.build();
Expand Down
4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@

## To do
- [x] More `PathMatchers` functions!
- [ ] Helper class for line extension
- [ ] Helper class for sorting
- [x] Helper class for line extension
- [x] Helper class for sorting
- [ ] Option: custom emojis
- [ ] Option: hide number of skipped files and folders for child limit
- [ ] Rework/fix Github wiki to be up to date
Expand Down
Binary file modified assets/project-structure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package io.github.computerdaddyguy.jfiletreeprettyprinter.example;

import io.github.computerdaddyguy.jfiletreeprettyprinter.ChildLimitBuilder;
import io.github.computerdaddyguy.jfiletreeprettyprinter.ChildLimits;
import io.github.computerdaddyguy.jfiletreeprettyprinter.FileTreePrettyPrinter;
import io.github.computerdaddyguy.jfiletreeprettyprinter.PathMatchers;

public class ChildLimitDynamic {

public static void main(String[] args) {
var isNodeModuleMatcher = PathMatchers.hasName("node_modules");
var childLimit = ChildLimitBuilder.builder()
.defaultLimit(ChildLimitBuilder.UNLIMITED)
.limit(isNodeModuleMatcher, 0)
var childLimit = ChildLimits.builder()
.setDefault(ChildLimits.UNLIMITED) // Unlimited children by default
.add(PathMatchers.hasName("node_modules"), 0) // Do NOT print any children in "node_modules" folder
.build();
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withChildLimit(childLimit))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.computerdaddyguy.jfiletreeprettyprinter.example;

import io.github.computerdaddyguy.jfiletreeprettyprinter.FileTreePrettyPrinter;
import io.github.computerdaddyguy.jfiletreeprettyprinter.LineExtensions;
import io.github.computerdaddyguy.jfiletreeprettyprinter.PathMatchers;
import java.nio.file.Path;
import java.util.function.Function;
Expand All @@ -10,21 +11,14 @@ public class LineExtension {
public static void main(String[] args) {
var printedPath = Path.of("src/example/resources/line_extension");

Function<Path, String> lineExtension = path -> {
if (PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/api").matches(path)) {
return "\t\t\t// All API code: controllers, etc.";
}
if (PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/domain").matches(path)) {
return "\t\t\t// All domain code: value objects, etc.";
}
if (PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/infra").matches(path)) {
return "\t\t\t// All infra code: database, email service, etc.";
}
if (PathMatchers.hasNameMatchingGlob("*.properties").matches(path)) {
return "\t// Config file";
}
return null;
};
Function<Path, String> lineExtension = LineExtensions.builder()
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/api"), "\t\t\t// All API code: controllers, etc.")
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/domain"), "\t\t\t// All domain code: value objects, etc.")
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/infra"), "\t\t\t// All infra code: database, email service, etc.")
.add(PathMatchers.hasRelativePathMatchingGlob(printedPath, "src/main/java/api"), "\t\t\t// All API code: controllers, etc.")
.add(PathMatchers.hasNameMatchingGlob("*.properties"), "\t// Config file")
.build();

var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withLineExtension(lineExtension))
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.github.computerdaddyguy.jfiletreeprettyprinter.example;

import io.github.computerdaddyguy.jfiletreeprettyprinter.ChildLimitBuilder;
import io.github.computerdaddyguy.jfiletreeprettyprinter.ChildLimits;
import io.github.computerdaddyguy.jfiletreeprettyprinter.FileTreePrettyPrinter;
import io.github.computerdaddyguy.jfiletreeprettyprinter.LineExtensions;
import io.github.computerdaddyguy.jfiletreeprettyprinter.PathMatchers;
import io.github.computerdaddyguy.jfiletreeprettyprinter.PrettyPrintOptions.Sorts;
import io.github.computerdaddyguy.jfiletreeprettyprinter.PathSorts;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.function.Function;
Expand Down Expand Up @@ -47,46 +48,38 @@ public static void main(String[] args) {
var fileFilter = PathMatchers.allOf(

// Hide files with names starting with "."
PathMatchers.not(PathMatchers.hasNameStartingWith(".")),

// Inside "jfiletreeprettyprinter" folder, keep only "FileTreePrettyPrinter.java"
// Files in other folders are not restricted by this rule.
PathMatchers.ifMatchesThenElse(
/* if */ PathMatchers.hasDirectParentMatching(PathMatchers.hasName("jfiletreeprettyprinter")),
/* then */ PathMatchers.hasName("FileTreePrettyPrinter.java"),
/* else */ path -> true
)
PathMatchers.not(PathMatchers.hasNameStartingWith("."))
);

/*
* Limit the number of displayed children by directory: some content is not relevant and clutters the final result!
*/
var childLimitFunction = ChildLimitBuilder.builder()
var childLimitFunction = ChildLimits.builder()
// Hide all files under renderer and scanner packages
.limit(PathMatchers.hasAbsolutePathMatchingGlob("**/io/github/computerdaddyguy/jfiletreeprettyprinter/renderer"), 0)
.limit(PathMatchers.hasAbsolutePathMatchingGlob("**/io/github/computerdaddyguy/jfiletreeprettyprinter/scanner"), 0)
.add(PathMatchers.hasAbsolutePathMatchingGlob("**/io/github/computerdaddyguy/jfiletreeprettyprinter/renderer"), 0)
.add(PathMatchers.hasAbsolutePathMatchingGlob("**/io/github/computerdaddyguy/jfiletreeprettyprinter/scanner"), 0)
.add(PathMatchers.hasAbsolutePathMatchingGlob("**/io/github/computerdaddyguy/jfiletreeprettyprinter"), 3)
.build();

/*
* Add some comments on a few files and directories
*/
Function<Path, String> lineExtension = path -> {
if (PathMatchers.hasName("project-structure.png").matches(path)) {
return "\t// This image";
} else if (PathMatchers.hasName("FileTreePrettyPrinter.java").matches(path)) {
return "\t// Main entry point";
} else if (PathMatchers.hasName("README.md").matches(path)) {
return "\t\t// You're reading at this!";
} else if (PathMatchers.hasRelativePathMatchingGlob(projectFolder, "src/main/java").matches(path)) {
return ""; // Empty string: force line break in compact directory chain
}
return null;
};
Function<Path, String> lineExtension = LineExtensions.builder()
.add(PathMatchers.hasName("project-structure.png"), "\t// This image")
.add(PathMatchers.hasName("FileTreePrettyPrinter.java"), "\t// Main entry point")
.add(PathMatchers.hasName("README.md"), "\t\t// You're reading at this!")
.addLineBreak(PathMatchers.hasRelativePathMatchingGlob(projectFolder, "src/main/java"))
.build();

/*
* Sort all paths by directory first (then alphabetically by default)
* Sort all paths by directory first (with highest precedence),
* then "FileTreePrettyPrinter.java" has precedence "-100".
* All other files have default precedence "0", and are then sorted alphabetically by default.
*/
Comparator<Path> pathComparator = Sorts.DIRECTORY_FIRST;
Comparator<Path> pathComparator = PathSorts.builder()
.addFirst(PathMatchers.isDirectory())
.add(PathMatchers.hasName("FileTreePrettyPrinter.java"), -100) // Default precedence is "0"
.build();

/*
* Build the final FileTreePrettyPrinter
Expand Down Expand Up @@ -115,25 +108,27 @@ public static void main(String[] args) {
Expected result
================================

📂 JFileTreePrettyPrinter/
├─ 📂 assets/
│ └─ 🖼️ project-structure.png // This image
├─ 📂 src/main/java/
│ └─ 📂 io/github/computerdaddyguy/jfiletreeprettyprinter/
│ ├─ 📂 renderer/
│ │ └─ ... (5 files and 2 directories skipped)
│ ├─ 📂 scanner/
│ │ └─ ... (4 files skipped)
│ └─ ☕ FileTreePrettyPrinter.java // Main entry point
├─ 🗺️ CHANGELOG.md
├─ 📖 CONTRIBUTING.md
├─ 📄 LICENSE
├─ 📖 README.md // You're reading at this!
├─ 🗺️ ROADMAP.md
├─ 🛡️ SECURITY.md
├─ 🏗️ pom.xml
├─ 📖 release_process.md
└─ 📜 runMutationTests.sh
📂 JFileTreePrettyPrinter/
├─ 📂 assets/
│ └─ 🖼️ project-structure.png // This image
├─ 📂 src/main/java/
│ └─ 📂 io/github/computerdaddyguy/jfiletreeprettyprinter/
│ ├─ 📂 renderer/
│ │ └─ ... (5 files and 2 directories skipped)
│ ├─ 📂 scanner/
│ │ └─ ... (4 files skipped)
│ ├─ ☕ FileTreePrettyPrinter.java // Main entry point
│ └─ ... (10 files skipped)
├─ 🗺️ CHANGELOG.md
├─ 📖 CONTRIBUTING.md
├─ 📄 LICENSE
├─ 📖 README.md // You're reading at this!
├─ 🗺️ ROADMAP.md
├─ 🛡️ SECURITY.md
├─ 🏗️ pom.xml
├─ 📖 release_process.md
└─ 📜 runMutationTests.sh

*/
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package io.github.computerdaddyguy.jfiletreeprettyprinter.example;

import io.github.computerdaddyguy.jfiletreeprettyprinter.FileTreePrettyPrinter;
import io.github.computerdaddyguy.jfiletreeprettyprinter.PrettyPrintOptions;
import io.github.computerdaddyguy.jfiletreeprettyprinter.PathSorts;

public class Sorting {

public static void main(String[] args) {
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.sort(PrettyPrintOptions.Sorts.DIRECTORY_FIRST))
.customizeOptions(options -> options.sort(PathSorts.DIRECTORY_FIRST))
.build();
var tree = prettyPrinter.prettyPrint("src/example/resources/sorting");
System.out.println(tree);
Expand Down
Loading
Loading