top | item 44306041

Show HN: Lstr – A modern, interactive tree command written in Rust

227 points| w108bmg | 8 months ago |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!

66 comments

order

drabbiticus|8 months ago

First off, the display looks great!

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!)

JoshTriplett|8 months ago

> The binary is also 53M

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.)

pveierland|8 months ago

Building in release:

  cargo build --release
  du -sh ./target/release/lstr -> 4.4M
Building with other release options brings it down to 2.3M:

  [profile.release]
  codegen-units = 1
  opt-level = "s"
  lto = true
  panic = "abort"
  strip = "symbols"

fabrice_d|8 months ago

You are probably looking at a debug build. On Linux, a release build (cargo build -r) is ~4.3M, and down to ~3.5M once stripped. This could be reduced further with some tricks applied to the release build profile.

getcrunk|8 months ago

Great catch! Comments mentioned getting it down to ~2MB but that’s still humongous.

If you just think about how roughly (napkin math) 2MB can be 100k loc, that’s nuts

ethan_smith|8 months ago

Try `cargo build --release --no-default-features` to get a much smaller binary (~5-10MB) - Rust statically links dependencies but supports conditional compilation for optional features.

ipdashc|8 months ago

Seems quite cool! Though the demo gif with (what seem to be?) broken icons is a bold choice :p

w108bmg|8 months ago

lol good catch, and I totally missed it

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!

sdegutis|8 months ago

I didn't notice, I was too busy seeing how impressive and useful this tool is.

And with fuzzy matching built in? Just amazing. Good job OP.

w108bmg|8 months ago

Really appreciate all the comments and useful feedback (first Rust package). Especially ways to reduce the size of the binary!

sdegutis|8 months ago

So after writing this to learn Rust, what are your thoughts on Rust? What do you especially like and dislike about it, or what were you surprised about?

w108bmg|8 months ago

I appreciate the ecosystem of packages that seem really well maintained. I don’t love the syntax and find Rust harder to read and learn so far compared to something like golang (I’m used to R which is not a compiled language but has a great dev community).

I do love the compiler and support tools built into Cargo (fmt, clippy, etc.).

gorgoiler|8 months ago

Doing this in just over 1000 lines of code is really inspiring. I was bracing myself for something quite a lot larger and, honestly, gearing up to use that as an excuse not to delve through the code. No such luck… good!

rewgs|8 months ago

This looks awesome! Right up my alley.

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.

berkes|8 months ago

I really love all the "modern" takes on classic tools by the Rust community.

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