Feature description
Add a new boolean option gitignore (default false). When enabled, lf automatically hides files ignored by .gitignore when inside a git worktree, and falls back to normal hiddenfiles behavior otherwise.
Why this cannot be done in user configuration
This was the first thing I tried :
cmd on-cd %{{
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
IGNORED=$(ls -A | git check-ignore --stdin 2>/dev/null | tr '\n' ':')
lf -remote "send $id set hiddenfiles '.git:${IGNORED}'"
else
lf -remote "send $id set hiddenfiles '.*'"
fi
}}
The problem: on-cd runs in a subprocess that does not block the UI thread. By the time lf -remote delivers the set hiddenfiles command, lf has already rendered the directory using the old patterns. The subsequent remote command forces a re-sort and redraw, producing a visible blink/flash every time you change directories. Caching the value (comparing old vs new) only reduces redundant calls -- it cannot eliminate the IPC delay inherent to the hook architecture.
Proposed implementation
The fix belongs at the directory-loading layer (nav.go), before the UI ever sees the files:
getGitIgnored(dir, names) -- calls git check-ignore --stdin -z once per directory load. Returns a map[string]bool of ignored basenames. If the directory is not inside a git worktree (or git is not installed), returns nil.
readdir -- populates file.gitIgnored for each file when inside a worktree.
dir.sort() -- uses a mutually exclusive filter:
- Inside a git worktree: hide only
gitIgnored files (and .git).
- Outside a worktree: use normal
hiddenfiles patterns.
checkDir -- detects gitignore option toggles and triggers async reloads via the existing directory reload infrastructure (same pattern used for dircounts changes).
Changes
| File |
What changed |
opts.go |
Add gitignore bool to gOpts; default false |
eval.go |
Add toggle handler; uses app.nav.renew() to trigger async reloads |
nav.go |
Add getGitIgnored, file.gitIgnored, dir.gitWorktree, and wire into filter logic |
doc.md |
Add gitignore to Quick Reference and Settings sections |
Complexity assessment
- No new Go dependencies.
nav.go already imports os/exec.
- No new goroutines. The git check runs synchronously inside the existing directory-loading goroutine.
- Performance: One
git check-ignore --stdin -z call per directory load. Negligible overhead when disabled. When enabled, batching via stdin is faster than N individual git check-ignore calls.
- Platform: Pure Go, works on any platform with git in
$PATH.
Usage
set hiddenfiles ".*"
set gitignore
- Inside a git repo: only gitignored files (plus
.git) are hidden. Normal dotfiles (e.g. .bashrc) that are not ignored remain visible.
- Outside a git repo: normal
hiddenfiles behavior applies.
- Toggle at runtime with
:set gitignore!.
Feature description
Add a new boolean option
gitignore(defaultfalse). When enabled,lfautomatically hides files ignored by.gitignorewhen inside a git worktree, and falls back to normalhiddenfilesbehavior otherwise.Why this cannot be done in user configuration
This was the first thing I tried :
cmd on-cd %{{ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then IGNORED=$(ls -A | git check-ignore --stdin 2>/dev/null | tr '\n' ':') lf -remote "send $id set hiddenfiles '.git:${IGNORED}'" else lf -remote "send $id set hiddenfiles '.*'" fi }}The problem:
on-cdruns in a subprocess that does not block the UI thread. By the timelf -remotedelivers theset hiddenfilescommand,lfhas already rendered the directory using the old patterns. The subsequent remote command forces a re-sort and redraw, producing a visible blink/flash every time you change directories. Caching the value (comparing old vs new) only reduces redundant calls -- it cannot eliminate the IPC delay inherent to the hook architecture.Proposed implementation
The fix belongs at the directory-loading layer (
nav.go), before the UI ever sees the files:getGitIgnored(dir, names)-- callsgit check-ignore --stdin -zonce per directory load. Returns amap[string]boolof ignored basenames. If the directory is not inside a git worktree (or git is not installed), returnsnil.readdir-- populatesfile.gitIgnoredfor each file when inside a worktree.dir.sort()-- uses a mutually exclusive filter:gitIgnoredfiles (and.git).hiddenfilespatterns.checkDir-- detectsgitignoreoption toggles and triggers async reloads via the existing directory reload infrastructure (same pattern used fordircountschanges).Changes
opts.gogitignore booltogOpts; defaultfalseeval.goapp.nav.renew()to trigger async reloadsnav.gogetGitIgnored,file.gitIgnored,dir.gitWorktree, and wire into filter logicdoc.mdgitignoreto Quick Reference and Settings sectionsComplexity assessment
nav.goalready importsos/exec.git check-ignore --stdin -zcall per directory load. Negligible overhead when disabled. When enabled, batching via stdin is faster than N individualgit check-ignorecalls.$PATH.Usage
.git) are hidden. Normal dotfiles (e.g..bashrc) that are not ignored remain visible.hiddenfilesbehavior applies.:set gitignore!.