Managing vault events to keep the index up-to-date
This commit is contained in:
99
src/main.ts
99
src/main.ts
@@ -1,4 +1,4 @@
|
|||||||
import { Notice, Plugin, SuggestModal } from 'obsidian'
|
import { Notice, Plugin, SuggestModal, TAbstractFile, TFile } from 'obsidian'
|
||||||
import MiniSearch from 'minisearch'
|
import MiniSearch from 'minisearch'
|
||||||
import removeMarkdown from 'remove-markdown'
|
import removeMarkdown from 'remove-markdown'
|
||||||
|
|
||||||
@@ -16,16 +16,53 @@ const regexYaml = /^---\s*\n(.*?)\n?^---\s?/ms
|
|||||||
export default class OmnisearchPlugin extends Plugin {
|
export default class OmnisearchPlugin extends Plugin {
|
||||||
minisearch: MiniSearch<OmniNote>
|
minisearch: MiniSearch<OmniNote>
|
||||||
lastSearch?: string
|
lastSearch?: string
|
||||||
|
notes: Record<string, OmniNote>
|
||||||
|
|
||||||
async instantiateMinisearch(): Promise<void> {
|
async onload(): Promise<void> {
|
||||||
|
this.instantiateMinisearch()
|
||||||
|
|
||||||
|
// Commands to display Omnisearch modal
|
||||||
|
this.addCommand({
|
||||||
|
id: 'show-modal',
|
||||||
|
name: 'Open Omnisearch',
|
||||||
|
hotkeys: [{ modifiers: ['Mod'], key: 'o' }],
|
||||||
|
callback: () => {
|
||||||
|
new OmnisearchModal(this).open()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Listeners to keep the search index up-to-date
|
||||||
|
this.registerEvent(this.app.vault.on('create', this.addToIndex.bind(this)))
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.vault.on('delete', this.removeFromIndex.bind(this)),
|
||||||
|
)
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.vault.on('modify', async file => {
|
||||||
|
this.removeFromIndex(file.path)
|
||||||
|
await this.addToIndex(file)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.vault.on('rename', async (file, oldPath) => {
|
||||||
|
this.removeFromIndex(oldPath)
|
||||||
|
await this.addToIndex(file)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
instantiateMinisearch(): void {
|
||||||
|
this.notes = {}
|
||||||
this.minisearch = new MiniSearch<OmniNote>({
|
this.minisearch = new MiniSearch<OmniNote>({
|
||||||
idField: 'path',
|
idField: 'path',
|
||||||
fields: ['body', 'title', 'name'],
|
fields: ['body', 'title', 'name'],
|
||||||
storeFields: ['body', 'title', 'name'],
|
storeFields: ['body', 'title', 'name'],
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const files = this.app.vault.getMarkdownFiles()
|
async addToIndex(file: TAbstractFile): Promise<void> {
|
||||||
for (const file of files) {
|
if (!(file instanceof TFile) || file.extension !== 'md') return
|
||||||
|
try {
|
||||||
|
console.log('Omnisearch - Indexing ' + file.path)
|
||||||
// Fetch content from the cache,
|
// Fetch content from the cache,
|
||||||
// trim the markdown, remove embeds and clear wikilinks
|
// trim the markdown, remove embeds and clear wikilinks
|
||||||
const content = clearContent(await this.app.vault.cachedRead(file))
|
const content = clearContent(await this.app.vault.cachedRead(file))
|
||||||
@@ -36,31 +73,22 @@ export default class OmnisearchPlugin extends Plugin {
|
|||||||
const title = getFirstLine(content)
|
const title = getFirstLine(content)
|
||||||
const body = removeFirstLine(content)
|
const body = removeFirstLine(content)
|
||||||
|
|
||||||
// Index those fields inside Minisearch
|
// Make the document and index it
|
||||||
this.minisearch.add({ title, body, path: file.path, name: file.name })
|
const note = { name: file.name, title, body, path: file.path }
|
||||||
|
this.minisearch.add(note)
|
||||||
|
this.notes[file.path] = note
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error('Error while indexing ' + file.name)
|
||||||
|
console.error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onload(): Promise<void> {
|
removeFromIndex(path: string): void {
|
||||||
this.app.workspace.onLayoutReady(async () => {
|
console.log('Omnisearch - Deindexing ' + path)
|
||||||
const start = new Date()
|
const note = this.notes[path]
|
||||||
await this.instantiateMinisearch()
|
this.minisearch.remove(note)
|
||||||
new Notice(
|
delete this.notes[path]
|
||||||
`Omnisearch - files indexed in ${
|
|
||||||
new Date().getTime() - start.getTime()
|
|
||||||
} ms`,
|
|
||||||
3000,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.addCommand({
|
|
||||||
id: 'show-modal',
|
|
||||||
name: 'Open Omnisearch',
|
|
||||||
hotkeys: [{ modifiers: ['Mod'], key: 'o' }],
|
|
||||||
callback: () => {
|
|
||||||
new OmnisearchModal(this).open()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,16 +112,28 @@ class OmnisearchModal extends SuggestModal<OmniNote> {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeydown(ev: KeyboardEvent): void {
|
async onKeydown(ev: KeyboardEvent): Promise<void> {
|
||||||
const noteId = this.selectedNoteId
|
const noteId = this.selectedNoteId
|
||||||
if (ev.key !== 'Enter' || !noteId) return
|
if (ev.key !== 'Enter' || !noteId) return
|
||||||
|
|
||||||
if (ev.ctrlKey) {
|
if (ev.ctrlKey) {
|
||||||
// Open in a new pane
|
// Open in a new pane
|
||||||
this.app.workspace.openLinkText(noteId, '', true)
|
await this.app.workspace.openLinkText(noteId, '', true)
|
||||||
}
|
}
|
||||||
else if (ev.shiftKey) {
|
else if (ev.shiftKey) {
|
||||||
// Create a note
|
// Create a note
|
||||||
|
try {
|
||||||
|
const file = await this.app.vault.create(
|
||||||
|
this.inputEl.value + '.md',
|
||||||
|
'# ' + this.inputEl.value,
|
||||||
|
)
|
||||||
|
await this.app.workspace.openLinkText(file.path, '')
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e.message === 'File already exists.') {
|
||||||
|
await this.app.workspace.openLinkText(this.inputEl.value, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.close()
|
this.close()
|
||||||
}
|
}
|
||||||
@@ -110,7 +150,6 @@ class OmnisearchModal extends SuggestModal<OmniNote> {
|
|||||||
const id = (record?.target as HTMLElement).getAttribute('data-note-id')
|
const id = (record?.target as HTMLElement).getAttribute('data-note-id')
|
||||||
if (id) {
|
if (id) {
|
||||||
this.selectedNoteId = id
|
this.selectedNoteId = id
|
||||||
console.log('saved note ' + id)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.mutationObserver.observe(modalEl, {
|
this.mutationObserver.observe(modalEl, {
|
||||||
@@ -142,7 +181,6 @@ class OmnisearchModal extends SuggestModal<OmniNote> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSuggestions(query: string): OmniNote[] {
|
getSuggestions(query: string): OmniNote[] {
|
||||||
console.log('query: ' + query)
|
|
||||||
this.plugin.lastSearch = query
|
this.plugin.lastSearch = query
|
||||||
|
|
||||||
const results = this.plugin.minisearch
|
const results = this.plugin.minisearch
|
||||||
@@ -154,6 +192,7 @@ class OmnisearchModal extends SuggestModal<OmniNote> {
|
|||||||
})
|
})
|
||||||
.sort((a, b) => b.score - a.score)
|
.sort((a, b) => b.score - a.score)
|
||||||
.slice(0, 50)
|
.slice(0, 50)
|
||||||
|
console.log('Omnisearch - Results:')
|
||||||
console.log(results)
|
console.log(results)
|
||||||
|
|
||||||
return results.map(result => {
|
return results.map(result => {
|
||||||
|
|||||||
Reference in New Issue
Block a user