Add full-text search
- Index notes in a separate, rebuildable SQLite database (index.db) using FTS5 trigram, synced from watcher snapshots so external edits are picked up; terms under 3 characters fall back to LIKE - GET /api/v1/search?q= returns matching notes with the first matching line and a snippet; path matches rank first - Sidebar search panel (Ctrl+Shift+F) with highlighted terms and keyboard navigation; opening a result jumps to and selects the match - Restore scroll position on tab switch with scroll snapshots; restoring scrollTop drifted by a few lines after line heights were re-estimated
This commit is contained in:
1 parent
a11e0ec498
commit
55f0ee174e
13 files changed
+792
-20
No files matched your search
+18
-2
@@ -34,20 +34,23 @@ type Watcher struct {
|
||||
fw *fsnotify.Watcher
|
||||
snap map[string]fileState
|
||||
watched map[string]bool
|
||||
onScan func(notes map[string]string)
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, v *vault.Vault, hub *events.Hub) error {
|
||||
// Start 开始监听。onScan 在首次扫描及之后每次有变化的扫描后调用,参数为全部笔记的路径 -> rev(用于更新搜索索引)
|
||||
func Start(ctx context.Context, v *vault.Vault, hub *events.Hub, onScan func(notes map[string]string)) error {
|
||||
fw, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := &Watcher{v: v, hub: hub, fw: fw, snap: map[string]fileState{}, watched: map[string]bool{}}
|
||||
w := &Watcher{v: v, hub: hub, fw: fw, snap: map[string]fileState{}, watched: map[string]bool{}, onScan: onScan}
|
||||
snap, err := w.scan()
|
||||
if err != nil {
|
||||
fw.Close()
|
||||
return err
|
||||
}
|
||||
w.snap = snap
|
||||
w.onScan(notes(snap))
|
||||
go w.loop(ctx)
|
||||
return nil
|
||||
}
|
||||
@@ -90,9 +93,22 @@ func (w *Watcher) rescan() {
|
||||
}
|
||||
evs := diff(w.snap, next)
|
||||
w.snap = next
|
||||
if len(evs) > 0 {
|
||||
w.onScan(notes(next))
|
||||
}
|
||||
w.hub.Broadcast(evs...)
|
||||
}
|
||||
|
||||
func notes(snap map[string]fileState) map[string]string {
|
||||
out := make(map[string]string, len(snap))
|
||||
for p, st := range snap {
|
||||
if !st.dir {
|
||||
out[p] = st.rev
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// scan 读取当前目录树;内容版本只对新出现或大小/修改时间变化的文件重新计算
|
||||
func (w *Watcher) scan() (map[string]fileState, error) {
|
||||
entries, err := w.v.Tree()
|
||||
|
||||
Reference in new issue
Block a user