A lightweight and flexible Java library with a native CLI to pretty-print directory structures - ideal for documentation, project overviews, or CLI tools.
JFileTreePrettyPrint project structure, using JFileTreePrettyPrint
Supports various options to customize the directories scanning and rendering:
| Option | Description | Supported in CLI | Supported in Library API |
|---|---|---|---|
filter - dir |
Include/exclude specific directories | β Yes | β Yes |
filter - file |
Include/exclude specific files | β Yes | β Yes |
sorting |
Custom sorting of files/directories | β No | β Yes |
emojis |
Display emojis as π folders and πfiles icons | β Yes | β Yes |
emoji - custom mapping |
Custom emoji mapping | β No | β Yes |
compactDirectories |
Compact single-child directories into one line | β Yes | β Yes |
childLimit - static |
Static limit number of displayed children per directory | β Yes | β Yes |
childLimit - dynamic |
Dynamic limit number of displayed children per directory | β Yes | β Yes |
maxDepth |
Maximum directory depth to display | β Yes | β Yes |
lineExtensions |
Append custom strings/comments after matching paths | β Yes | β Yes |
treeFormat |
Custom symbols for branches and indentation | β No | β Yes |
external options file |
Use options defined in an external file | β Yes | β No |
debug |
Print debug information to console | β
Yes (--debug) |
β No |
Unlike a plain recursive Files.walk(), this library:
- π Prints visually appealing directory trees.
- π¨ Allows rich customization (filters, sorts, emojis, compacting, tree style).
- π Is dependency-free (on runtime) and compatible with Java 21+.
- βοΈ Choose between Java lib or Native CLI implementation.
- See πCHANGELOG.md for a list of released versions and detailed changes.
- See πΊοΈROADMAP.md to discover planned features and upcoming improvements.
- This project is licensed under the Apache License 2.0. See βοΈLICENSE for details.
- For any questions or feedback please open an issue on this repository, as detailed in π€CONTRIBUTING.md.
- Java 21 or later
- No runtime dependencies!
For Maven, import this dependency to your pom.xml:
<dependency>
<groupId>io.github.computerdaddyguy</groupId>
<artifactId>jfiletreeprettyprinter-core</artifactId>
<version>0.2.0</version>
</dependency>For Gradle:
implementation "io.github.computerdaddyguy:jfiletreeprettyprinter-core:0.2.0"// Example: BasicUsage.java
var printer = FileTreePrettyPrinter.createDefault(); // Create a printer with default options
var tree = printer.prettyPrint("src/example/resources/base"); // Pretty print the target folder
System.out.println(tree); // Admire the result!Result:
base/
ββ businessPlan.pdf
ββ businessProject.pdf
ββ cars/
β ββ Ferrari.doc
β ββ Porsche.doc
ββ diyIdeas.docx
ββ giftIdeas.txt
ββ images/
ββ funnyCat.gif
ββ holidays/
β ββ meAtTheBeach.jpeg
β ββ meAtTheZoo.jpeg
ββ landscape.jpeg
Tip
All code below is availabe in jfiletreeprettyprinter-examples submodule.
- Filtering
- Sorting
- Emojis β€οΈ
- Child limit
- Line extension
- Compact directories
- Max depth
- Tree format
Files and directories can be selectively included or excluded using a custom PathMatcher.
Filtering applies independently to files and directories. Files are filtered only if their parent directory passes the directory filter. If none of a directoryβs children match, the directory is still displayed.
The PathMatchers class provides several ready-to-use methods for creating and combining common matchers.
// Example: Filtering.java
var excludeDirWithNoJavaFiles = PathMatchers.not(PathMatchers.hasNameEndingWith("no_java_file"));
var hasJavaExtension = PathMatchers.hasExtension("java");
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(
options -> options
.filterDirectories(excludeDirWithNoJavaFiles)
.filterFiles(hasJavaExtension)
)
.build();filtering/
ββ dir_with_java_files/
β ββ file_B.java
β ββ file_E.java
ββ dir_with_nested_java_files/
β ββ nested_dir_with_java_files/
β ββ file_G.java
β ββ file_J.java
ββ file_A.java
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 PathSorts class provides a set of basic, ready-to-use comparators, as well as a builder for creating your own tailor-made sort.
// Example: Sorting.java
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.sort(PathSorts.DIRECTORY_FIRST))
.build();sorting/
ββ c_dir/
β ββ c_file
ββ d_dir/
β ββ d_b_dir/
β β ββ d_b_file
β ββ d_a_file
ββ a_file
ββ b_file
ββ x_file
ββ y_file
You can choose to use default built-in emojis, or define your own emoji mapping.
Folders use the π emoji, and files will have an emoji depending on their name or extension (when applicable).
Define your own emoji mappings with the EmojiMapping class!
// Example: Emojis.java
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withDefaultEmojis()) // or withEmojis(EmojiMapping) for custom mapping
.build();// Run Emojis.java example for the full list of emoji mappings
π emojis/
ββ π¦ file.zip
ββ π³ Dockerfile
ββ π€΅ Jenkinsfile
ββ β file.java
ββ π readme
ββ βοΈ file.ini
ββ π file.xlsx
ββ π file.docx
ββ π file.pdf
ββ π΅ file.mp3
ββ πΌοΈ file.jpeg
ββ π¬ file.avi
You can set a fixed limit to the number of children displayed for each directory. Each directory and file that pass the filter (if set) counts for one.
// Example: ChildLimitStatic.java
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withChildLimit(3))
.build();child_limit_static/
ββ file_0_1
ββ folder_1/
β ββ file_1_1
β ββ file_1_2
β ββ file_1_3
β ββ ...
ββ folder_2/
β ββ file_2_1
β ββ file_2_2
β ββ file_2_3
β ββ ...
ββ ...
Or you can also set a limitation function, to dynamically choose the number of children displayed in each directory.
This avoids cluttering the result with known large folders (e.g. node_modules) while continuing to pretty-print other folders normally.
Use the ChildLimits class to help you build the limit function that fits your needs.
// Example: ChildLimitDynamic.java
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();child_limit_dynamic/
ββ file_0_1
ββ folder_1/
β ββ file_1_1
β ββ file_1_2
β ββ file_1_3
β ββ file_1_4
β ββ file_1_5
ββ node_modules/
ββ ...
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 (empty string is authorized).
If the function returns null, nothing is added.
Use the LineExtensions class to help you build line extension functions.
// Example: LineExtension.java
var printedPath = Path.of("src/example/resources/line_extension");
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.hasNameMatchingGlob("*.properties"), "\t// Config file")
.build();
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withLineExtension(lineExtension))
.build();line_extension/
ββ src/
ββ main/
ββ java/
β ββ api/ // All API code: controllers, etc.
β β ββ Controller.java
β ββ domain/ // All domain code: value objects, etc.
β β ββ ValueObject.java
β ββ infra/ // All infra code: database, email service, etc.
β ββ Repository.java
ββ resources/
ββ application.properties // Config file
Directory chains with a single child directory are fully expanded by default, but you can inline them into a single tree entry.
// Example: CompactDirectories.java
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withCompactDirectories(true))
.build();single_directory_child/
ββ file1
ββ file2
ββ this/is/single/directory/child/
ββ file1
ββ file2
ββ file3
You can customize the default max depth (default is 20).
// Example: MaxDepth.java
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withMaxDepth(3))
.build();max_depth/
ββ level1/
ββ file1#1
ββ file1#2
ββ level2/
ββ file2#1
ββ file2#2
ββ level3/
ββ ... (max depth reached)
Choose between different built-in tree formats, or create your own.
The default is UNICODE_BOX_DRAWING, supported by all terminals, but you can also switch to use CLASSIC_ASCII.
// Example: FileTreeFormat.java
var prettyPrinter = FileTreePrettyPrinter.builder()
.customizeOptions(options -> options.withTreeFormat(TreeFormats.CLASSIC_ASCII))
.build();tree_format/
|-- file_1
|-- file_2
`-- subFolder/
|-- subFile_1
`-- subFile_2
You can download the latest CLI release directly from https://github.com/ComputerDaddyGuy/JFileTreePrettyPrinter/releases/latest.
Choose the archive for your platform (Windows, Linux, or macOS), download it, and unzip it anywhere on your system.
Note
If desired, add the executableβs folder to your systemβs PATH variable to run it from any directory.
To pretty-print a folder and its contents, simply run:
$ jfiletreeprettyprinter <folderName>Example:
$ jfiletreeprettyprinter jfiletreeprettyprinter-examples/src/main/resources/base/
base/
ββ businessPlan.pdf
ββ businessProject.pdf
ββ cars/
β ββ Ferrari.doc
β ββ Porsche.doc
ββ diyIdeas.docx
ββ giftIdeas.txt
ββ images/
ββ funnyCat.gif
ββ holidays/
β ββ meAtTheBeach.jpeg
β ββ meAtTheZoo.jpeg
ββ landscape.jpegTo get an overview of the CLIβs capabilities and available options:
$ jfiletreeprettyprinter --help
Usage: prettyprint [-dhV] [-o] [<target>]
Pretty-prints directory structure
[<target>] The path to pretty print
-d, --debug debug mode
-h, --help Show this help message and exit.
-o, --options the options file
-V, --version Print version information and exit.If the tree symbols appear as garbled characters (e.g., ΓΓΆΓ© instead of ββ), your console is likely not using UTF-8 encoding.
Set UTF-8 Encoding
# Windows
> chcp 65001
# Linux (bash, zsh)
$ export LANG=en_US.UTF-8
# macOS (bash, zsh)
$ export LC_CTYPE=UTF-8
The native CLI supports custom options through an external JSON or YAML file provided with the --options (or -o) argument.
This options file must comply with the CLI options file schema.
Tip
YAML is fully supported since itβs a superset of JSON, offering a more readable syntax.
$ jfiletreeprettyprinter myFolder --options myOptions.jsonIf no options file is explicitly provided as argument, the CLI automatically searches for one in the following order:
- Inside the target path:
A.prettyprintfile located within the directory being printed. - Beside the executable:
A.prettyprintfile in the same folder as the native executable. - In the userβs home directory:
A.prettyprintfile located in the userβs home folder. - Fallback:
If no configuration file is found, default options are used β equivalent toPrettyPrintOptions.createDefault().
Tip
Using a .prettyprint file allows each project or directory to define its own display style β no need to pass extra parameters each time.
Below is an example configuration file that demonstrates commonly used options. It should be mostly self-explanatory:
emojis: true
maxDepth: 2
compactDirectories: true
childLimit:
type: static
limit: 3
lineExtensions:
- extension: " // Main entry point"
matcher:
type: name
glob: "FileTreePrettyPrinter.java"
filter:
dir:
type: name
glob: "src/main/**"
file:
type: name
glob: "*.java"While the CLI offers broad configuration flexibility, not all features from the Java API are currently available.
Refer to the βοΈ Options Compatibility Matrix at the top of this README for a complete overview.
Path Matcher Support
The external options file supports a limited subset of matchers for defining filtering and selection logic:
| Matcher type | Description | Example | Equivalent in PathMatchers Library API |
|---|---|---|---|
name |
Matches folder or file name using a glob pattern | *.java |
hasNameMatchingGlob(String glob) |
path |
Matches a relative path (from the printed root) using a glob pattern | src/main/java/** |
hasRelativePathMatchingGlob(Path ref, String glob) |
allOf, anyOf, noneOf |
Composite matchers combining multiple matchers | n/a | allOf(...), anyOf(...), noneOf(...) |
Note
The term glob refers to the pattern syntax supported by FileSystem.getPathMatcher(String).
Made with β€οΈ by ComputerDaddyGuy