diff --git a/src/globals.ts b/src/globals.ts index 3ea1ce0..29c7013 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -2,6 +2,7 @@ import { EventBus } from './tools/event-bus' import { writable } from 'svelte/store' import { settings } from './settings' import type { TFile } from 'obsidian' +import { Platform } from 'obsidian' export const regexLineSplit = /\r?\n|\r|((\.|\?|!)( |\r?\n|\r))/g export const regexYaml = /^---\s*\n(.*?)\n?^---\s?/ms @@ -77,10 +78,9 @@ export function isInputComposition(): boolean { return inComposition } - /** * Plugin dependency - Chs Patch for Chinese word segmentation - * @returns + * @returns */ export function getChsSegmenter(): any | undefined { return (app as any).plugins.plugins['cm-chs-patch'] @@ -93,11 +93,15 @@ export type TextExtractorApi = { /** * Plugin dependency - Text Extractor - * @returns + * @returns */ export function getTextExtractor(): TextExtractorApi | undefined { return (app as any).plugins?.plugins?.['text-extractor']?.api } +export function isCacheEnabled(): boolean { + return !Platform.isIosApp && settings.useCache +} + export const SPACE_OR_PUNCTUATION = /[|\n\r -#%-*,-/:;?@[-\]_{}\u00A0\u00A1\u00A7\u00AB\u00B6\u00B7\u00BB\u00BF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4F\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]+/u diff --git a/src/main.ts b/src/main.ts index 28f10ae..7469075 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,10 +1,22 @@ -import { Notice, Platform, Plugin } from 'obsidian' +import { Notice, Plugin } from 'obsidian' import { OmnisearchInFileModal, OmnisearchVaultModal, } from './components/modals' -import { loadSettings, settings, SettingsTab, showExcerpt } from './settings' -import { eventBus, EventNames, indexingStep, IndexingStepType } from './globals' +import { + loadSettings, + saveSettings, + settings, + SettingsTab, + showExcerpt, +} from './settings' +import { + eventBus, + EventNames, + indexingStep, + IndexingStepType, + isCacheEnabled, +} from './globals' import api from './tools/api' import { isFileIndexable } from './tools/utils' import { database, OmnisearchCache } from './database' @@ -87,10 +99,24 @@ export default class OmnisearchPlugin extends Plugin { }) ) - await populateIndex() + await this.populateIndex() }) - executeFirstLaunchTasks(this) + this.executeFirstLaunchTasks() + } + + executeFirstLaunchTasks(): void { + const code = '1.10.0-beta.1' + if (settings.welcomeMessage !== code) { + const welcome = new DocumentFragment() + welcome.createSpan({}, span => { + span.innerHTML = `🔎 Omnisearch will soon require the Text Extractor plugin to index PDF and images. See Omnisearch settings for more information.` + }) + new Notice(welcome, 20_000) + } + settings.welcomeMessage = code + + this.saveData(settings) } async onunload(): Promise { @@ -114,64 +140,75 @@ export default class OmnisearchPlugin extends Plugin { this.ribbonButton.parentNode?.removeChild(this.ribbonButton) } } + + private async populateIndex(): Promise { + console.time('Omnisearch - Indexing total time') + indexingStep.set(IndexingStepType.ReadingFiles) + const files = app.vault.getFiles().filter(f => isFileIndexable(f.path)) + console.log(`Omnisearch - ${files.length} files total`) + + // Map documents in the background + // Promise.all(files.map(f => cacheManager.addToLiveCache(f.path))) + + if (isCacheEnabled()) { + console.time('Omnisearch - Loading index from cache') + indexingStep.set(IndexingStepType.LoadingCache) + await searchEngine.loadCache() + console.timeEnd('Omnisearch - Loading index from cache') + } + + const diff = searchEngine.getDiff( + files.map(f => ({ path: f.path, mtime: f.stat.mtime })) + ) + + if (diff.toAdd.length) { + console.log( + 'Omnisearch - Total number of files to add/update: ' + diff.toAdd.length + ) + } + if (diff.toRemove.length) { + console.log( + 'Omnisearch - Total number of files to remove: ' + diff.toRemove.length + ) + } + + if (diff.toAdd.length >= 1000 && isCacheEnabled()) { + new Notice( + `Omnisearch - ${diff.toAdd.length} files need to be indexed. Obsidian may experience stutters and freezes during the process`, + 10_000 + ) + } + + indexingStep.set(IndexingStepType.IndexingFiles) + searchEngine.removeFromPaths(diff.toRemove.map(o => o.path)) + await searchEngine.addFromPaths(diff.toAdd.map(o => o.path)) + + if ((diff.toRemove.length || diff.toAdd.length) && isCacheEnabled()) { + indexingStep.set(IndexingStepType.WritingCache) + + // Disable settings.useCache while writing the cache, in case it freezes + settings.useCache = false + saveSettings(this) + + // Write the cache + await searchEngine.writeToCache() + + // Re-enable settings.caching + settings.useCache = true + saveSettings(this) + } + + console.timeEnd('Omnisearch - Indexing total time') + if (diff.toAdd.length >= 1000) { + new Notice(`Omnisearch - Your files have been indexed.`) + } + indexingStep.set(IndexingStepType.Done) + } } /** * Read the files and feed them to Minisearch */ -async function populateIndex(): Promise { - console.time('Omnisearch - Indexing total time') - indexingStep.set(IndexingStepType.ReadingFiles) - const files = app.vault.getFiles().filter(f => isFileIndexable(f.path)) - console.log(`Omnisearch - ${files.length} files total`) - - // Map documents in the background - // Promise.all(files.map(f => cacheManager.addToLiveCache(f.path))) - - if (!Platform.isIosApp) { - console.time('Omnisearch - Loading index from cache') - indexingStep.set(IndexingStepType.LoadingCache) - await searchEngine.loadCache() - console.timeEnd('Omnisearch - Loading index from cache') - } - - const diff = searchEngine.getDiff( - files.map(f => ({ path: f.path, mtime: f.stat.mtime })) - ) - - if (diff.toAdd.length) { - console.log( - 'Omnisearch - Total number of files to add/update: ' + diff.toAdd.length - ) - } - if (diff.toRemove.length) { - console.log( - 'Omnisearch - Total number of files to remove: ' + diff.toRemove.length - ) - } - - if (diff.toAdd.length >= 1000 && !Platform.isIosApp) { - new Notice( - `Omnisearch - ${diff.toAdd.length} files need to be indexed. Obsidian may experience stutters and freezes during the process`, - 10_000 - ) - } - - indexingStep.set(IndexingStepType.IndexingFiles) - searchEngine.removeFromPaths(diff.toRemove.map(o => o.path)) - await searchEngine.addFromPaths(diff.toAdd.map(o => o.path)) - - if (diff.toRemove.length || diff.toAdd.length) { - indexingStep.set(IndexingStepType.WritingCache) - await searchEngine.writeToCache() - } - - console.timeEnd('Omnisearch - Indexing total time') - if (diff.toAdd.length >= 1000) { - new Notice(`Omnisearch - Your files have been indexed.`) - } - indexingStep.set(IndexingStepType.Done) -} async function cleanOldCacheFiles() { const toDelete = [ @@ -191,20 +228,6 @@ async function cleanOldCacheFiles() { } } -function executeFirstLaunchTasks(plugin: Plugin) { - const code = '1.10.0-beta.1' - if (settings.welcomeMessage !== code) { - const welcome = new DocumentFragment() - welcome.createSpan({}, span => { - span.innerHTML = `🔎 Omnisearch will soon require the Text Extractor plugin to index PDF and images. See Omnisearch settings for more information.` - }) - new Notice(welcome, 20_000) - } - settings.welcomeMessage = code - - plugin.saveData(settings) -} - function registerAPI(plugin: OmnisearchPlugin): void { // Url scheme for obsidian://omnisearch?query=foobar plugin.registerObsidianProtocolHandler('omnisearch', params => { diff --git a/src/search/omnisearch.ts b/src/search/omnisearch.ts index 6265bdd..96cdd1a 100644 --- a/src/search/omnisearch.ts +++ b/src/search/omnisearch.ts @@ -348,9 +348,6 @@ export class Omnisearch { } public async writeToCache(): Promise { - if (Platform.isIosApp) { - return - } await cacheManager.writeMinisearchCache( this.minisearch, this.indexedDocuments diff --git a/src/settings.ts b/src/settings.ts index 777a6b6..e059de7 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -8,7 +8,7 @@ import { } from 'obsidian' import { writable } from 'svelte/store' import { database } from './database' -import { getTextExtractor } from './globals' +import { getTextExtractor, isCacheEnabled } from './globals' import type OmnisearchPlugin from './main' interface WeightingSettings { @@ -19,6 +19,8 @@ interface WeightingSettings { } export interface OmnisearchSettings extends WeightingSettings { + /** Enables caching to speed up indexing */ + useCache: boolean /** Respect the "excluded files" Obsidian setting by downranking results ignored files */ hideExcluded: boolean /** Ignore diacritics when indexing files */ @@ -160,6 +162,19 @@ export class SettingsTab extends PluginSettingTab { new Setting(containerEl).setName('Behavior').setHeading() + // Caching + new Setting(containerEl) + .setName('Save index to cache') + .setDesc( + 'Enable caching to speed up indexing time. In rare cases, the cache write may cause a freeze in Obsidian. This option will disable itself if it happens.' + ) + .addToggle(toggle => + toggle.setValue(settings.useCache).onChange(async v => { + settings.useCache = v + await saveSettings(this.plugin) + }) + ) + // Respect excluded files new Setting(containerEl) .setName('Respect Obsidian\'s "Excluded Files"') @@ -336,7 +351,7 @@ export class SettingsTab extends PluginSettingTab { //#endregion Results Weighting //#region Danger Zone - if (!Platform.isIosApp) { + if (isCacheEnabled()) { new Setting(containerEl).setName('Danger Zone').setHeading() const resetCacheDesc = new DocumentFragment() @@ -371,6 +386,7 @@ export class SettingsTab extends PluginSettingTab { } export const DEFAULT_SETTINGS: OmnisearchSettings = { + useCache: true, hideExcluded: false, ignoreDiacritics: true, indexedFileTypes: [] as string[],