Skip to content

Feature: .zenignore to exclude paths from vault indexing #431

Description

@yfernandes

Summary

Add support for a .zenignore file at the vault root that lets users exclude
directories and files from indexing, search, and the folder tree — using
gitignore-compatible syntax.

Motivation

Some vaults contain more than notes. When a vault directory also holds
programming artifacts (e.g. node_modules, __pycache__, build output), every
one of those files is currently walked, read for metadata, and surfaced in the
sidebar. This inflates load times and clutters the tree with content that isn't
a note.

Concretely, a single project folder in my vault indexes 2385 items, of which
2209 come from node_modules
— so ~93% of the indexing cost for that folder
is pure noise.

Current behavior

Vault content is walked in several independent places, all sharing the same
skip rules (resolveDirDescent + entry.name.startsWith('.')):

  • listNotes() — the note-metadata index (main load-time cost)
  • listFolders() — the sidebar folder tree
  • collectBuiltinSearchCandidates() — JS full-text search fallback
  • collectRipgrepSearchCandidates() — ripgrep full-text search
  • VaultWatcher — the chokidar ignored predicate for live updates

There is already precedent for path exclusion: VaultWatcher hardcodes
node_modules in its ignore predicate. That skip is not honored by the
load-time walks, and it isn't user-configurable. .zenignore generalizes it.

Proposed behavior

  • On scan, read <vault-root>/.zenignore (if present) and build a
    gitignore-compatible matcher.
  • Apply the matcher in each walk so ignored directories are skipped before
    descending into them — that's where the load-time win comes from.
  • Honor it in the watcher and both search backends so ignored paths don't
    reappear via live updates or search results.
  • Keep the existing built-in node_modules default so current behavior
    doesn't regress; .zenignore adds to it rather than replacing it.

Open questions

  • Scope: root-only .zenignore vs. nested per-directory files (like git).
    Root-only is much simpler and covers the primary use case; suggest starting
    there.
  • Syntax source: adopt exact gitignore semantics (least surprising) via a
    small dependency rather than hand-rolling glob matching?

Notes on implementation

The startsWith('.') skip + descent check is currently duplicated across the
walks. Extracting that shared skip logic into one helper first would let the
ignore matcher be threaded through a single place, keeping the feature small and
the diff easy to review.

Happy to implement this if the approach sounds good — I'd wait for agreement on scope (root-only vs. nested) before starting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions