# How Zakirullin Files.md Inline Search Works: Fuzzy File Finding in Vanilla JS

> Discover how Zakirullin Files.md inline search offers fuzzy file finding in vanilla JS. Learn about Levenshtein distance scoring and directory heuristics for instant markdown file location.

- Repository: [Artem Zakirullin/files.md](https://github.com/zakirullin/files.md)
- Tags: internals
- Published: 2026-05-21

---

**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`](https://github.com/zakirullin/files.md/blob/main/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`](https://github.com/zakirullin/files.md/blob/main/web/modals.js) and a string-similarity algorithm housed in [`web/lib/similarity.js`](https://github.com/zakirullin/files.md/blob/main/web/lib/similarity.js).

## Initializing the Search Interface

When the application boots, [`web/app.js`](https://github.com/zakirullin/files.md/blob/main/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`](https://github.com/zakirullin/files.md/blob/main/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`](https://github.com/zakirullin/files.md/blob/main/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`](https://github.com/zakirullin/files.md/blob/main/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`](https://github.com/zakirullin/files.md/blob/main/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:

```javascript
// 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.js`](https://github.com/zakirullin/files.md/blob/main/web/modals.js) and relies on the `similarity()` function from [`web/lib/similarity.js`](https://github.com/zakirullin/files.md/blob/main/web/lib/similarity.js) to 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 `archive` receiving score penalties to reduce noise.
- Results are deduplicated using a `Map` and 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`](https://github.com/zakirullin/files.md/blob/main/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.