diff --git a/src/components/ModalVault.svelte b/src/components/ModalVault.svelte index 45cfa1d..94db808 100644 --- a/src/components/ModalVault.svelte +++ b/src/components/ModalVault.svelte @@ -6,7 +6,7 @@ import { eventBus, type ResultNote } from 'src/globals' import { createNote, openNote } from 'src/notes' import { getSuggestions, reindexNotes } from 'src/search' - import { getCtrlKeyLabel, loopIndex } from 'src/utils' + import { getCtrlKeyLabel, getExtension, loopIndex } from 'src/utils' import { OmnisearchInFileModal, type OmnisearchVaultModal } from 'src/modals' import ResultItemVault from './ResultItemVault.svelte' import { Query } from 'src/query' @@ -20,7 +20,6 @@ let resultNotes: ResultNote[] = [] let query: Query $: selectedNote = resultNotes[selectedIndex] - // $: lastSearch = lastSearches[lastSearchIndex] $: if (searchQuery) { updateResults() @@ -94,6 +93,10 @@ openNote(note, newPane) } + async function onClickCreateNote(e: MouseEvent) { + await createNoteAndCloseModal() + } + async function createNoteAndCloseModal(opt?: { newLeaf: boolean }): Promise { @@ -123,7 +126,7 @@ if (file && active) { link = app.fileManager.generateMarkdownLink(file, active.path) } else { - link = `[[${selectedNote.basename}.md]]` + link = `[[${selectedNote.basename}.${getExtension(selectedNote.path)}]]` } // Inject link @@ -172,8 +175,8 @@ value="{searchQuery}" on:input="{e => (searchQuery = e.detail)}" placeholder="Omnisearch - Vault"> - {#if $settings.showCreateButton} - + {#if settings.showCreateButton} + {/if} diff --git a/src/components/ResultItemVault.svelte b/src/components/ResultItemVault.svelte index 6e62ed9..be46a88 100644 --- a/src/components/ResultItemVault.svelte +++ b/src/components/ResultItemVault.svelte @@ -1,6 +1,6 @@ @@ -29,7 +29,7 @@ {/if} - {#if $settings.showContext} + {#if $showContext}
{@html cleanedContent.replace(reg, highlighter)}
diff --git a/src/main.ts b/src/main.ts index 73d35c1..43035cd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,20 +6,12 @@ import { removeFromIndex, } from './search' import { OmnisearchInFileModal, OmnisearchVaultModal } from './modals' -import { loadSettings, settings, SettingsTab } from './settings' +import { loadSettings, settings, SettingsTab, showContext } from './settings' import { eventBus } from './globals' import { registerAPI } from '@vanakat/plugin-api' import api from './api' import { loadSearchHistory } from './search-history' -import { get } from 'svelte/store' - -// let mainWindow: { on: any; off: any } | null = null -// try { -// mainWindow = require('electron').remote.getCurrentWindow() -// } -// catch (e) { -// console.log("Can't load electron, mobile platform") -// } +import { isFileIndexable } from './utils' function _registerAPI(plugin: OmnisearchPlugin): void { registerAPI('omnisearch', api, plugin as any) @@ -31,12 +23,15 @@ function _registerAPI(plugin: OmnisearchPlugin): void { export default class OmnisearchPlugin extends Plugin { async onload(): Promise { + // additional files to index by Omnisearch + await loadSettings(this) + this.registerExtensions(settings.indexedFileTypes, 'markdown') await loadSearchHistory() _registerAPI(this) - if (get(settings).ribbonIcon) { + if (settings.ribbonIcon) { this.addRibbonButton() } @@ -44,11 +39,7 @@ export default class OmnisearchPlugin extends Plugin { eventBus.disable('vault') eventBus.disable('infile') eventBus.on('global', 'toggle-context', () => { - settings.update(s => { - s.showContext = !s.showContext - return s - }) - this.saveData(get(settings)) + showContext.set(!settings.showContext) }) // Commands to display Omnisearch modals @@ -87,7 +78,7 @@ export default class OmnisearchPlugin extends Plugin { ) this.registerEvent( this.app.vault.on('rename', async (file, oldPath) => { - if (file instanceof TFile && file.path.endsWith('.md')) { + if (file instanceof TFile && isFileIndexable(file.path)) { removeFromIndex(oldPath) await addToIndex(file) } diff --git a/src/modals.ts b/src/modals.ts index b45c7d2..f9a99b4 100644 --- a/src/modals.ts +++ b/src/modals.ts @@ -3,7 +3,6 @@ import ModalVault from './components/ModalVault.svelte' import ModalInFile from './components/ModalInFile.svelte' import { eventBus, isInputComposition } from './globals' import { settings } from './settings' -import { get } from 'svelte/store' abstract class OmnisearchModal extends Modal { protected constructor(app: App) { @@ -38,7 +37,7 @@ abstract class OmnisearchModal extends Modal { ] as const) { for (const modifier of ['Ctrl', 'Meta'] as const) { this.scope.register([modifier], key.k, e => { - if (get(settings).CtrlJK && this.app.vault.getConfig('vimMode')) { + if (settings.CtrlJK && this.app.vault.getConfig('vimMode')) { e.preventDefault() eventBus.emit('arrow-' + key.dir) } @@ -53,7 +52,7 @@ abstract class OmnisearchModal extends Modal { ] as const) { for (const modifier of ['Ctrl', 'Meta'] as const) { this.scope.register([modifier], key.k, e => { - if (get(settings).CtrlNP && this.app.vault.getConfig('vimMode')) { + if (settings.CtrlNP && this.app.vault.getConfig('vimMode')) { e.preventDefault() eventBus.emit('arrow-' + key.dir) } diff --git a/src/notes.ts b/src/notes.ts index f03e514..d013df8 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -11,7 +11,6 @@ import { } from './globals' import { stringsToRegex, wait } from './utils' import { settings } from './settings' -import { get } from 'svelte/store' /** * This is an in-memory cache of the notes, with all their computed fields @@ -26,7 +25,7 @@ export function resetNotesCache(): void { export async function loadNotesCache(): Promise { if ( - get(settings).storeIndexInFile && + settings.storeIndexInFile && (await app.vault.adapter.exists(notesCacheFilePath)) ) { try { diff --git a/src/query.ts b/src/query.ts index a88c6e2..1bb8d2a 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,4 +1,3 @@ -import { get } from 'svelte/store' import { settings } from './settings' import { removeDiacritics, stripSurroundingQuotes } from './utils' import { parseQuery } from './vendor/parse-query' @@ -23,7 +22,7 @@ export class Query { public exclusions: QueryToken[] = [] constructor(text = '') { - if (get(settings).ignoreDiacritics) text = removeDiacritics(text) + if (settings.ignoreDiacritics) text = removeDiacritics(text) const tokens = parseQuery(text.toLowerCase(), { tokenize: true }) this.exclusions = tokens.exclude.text .map(this.formatToken) diff --git a/src/search.ts b/src/search.ts index f69f80a..c73c4d8 100644 --- a/src/search.ts +++ b/src/search.ts @@ -12,13 +12,14 @@ import { extractHeadingsFromCache, getAliasesFromMetadata, getTagsFromMetadata, + isFileIndexable, removeDiacritics, stringsToRegex, stripMarkdownCharacters, wait, } from './utils' import type { Query } from './query' -import { settings as storeSettings } from './settings' +import { settings } from './settings' import { removeNoteFromCache, getNoteFromCache, @@ -31,13 +32,9 @@ import { saveNotesCacheToFile, isCacheOutdated, } from './notes' -import { get } from 'svelte/store' let minisearchInstance: MiniSearch let isIndexChanged: boolean - -const settings = get(storeSettings) - const tokenize = (text: string): string[] => { const tokens = text.split(SPACE_OR_PUNCTUATION) const chsSegmenter = (app as any).plugins.plugins['cm-chs-patch'] @@ -95,7 +92,7 @@ export async function initGlobalSearchIndex(): Promise { // Index files that are already present const start = new Date().getTime() - const allFiles = app.vault.getMarkdownFiles() + const allFiles = app.vault.getFiles().filter(f => isFileIndexable(f.path)) let files let notesSuffix @@ -302,7 +299,7 @@ export async function getSuggestions( * @returns */ export async function addToIndex(file: TAbstractFile): Promise { - if (!(file instanceof TFile) || file.extension !== 'md') { + if (!(file instanceof TFile) || !isFileIndexable(file.path)) { return } @@ -396,8 +393,8 @@ export function addNonExistingToIndex(name: string, parent: string): void { * @param path */ export function removeFromIndex(path: string): void { - if (!path.endsWith('.md')) { - console.info(`"${path}" is not a .md file`) + if (!isFileIndexable(path)) { + console.info(`"${path}" is not an indexable file`) return } const note = getNoteFromCache(path) diff --git a/src/settings.ts b/src/settings.ts index 2c45223..70908ee 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,7 +1,7 @@ import { Plugin, PluginSettingTab, Setting, SliderComponent } from 'obsidian' +import { writable } from 'svelte/store' import { notesCacheFilePath, searchIndexFilePath } from './globals' import type OmnisearchPlugin from './main' -import { get, writable } from 'svelte/store' interface WeightingSettings { weightBasename: number @@ -13,6 +13,9 @@ interface WeightingSettings { export interface OmnisearchSettings extends WeightingSettings { respectExcluded: boolean ignoreDiacritics: boolean + indexedFileTypes: string[] + storeIndexInFile: boolean + showIndexingNotices: boolean ribbonIcon: boolean showShortName: boolean @@ -20,15 +23,24 @@ export interface OmnisearchSettings extends WeightingSettings { showCreateButton: boolean CtrlJK: boolean CtrlNP: boolean - storeIndexInFile: boolean } +/** + * A store to reactively toggle the `showContext` setting on the fly + */ +export const showContext = writable(false) + export class SettingsTab extends PluginSettingTab { plugin: OmnisearchPlugin constructor(plugin: OmnisearchPlugin) { super(app, plugin) this.plugin = plugin + + showContext.subscribe(async v => { + settings.showContext = v + await saveSettings(this.plugin) + }) } display(): void { @@ -49,11 +61,8 @@ export class SettingsTab extends PluginSettingTab { 'Files that are in Obsidian\'s "Options > Files & Links > Excluded Files" list will be downranked in results.' ) .addToggle(toggle => - toggle.setValue(get(settings).respectExcluded).onChange(async v => { - settings.update(s => { - s.respectExcluded = v - return s - }) + toggle.setValue(settings.respectExcluded).onChange(async v => { + settings.respectExcluded = v await saveSettings(this.plugin) }) ) @@ -68,15 +77,33 @@ export class SettingsTab extends PluginSettingTab { .setName('Ignore diacritics') .setDesc(diacriticsDesc) .addToggle(toggle => - toggle.setValue(get(settings).ignoreDiacritics).onChange(async v => { - settings.update(s => { - s.ignoreDiacritics = v - return s - }) + toggle.setValue(settings.ignoreDiacritics).onChange(async v => { + settings.ignoreDiacritics = v await saveSettings(this.plugin) }) ) + // Additional files to index + const indexedFileTypesDesc = new DocumentFragment() + indexedFileTypesDesc.createSpan({}, span => { + span.innerHTML = `In addition to standard md files, Omnisearch can also index other plain text files.
+ Add extensions separated by a space. Example: txt org.
+ This setting will also add these files in the navigation, and they will be treated as markdown.
+ Needs a restart to fully take effect.` + }) + new Setting(containerEl) + .setName('Additional files to index') + .setDesc(indexedFileTypesDesc) + .addText(component => { + component + .setValue(settings.indexedFileTypes.join(' ')) + .setPlaceholder('Example: txt org') + .onChange(async v => { + settings.indexedFileTypes = v.split(' ') + await saveSettings(this.plugin) + }) + }) + // Store index const serializedIndexDesc = new DocumentFragment() serializedIndexDesc.createSpan({}, span => { @@ -91,13 +118,10 @@ export class SettingsTab extends PluginSettingTab { .setName('EXPERIMENTAL - Store index in file') .setDesc(serializedIndexDesc) .addToggle(toggle => - toggle.setValue(get(settings).storeIndexInFile).onChange(async v => { + toggle.setValue(settings.storeIndexInFile).onChange(async v => { await app.vault.adapter.remove(notesCacheFilePath) await app.vault.adapter.remove(searchIndexFilePath) - settings.update(s => { - s.storeIndexInFile = v - return s - }) + settings.storeIndexInFile = v await saveSettings(this.plugin) }) ) @@ -115,11 +139,8 @@ export class SettingsTab extends PluginSettingTab { 'Add a button on the sidebar to open the Vault search modal. Needs a restart to remove the button.' ) .addToggle(toggle => - toggle.setValue(get(settings).ribbonIcon).onChange(async v => { - settings.update(s => { - s.ribbonIcon = v - return s - }) + toggle.setValue(settings.ribbonIcon).onChange(async v => { + settings.ribbonIcon = v await saveSettings(this.plugin) if (v) { this.plugin.addRibbonButton() @@ -134,15 +155,8 @@ export class SettingsTab extends PluginSettingTab { 'Shows the part of the note that matches the search. Disable this to only show filenames in results.' ) .addToggle(toggle => - toggle.setValue(get(settings).showContext).onChange(async v => { - settings.update(s => { - s.showContext = v - return s - }) - await saveSettings(this.plugin) - if (v) { - this.plugin.addRibbonButton() - } + toggle.setValue(settings.showContext).onChange(async v => { + showContext.set(v) }) ) @@ -156,11 +170,8 @@ export class SettingsTab extends PluginSettingTab { .setName('Show "Create note" button') .setDesc(createBtnDesc) .addToggle(toggle => - toggle.setValue(get(settings).showCreateButton).onChange(async v => { - settings.update(s => { - s.showCreateButton = v - return s - }) + toggle.setValue(settings.showCreateButton).onChange(async v => { + settings.showCreateButton = v await saveSettings(this.plugin) }) ) @@ -170,11 +181,8 @@ export class SettingsTab extends PluginSettingTab { .setName('Show indexing notices') .setDesc('Shows a notice when indexing is done, usually at startup.') .addToggle(toggle => - toggle.setValue(get(settings).showIndexingNotices).onChange(async v => { - settings.update(s => { - s.showIndexingNotices = v - return s - }) + toggle.setValue(settings.showIndexingNotices).onChange(async v => { + settings.showIndexingNotices = v await saveSettings(this.plugin) }) ) @@ -186,11 +194,8 @@ export class SettingsTab extends PluginSettingTab { 'In the search results, only show the note name, without the full path.' ) .addToggle(toggle => - toggle.setValue(get(settings).showShortName).onChange(async v => { - settings.update(s => { - s.showShortName = v - return s - }) + toggle.setValue(settings.showShortName).onChange(async v => { + settings.showShortName = v await saveSettings(this.plugin) }) ) @@ -230,11 +235,8 @@ export class SettingsTab extends PluginSettingTab { 'Use [Ctrl/Cmd]+j/k to navigate up/down in the results, if Vim mode is enabled' ) .addToggle(toggle => - toggle.setValue(get(settings).CtrlJK).onChange(async v => { - settings.update(s => { - s.CtrlJK = v - return s - }) + toggle.setValue(settings.CtrlJK).onChange(async v => { + settings.CtrlJK = v await saveSettings(this.plugin) }) ) @@ -244,11 +246,8 @@ export class SettingsTab extends PluginSettingTab { 'Use [Ctrl/Cmd]+n/p to navigate up/down in the results, if Vim mode is enabled' ) .addToggle(toggle => - toggle.setValue(get(settings).CtrlNP).onChange(async v => { - settings.update(s => { - s.CtrlNP = v - return s - }) + toggle.setValue(settings.CtrlNP).onChange(async v => { + settings.CtrlNP = v await saveSettings(this.plugin) }) ) @@ -258,13 +257,10 @@ export class SettingsTab extends PluginSettingTab { weightSlider(cb: SliderComponent, key: keyof WeightingSettings): void { cb.setLimits(1, 3, 0.1) - cb.setValue(get(settings)[key]) + cb.setValue(settings[key]) cb.setDynamicTooltip() cb.onChange(v => { - settings.update(s => { - s[key] = v - return s - }) + settings[key] = v saveSettings(this.plugin) }) } @@ -273,6 +269,7 @@ export class SettingsTab extends PluginSettingTab { export const DEFAULT_SETTINGS: OmnisearchSettings = { respectExcluded: true, ignoreDiacritics: true, + indexedFileTypes: [] as string[], showIndexingNotices: false, showShortName: false, @@ -291,14 +288,13 @@ export const DEFAULT_SETTINGS: OmnisearchSettings = { storeIndexInFile: false, } as const -export const settings = writable( - Object.assign({}, DEFAULT_SETTINGS) as OmnisearchSettings -) +export let settings = Object.assign({}, DEFAULT_SETTINGS) as OmnisearchSettings export async function loadSettings(plugin: Plugin): Promise { - settings.set(Object.assign({}, DEFAULT_SETTINGS, await plugin.loadData())) + settings = Object.assign({}, DEFAULT_SETTINGS, await plugin.loadData()) + showContext.set(settings.showContext) } export async function saveSettings(plugin: Plugin): Promise { - await plugin.saveData(get(settings)) + await plugin.saveData(settings) } diff --git a/src/utils.ts b/src/utils.ts index cae26af..b09cfb6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,6 +9,7 @@ import { regexYaml, } from './globals' import type { SearchMatch } from './globals' +import { settings } from './settings' export function highlighter(str: string): string { return `${str}` @@ -170,3 +171,15 @@ export function removeDiacritics(str: string): string { export function getCtrlKeyLabel(): 'ctrl' | '⌘' { return Platform.isMacOS ? '⌘' : 'ctrl' } + +export function isFileIndexable(path: string): boolean { + return ( + path.endsWith('.md') || + settings.indexedFileTypes.some(t => path.endsWith(`.${t}`)) + ) +} + +export function getExtension(path: string): string { + const split = path.split('.') + return split[split.length - 1] +}