What's Changed
Detect ctags on more systems out of the box
- Homebrew's
ctags(which is universal-ctags) now detected correctly on macOS — no manualCTAGS_COMMANDneeded - Three-tier detection:
CTAGS_COMMANDenv var →universal-ctagson PATH →ctagsverified via--version - Clear error when
CTAGS_COMMANDis set but not found on PATH
Catch more file changes from editors like vim and emacs
- Atomic-write editors that
write-to-tmp + renamenow correctly trigger re-indexing, by tracking file inodes alongside mtime and size - State hash bumped to
v5— caches from v0.3.0 are invalidated on first run
Faster and more robust git status parsing
- Added
--no-ahead-behindtogit statusfor faster execution - Defensive handling for rename/copy entries in porcelain v2 output (not expected with
--no-renames, but guards against edge cases) - Fixed
.gitignore-style exclude matching to use exact line comparison instead of substring (prevents false positives like.seek-cache-oldmatching.seek-cache)
Reduced memory usage for uncommitted file indexing
- Uncommitted files are now streamed through a bounded channel instead of buffered into a single unbounded slice, keeping at most
2×parallelismfiles in flight - Non-regular files (FIFOs, sockets, devices) now skipped, preventing potential blocking reads
- Per-file reads use pre-sized buffer from
Lstatinstead ofos.ReadFile, saving an extraFstatsyscall per file
Lock improvements
- Shared search lock is now non-blocking with poll timeout, preventing indefinite hangs if an indexer is stuck
- Added jitter to lock polling backoff to prevent thundering herd, and extracted a reusable
pollLockhelper
Bug fixes
- Zoekt builder
Finish()is now always called even afterAdderrors, fixing a resource leak (ctags subprocess and open file handles) formatResultstrailing newline removal uses single-byte check instead ofstrings.TrimRight, avoiding unintended stripping of content newlines
Internal
fmt.FprintfinrepoStateFingerprintreplaced withstrings.Builder+strconvfor fewer allocationsstrings.Builder.Grow()pre-allocates fingerprint bufferxxhash.WriteStringreplacesWrite([]byte(...))incomputeStateHash, eliminating two allocations per hash- Zoekt builder created lazily on first file, avoiding ctags process spawning when there are no dirty files
- Channel fully drained on error/panic paths to prevent goroutine leaks
- Lock logic consolidated from
indexer.gointolock.go
Full Changelog: v0.3.0...v0.3.1