4.9 KiB

Search Module

Quick Start

Basic Usage

import { SearchPanelComponent } from './components/search-panel/search-panel.component';

// In your component template
<app-search-panel
  placeholder="Search in vault..."
  context="vault"
  (noteOpen)="openNote($event)"
/>
import { SearchBarComponent } from './components/search-bar/search-bar.component';

<app-search-bar
  placeholder="Search..."
  context="my-context"
  (search)="onSearch($event)"
/>

Supported Operators

Operator Description Example
file: Match file name file:.jpg
path: Match file path path:"Daily notes"
content: Match in content content:"hello"
tag: Search tags tag:#work
line: Same line line:(mix flour)
block: Same block block:(dog cat)
section: Same section section:(intro)
task: In tasks task:call
task-todo: Uncompleted tasks task-todo:review
task-done: Completed tasks task-done:meeting
match-case: Case-sensitive match-case:API
ignore-case: Case-insensitive ignore-case:test
[property] Property exists [description]
[property:value] Property value [status]:"draft"

Boolean Operators

  • AND (implicit): term1 term2
  • OR: term1 OR term2
  • NOT: -term
  • Grouping: (term1 OR term2) term3

Special Syntax

  • Exact phrase: "hello world"
  • Wildcard: test*
  • Regex: /\d{4}/

Services

SearchIndexService

Indexes vault content for fast searching.

constructor(private searchIndex: SearchIndexService) {}

// Rebuild index
this.searchIndex.rebuildIndex(notes);

// Get suggestions
const suggestions = this.searchIndex.getSuggestions('tag', '#');

SearchEvaluatorService

Executes search queries.

constructor(private evaluator: SearchEvaluatorService) {}

// Search
const results = this.evaluator.search('tag:#work', {
  caseSensitive: false
});

SearchAssistantService

Provides autocomplete and suggestions.

constructor(private assistant: SearchAssistantService) {}

// Get filtered options
const options = this.assistant.getFilteredOptions('pa');

// Get contextual suggestions
const suggestions = this.assistant.getSuggestions('path:proj');

SearchHistoryService

Manages search history.

constructor(private history: SearchHistoryService) {}

// Add to history
this.history.add('vault', 'my query');

// Get history
const items = this.history.list('vault');

// Clear history
this.history.clear('vault');

Components

SearchBarComponent

Main search input with Aa and .* buttons.

Inputs:

  • placeholder: string - Placeholder text
  • context: string - History context
  • showSearchIcon: boolean - Show search icon
  • inputClass: string - Custom CSS classes
  • initialQuery: string - Initial query value

Outputs:

  • search: { query: string; options: SearchOptions } - Search event
  • queryChange: string - Query change event

SearchResultsComponent

Displays search results with grouping.

Inputs:

  • results: SearchResult[] - Search results

Outputs:

  • noteOpen: { noteId: string; line?: number } - Note open event

SearchPanelComponent

Complete search UI (bar + results).

Inputs:

  • placeholder: string - Placeholder text
  • context: string - History context

Outputs:

  • noteOpen: { noteId: string; line?: number } - Note open event

Examples

Complex Query

const query = `
  path:projects/ 
  tag:#active 
  (Python OR JavaScript) 
  -deprecated 
  file:".md" 
  match-case:"API"
`;

const results = this.evaluator.search(query, {
  caseSensitive: false,
  regexMode: false
});

Custom Search Context

import { SearchContext } from './search-parser.types';

const context: SearchContext = {
  filePath: 'notes/test.md',
  fileName: 'test',
  fileNameWithExt: 'test.md',
  content: 'Hello world',
  tags: ['#test'],
  properties: { status: 'draft' },
  lines: ['Hello world'],
  blocks: ['Hello world'],
  sections: [{ heading: 'Title', content: 'Hello world', level: 1 }],
  tasks: [{ text: 'Do something', completed: false, line: 1 }]
};

const predicate = queryToPredicate(parsed);
const matches = predicate(context);

Performance Tips

  1. Debounce input: Avoid searching on every keystroke
  2. Limit results: Cap results at reasonable number (e.g., 100)
  3. Incremental indexing: Update index incrementally instead of full rebuild
  4. Lazy loading: Load results as user scrolls

Testing

import { parseSearchQuery } from './search-parser';

describe('Search Parser', () => {
  it('should parse file operator', () => {
    const parsed = parseSearchQuery('file:test.md');
    expect(parsed.isEmpty).toBe(false);
    // Assert AST structure
  });
});