From 50db35b667bf202c8d81b00256a49e12c2da3c3b Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Thu, 5 Feb 2026 12:44:58 -0700 Subject: [PATCH] feat: Prioritize search matches in note title and headings Co-authored-by: aider (gemini/gemini-2.5-pro) --- src/search/search-engine.ts | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/search/search-engine.ts b/src/search/search-engine.ts index 6cb8451..8dea3dc 100644 --- a/src/search/search-engine.ts +++ b/src/search/search-engine.ts @@ -475,11 +475,45 @@ export class SearchEngine { logVerbose('Matching tokens:', foundWords) logVerbose('Getting matches locations...') - const matches = this.plugin.textProcessor.getMatches( + let matches = this.plugin.textProcessor.getMatches( note.content, foundWords, query ) + + const lowerCaseBasename = note.basename.toLowerCase() + const titleMatchWord = foundWords.find(word => + lowerCaseBasename.includes(word.toLowerCase()) + ) + + if (titleMatchWord) { + // If there's a match in the title, make it the first result with offset 0 + // And remove any other match with offset 0 to avoid duplicates if the title is at the top of the file + matches = matches.filter(m => m.offset !== 0) + matches.unshift({ match: titleMatchWord, offset: 0 }) + } else { + // If no title match, check for header matches and move them to the front + const headings = + this.plugin.app.metadataCache.getCache(note.path)?.headings ?? [] + if (headings.length > 0) { + const headingMatches: SearchMatch[] = [] + const otherMatches: SearchMatch[] = [] + for (const match of matches) { + const isHeadingMatch = headings.some( + h => + match.offset >= h.position.start.offset && + match.offset < h.position.end.offset + ) + if (isHeadingMatch) { + headingMatches.push(match) + } else { + otherMatches.push(match) + } + } + matches = [...headingMatches, ...otherMatches] + } + } + logVerbose(`Matches for note "${note.path}"`, matches) const resultNote: ResultNote = { score: result.score,