Show HN: Lstr – A modern, interactive tree command written in Rust
104 w108bmg 36 6/18/2025, 2:07:19 AM github.com ↗
Hi HN,
(First time poster!)
I'm the author of `lstr`. I've always loved the classic Linux `tree` command for its simplicity, but I often found myself wanting more modern features like interactivity and Git integration. So, I decided to build my own version in Rust with a philosophy of being fast, minimalist, and interactive. It was also an excuse to help learn more about Rust\!
Here's a quick look at the interactive mode:
https://raw.githubusercontent.com/bgreenwell/lstr/main/asset...
I've just released v0.2.0 with some features I think this community might find useful:
* **Interactive TUI Mode:** You can launch it with `lstr interactive`. It allows for keyboard-driven navigation, expanding/collapsing directories, and opening files in your default editor.
* **Git Status Integration:** Using the `-G` flag, `lstr` will show the Git status of every file and directory right in the tree output.
* **Shell Integration:** This is my favorite feature. In interactive mode, you can press `Ctrl+s` to quit and have `lstr` print the selected path to stdout. This lets you pipe it into other commands or use it as a visual `cd`. For example, you can add this function to your `.bashrc`/`.zshrc`:
```bash
lcd() {
local selected_path
selected_path="$(lstr interactive -gG)"
if [[ -n "$selected_path" && -d "$selected_path" ]]; then
cd "$selected_path"
fi
}
```
Then just run `lcd` to visually pick a directory and jump to it.
It also supports file-type icons (via Nerd Fonts), file sizes, permissions, and respects your `.gitignore`.The project is open-source and I would love to get your feedback.
GitHub: https://github.com/bgreenwell/lstr
Crates.io: https://crates.io/crates/lstr
Thanks for checking it out!
I'm using eza (aka exa), aliased as ls, which has "tree" built in (aliased as lt), amongst others, as replacement for "ls" and it's one of my biggest production boosts in daily commandline use. Because eza has the tree built in, and the tree is also insanely fast, I won't be needing this tool - yet. Maybe one day the interactive mode will pull me over.
Congrats on releasing. And kudo's to how well you've released it: solid README, good description, good-looking gifs with exactly the right feature highlights
I used vhs to record the gif which must not run the script in my native terminal! I’ll have to see about fixing it!
And with fuzzy matching built in? Just amazing. Good job OP.
Second off, I didn't realize how deep the dep tree would be for this type of program -- 141 total! So much of it is the url crate, itself a dep of the git crate, but there's a bunch of others too. I'm just getting into learning Rust -- is this typical of Rust projects or perhaps typical of TUI projects in general?
(EDIT to strikeout) ~~The binary is also 53M as a result whereas /usr/sbin/tree is 80K on my machine -- not really a problem on today's storage, but very roughly 500-1000x different in size isn't nothing.~~
Maybe it's linking-related? I don't know how to check really.
(EDIT: many have pointed out that you can run `cargo build --release` with other options to get a much smaller binary. Thanks for teaching me!)
That's a debug binary, and the vast majority of that is debug symbols. A release build of this project is 4.3M, an order of magnitude smaller.
Also, compiling out the default features of the git2 crate eliminates several dependencies and reduces it further to 3.6M.
https://github.com/bgreenwell/lstr/pull/5
https://github.com/rust-lang/git2-rs/pull/1168
Stripping the binary further improves it to 2.9M, and some further optimizations get it to 2.2M without any compromise to performance. (You can get it smaller by optimizing for size, but I wouldn't recommend that unless you really do value size more than performance.)
Most shells dynamically link to a runtime your OS provides "for free". The 4.3 MiB binary in question is bundling the Rust runtime and its dependencies.
For reference, a statically-compiled C++ "Hello, World" is 2.2 MiB after stripping.
The executable takes 33KB in C, 75KB in nim.
But in all seriousness, my example is quite cherrypicked, since nobody will actually statically link glibc. And even if they did, one can make use of link-time optimization to remove lots of patches of unused code. Note that this is the same strategy one would employ to debloat their Rust binaries. (Use LTO, don't aggressively inline code, etc.)
Rust binaries also dynamically link to and rely on this runtime.
I'll try with `panic = "abort"` for our next release, thanks for the reminder.
If you just think about how roughly (napkin math) 2MB can be 100k loc, that’s nuts
Further I think everyone keeps getting larger and larger memory because software keeps getting more and more bloated.
I remember when 64gb iPhone was more than enough (I don’t take pictures so just apps and data) Now my 128 is getting uncomfortable due to the os and app sizes. My next phone likely will be a 256
> First because it’s kind of a fallacy. Size is absolute not relative to something. Especially for software. No one thinks of software size primarily in the context of their disk space.
That’s exactly how most people think about file sizes.
When your disk is full, you don’t delete the smallest files first. You delete the biggest.
> Further I think everyone keeps getting larger and larger memory because software keeps getting more and more bloated.
RAM sizes have actually stagnated over the last decade.
> I remember when 64gb iPhone was more than enough (I don’t take pictures so just apps and data) Now my 128 is getting uncomfortable due to the os and app sizes. My next phone likely will be a 256
That’s because media sizes increase, not executable sizes.
And people do want higher resolution cameras, higher definition videos, improved audio quality, etc. These are genuinely desirable features.
Couple that with improved internet bandwidth allowing for content providers to push higher bitrate media, however the need to still locally cache media.
Part of it is app sizes on mobile. But it's apps in the 200mb - 2gb range that are the problem, not ones that single-digit megabytes.
What incentive does Apple have to help iOS devs get package sizes down, then?
Side-note: what theme are you using in the linked gif? It's right in the middle of my two favorite themes, onedark and gruvbox.
I do love the compiler and support tools built into Cargo (fmt, clippy, etc.).
[0]: https://github.com/solidiquis/erdtree [1]: https://github.com/Canop/broot
No comments yet