222 lines
4.9 KiB
Markdown

# Search Module
## Quick Start
### Basic Usage
```typescript
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)"
/>
```
### Standalone Search Bar
```typescript
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.
```typescript
constructor(private searchIndex: SearchIndexService) {}
// Rebuild index
this.searchIndex.rebuildIndex(notes);
// Get suggestions
const suggestions = this.searchIndex.getSuggestions('tag', '#');
```
### SearchEvaluatorService
Executes search queries.
```typescript
constructor(private evaluator: SearchEvaluatorService) {}
// Search
const results = this.evaluator.search('tag:#work', {
caseSensitive: false
});
```
### SearchAssistantService
Provides autocomplete and suggestions.
```typescript
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.
```typescript
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
```typescript
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
```typescript
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
```typescript
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
});
});
```