How Zakirullin Files.md Inline Search Works: Fuzzy File Finding in Vanilla JS
Zakirullin Files.md implements a fuzzy inline search using Levenshtein distance scoring, directory-aware heuristics, and keyboard-navigable results to help users instantly locate markdown files.
The zakirullin/files.md repository is a lightweight, browser-based markdown file manager. Its inline search feature allows users to query thousands of notes without server round-trips by leveraging a custom SearchModal class defined in web/modals.js and a string-similarity algorithm housed in web/lib/similarity.js.
Initializing the Search Interface
When the application boots, web/app.js instantiates the search system with new SearchModal() and binds the global hotkey (Cmd+K or Ctrl+K) to open the modal overlay. The constructor in web/modals.js registers a keydown listener on the modal element that intercepts Enter, ArrowUp, ArrowDown, and Escape keys, forwarding them to dedicated navigation handlers.
Keyboard Event Handling
The listener maintains a focusedIndex variable and invokes updateFocusedItem() to highlight the current selection. Pressing Enter triggers the action associated with the focused result—either moveToDir or moveToFile—while Escape closes the modal and returns focus to the document.
Query Normalization and Folder Shortcuts
The search() method reads the raw input from #search-input and normalizes it to lowercase to ensure case-insensitive matching. If the query ends with a forward slash (/), the system treats it as a folder shortcut and immediately returns all files contained within that directory, bypassing fuzzy scoring.
The Fuzzy Matching Algorithm
At the heart of the inline search is a multi-stage scoring pipeline that ranks candidates using the similarity() helper imported from web/lib/similarity.js.
Levenshtein-Based Similarity Scoring
The similarity() function calculates the edit distance between the query and each candidate filename (stripping the .md extension), returning a normalized score from 0 to 100. Only files achieving a score of 70 or higher proceed to the results list.
Directory-Aware Candidate Filtering
The algorithm first excludes system directories via excludeDirs(SYSTEM_DIRS) and optionally splits queries containing slashes into directory and file components. It iterates through all searchable files using walkFilesExcludingSystemDirs, applying heavy penalties to low-priority directories such as archive, habits, and triggers to deprioritize stale or auxiliary content.
Exact-Match Heuristics and Smart Shortcuts
Beyond fuzzy matching, the engine applies specific heuristics to accelerate common workflows and improve result relevance.
Exact Directory Matches
If the query exactly matches a directory name present in the files object (supplied implicitly by web/lib/folder.js), all files inside that directory receive a perfect score of 100 and bubble to the top of the results.
"Directory File" Syntax
When the query contains a space, the left segment is interpreted as a directory name and the right segment as a partial filename. Matching files receive a high priority score of 95, enabling rapid filtering such as typing "projects report" to locate report.md inside the projects folder.
Substring Fallback and Result Deduplication
If no high-scoring fuzzy matches exist, the system falls back to a simple case-insensitive substring check. The raw match length is converted to a percentage score, again applying directory-specific penalties to ensure relevant files surface first.
Deduplication and Sorting
A JavaScript Map keyed by file path ensures that each file appears only once, retaining its highest achieved score across all matching strategies. The final collection is sorted in descending order by score before rendering.
Rendering Results and Interaction
The showResults() method constructs an <li> list under #search-results. It displays matching directories first (when the user is moving messages) followed by file entries, each wired with onclick handlers that invoke moveToDir or moveToFile based on the selection type.
Practical Implementation Examples
Developers can interact with the search system programmatically:
// Open the inline search modal from a custom button
const searchModal = new SearchModal();
searchModal.open(); // Shows the modal and focuses #search-input
// Trigger a re-evaluation of the current input value
searchModal.search();
// Use the similarity algorithm independently
import { similarity } from './web/lib/similarity.js';
console.log(similarity('not', 'note')); // Outputs: "80.00"
Summary
- The inline search lives in
web/modals.jsand relies on thesimilarity()function fromweb/lib/similarity.jsto compute Levenshtein distance for fuzzy matching. - Queries are normalized to lowercase and support folder shortcuts via trailing slashes or space-separated "directory file" syntax.
- Files must score at least 70 to appear in results, with low-priority directories like
archivereceiving score penalties to reduce noise. - Results are deduplicated using a
Mapand sorted by descending relevance before rendering as an interactive, keyboard-navigable list. - Global hotkeys (
Cmd+K/Ctrl+K) and arrow-key navigation provide a complete keyboard-driven workflow.
Frequently Asked Questions
How does the similarity scoring work in Zakirullin Files?
The system uses the similarity() function in web/lib/similarity.js to calculate Levenshtein distance between the query and each filename, returning a 0-100 score. Only candidates scoring 70 or higher are included in results, with additional penalties applied to files residing in low-priority directories.
Can I search for files within a specific directory only?
Yes. Appending a forward slash (/) to your query returns all files within that folder immediately. Alternatively, use the space-separated syntax (e.g., "projects report") to target files inside a specific directory, which assigns a high priority score of 95 to matching results.
What keyboard shortcuts are available for the inline search?
Press Cmd+K (macOS) or Ctrl+K (Linux/Windows) to open the search modal. Use ArrowUp and ArrowDown to navigate through results, Enter to select the highlighted item, and Escape to close the modal without taking action.
Why are some folders excluded from search results?
The search automatically excludes system directories defined in SYSTEM_DIRS via the excludeDirs() helper. Additionally, directories such as archive, habits, and triggers receive heavy score penalties to ensure that active, current notes surface above archived or auxiliary content.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →