From fc6da987c9022eed57dfadc40b3ab8e384cec5c4 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 09:20:37 +0100 Subject: [PATCH 01/13] getFiles().find() > .getAbstractFileByPath() --- src/components/ResultItemVault.svelte | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/ResultItemVault.svelte b/src/components/ResultItemVault.svelte index 45f8f0d..9a5eeca 100644 --- a/src/components/ResultItemVault.svelte +++ b/src/components/ResultItemVault.svelte @@ -10,7 +10,7 @@ removeDiacritics, } from '../tools/utils' import ResultItemContainer from './ResultItemContainer.svelte' - import { setIcon } from 'obsidian' + import { TFile, setIcon } from 'obsidian' import { cloneDeep } from 'lodash-es' import { stringsToRegex, getMatches, makeExcerpt, highlightText } from 'src/tools/text-processing' @@ -26,10 +26,8 @@ $: { imagePath = null if (isFileImage(note.path)) { - // @ts-ignore - const file = app.vault.getFiles().find(f => f.path === note.path) - if (file) { - // @ts-ignore + const file = app.vault.getAbstractFileByPath(note.path) + if (file instanceof TFile) { imagePath = app.vault.getResourcePath(file) } } From 4a4d322f333dadf509293729d7dbf194d192c977 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 09:53:32 +0100 Subject: [PATCH 02/13] #303 - Improving Chinese result highlighting --- src/tools/text-processing.ts | 52 +++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/src/tools/text-processing.ts b/src/tools/text-processing.ts index adb5910..56c20c1 100644 --- a/src/tools/text-processing.ts +++ b/src/tools/text-processing.ts @@ -29,24 +29,46 @@ export function highlighterGroups(_substring: string, ...args: any[]) { * @returns The html string with the matches highlighted */ export function highlightText(text: string, matches: SearchMatch[]): string { + if (!matches.length) { + return text + } + const chsSegmenter = getChsSegmenter() try { - return text.replace( - new RegExp( - matches - .map(matchInfo => `\\b${escapeRegExp(matchInfo.match)}\\b`) - .join('|'), - 'giu' - ), - match => { - const matchInfo = matches.find(info => - match.match(new RegExp(`\\b${escapeRegExp(info.match)}\\b`, 'giu')) + // Text to highlight + const src = new RegExp( + matches + .map( + // This regex will match the word (with \b word boundary) + // and, if ChsSegmenter is active, the simple string (without word boundary) + matchItem => + `\\b${escapeRegExp(matchItem.match)}\\b${ + chsSegmenter ? `|${escapeRegExp(matchItem.match)}` : '' + }` ) - if (matchInfo) { - return `${match}` - } - return match - } + .join('|'), + 'giu' ) + + // Replacer function that will highlight the matches + const replacer = (match: string) => { + const matchInfo = matches.find(info => + match.match( + new RegExp( + `\\b${escapeRegExp(info.match)}\\b${ + chsSegmenter ? `|${escapeRegExp(info.match)}` : '' + }`, + 'giu' + ) + ) + ) + if (matchInfo) { + return `${match}` + } + return match + } + + // Effectively highlight the text + return text.replace(src, replacer) } catch (e) { console.error('Omnisearch - Error in highlightText()', e) return text From beb4f191dc3036108d3fb43e486257486bebc5ab Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 10:29:41 +0100 Subject: [PATCH 03/13] #306 - Reworked search field auto-fill --- src/cache-manager.ts | 3 +++ src/components/ModalVault.svelte | 3 --- src/components/modals.ts | 41 +++++++++++++++++++++----------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/cache-manager.ts b/src/cache-manager.ts index 3503b23..06f79fd 100644 --- a/src/cache-manager.ts +++ b/src/cache-manager.ts @@ -217,6 +217,9 @@ class CacheManager { await database.searchHistory.bulkAdd(history) } + /** + * @returns The search history, in reverse chronological order + */ public async getSearchHistory(): Promise> { const data = (await database.searchHistory.toArray()) .reverse() diff --git a/src/components/ModalVault.svelte b/src/components/ModalVault.svelte index 5f5ea9a..5c3ef27 100644 --- a/src/components/ModalVault.svelte +++ b/src/components/ModalVault.svelte @@ -102,9 +102,6 @@ eventBus.on('vault', Action.PrevSearchHistory, prevSearchHistory) eventBus.on('vault', Action.NextSearchHistory, nextSearchHistory) await NotesIndex.refreshIndex() - if (settings.showPreviousQueryResults) { - previousQuery = (await cacheManager.getSearchHistory())[0] - } }) onDestroy(() => { diff --git a/src/components/modals.ts b/src/components/modals.ts index eaeef5d..ab17381 100644 --- a/src/components/modals.ts +++ b/src/components/modals.ts @@ -4,6 +4,7 @@ import ModalVault from './ModalVault.svelte' import ModalInFile from './ModalInFile.svelte' import { Action, eventBus, EventNames, isInputComposition } from '../globals' import { settings } from '../settings' +import { cacheManager } from 'src/cache-manager' abstract class OmnisearchModal extends Modal { protected constructor(app: App) { @@ -142,25 +143,37 @@ abstract class OmnisearchModal extends Modal { } export class OmnisearchVaultModal extends OmnisearchModal { + /** + * Instanciate the Omnisearch vault modal + * @param app + * @param query The query to pre-fill the search field with + */ constructor(app: App, query?: string) { super(app) - // Get selected text - const selection = app.workspace.getActiveViewOfType(MarkdownView)?.editor.getSelection() + // Selected text in the editor + const selectedText = app.workspace + .getActiveViewOfType(MarkdownView) + ?.editor.getSelection() - const cmp = new ModalVault({ - target: this.modalEl, - props: { - modal: this, - previousQuery: selection ?? query, - }, + cacheManager.getSearchHistory().then(history => { + // Previously searched query (if enabled in settings) + const previous = settings.showPreviousQueryResults ? history[0] : null + + // Instantiate and display the Svelte component + const cmp = new ModalVault({ + target: this.modalEl, + props: { + modal: this, + previousQuery: query || selectedText || previous || '', + }, + }) + this.onClose = () => { + // Since the component is manually created, + // we also need to manually destroy it + cmp.$destroy() + } }) - - this.onClose = () => { - // Since the component is manually created, - // we also need to manually destroy it - cmp.$destroy() - } } } From 4735d1dac3184d4fcb9fb4a0fb7ef630573b9b2b Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 11:03:49 +0100 Subject: [PATCH 04/13] Moved "show previous query" setting --- src/settings.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 760422c..04dda3f 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -220,6 +220,17 @@ export class SettingsTab extends PluginSettingTab { }) ) + // Show previous query results + new Setting(containerEl) + .setName('Show previous query results') + .setDesc('Re-executes the previous query when opening Omnisearch.') + .addToggle(toggle => + toggle.setValue(settings.showPreviousQueryResults).onChange(async v => { + settings.showPreviousQueryResults = v + await saveSettings(this.plugin) + }) + ) + // Respect excluded files new Setting(containerEl) .setName('Respect Obsidian\'s "Excluded Files"') @@ -367,17 +378,6 @@ export class SettingsTab extends PluginSettingTab { }) ) - // Show previous query results - new Setting(containerEl) - .setName('Show previous query results') - .setDesc('Re-executes the previous query when opening Omnisearch.') - .addToggle(toggle => - toggle.setValue(settings.showPreviousQueryResults).onChange(async v => { - settings.showPreviousQueryResults = v - await saveSettings(this.plugin) - }) - ) - // Show "Create note" button const createBtnDesc = new DocumentFragment() createBtnDesc.createSpan({}, span => { From 21df489a0b43f634d3cdf6e7b4e9b258e0c5ee61 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 11:18:43 +0100 Subject: [PATCH 05/13] #298 - enabled case-insensitivity --- src/tools/notes.ts | 2 +- src/tools/text-processing.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/notes.ts b/src/tools/notes.ts index 2d61574..4edca68 100644 --- a/src/tools/notes.ts +++ b/src/tools/notes.ts @@ -38,7 +38,7 @@ export async function openNote( return } const pos = view.editor.offsetToPos(offset) - pos.ch = 0 + // pos.ch = 0 view.editor.setCursor(pos) view.editor.scrollIntoView({ diff --git a/src/tools/text-processing.ts b/src/tools/text-processing.ts index 56c20c1..5a5e8e9 100644 --- a/src/tools/text-processing.ts +++ b/src/tools/text-processing.ts @@ -115,7 +115,7 @@ export function stringsToRegex(strings: string[]): RegExp { ')' + `(${strings.map(s => escapeRegExp(s)).join('|')})` - return new RegExp(`${joined}`, 'gu') + return new RegExp(`${joined}`, 'gui') } export function getMatches( From c418b8a6b75f82d31cff9eba85b5e21ba41f362b Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 12:18:37 +0100 Subject: [PATCH 06/13] Fixed "create note" button position --- assets/styles.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assets/styles.css b/assets/styles.css index 2bec00f..e3088a8 100644 --- a/assets/styles.css +++ b/assets/styles.css @@ -78,10 +78,15 @@ .omnisearch-input-container { display: flex; + align-items: center; flex-direction: row; gap: 5px; } +.omnisearch-input-container>button { + margin-right: var(--size-4-3); +} + @media only screen and (max-width: 600px) { .omnisearch-input-container { flex-direction: column; From 285c4e925795ab5dbe8985e9ef25000b2cd360e3 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 12:19:04 +0100 Subject: [PATCH 07/13] Fixed bug where "Searching..." label wouldn't disappear --- src/components/InputSearch.svelte | 2 +- src/components/ModalVault.svelte | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/InputSearch.svelte b/src/components/InputSearch.svelte index 15b4df2..b940547 100644 --- a/src/components/InputSearch.svelte +++ b/src/components/InputSearch.svelte @@ -59,4 +59,4 @@ type="text" /> - + \ No newline at end of file diff --git a/src/components/ModalVault.svelte b/src/components/ModalVault.svelte index 5c3ef27..626f946 100644 --- a/src/components/ModalVault.svelte +++ b/src/components/ModalVault.svelte @@ -29,6 +29,7 @@ import { cacheManager } from '../cache-manager' import { searchEngine } from 'src/search/omnisearch' import { cancelable, CancelablePromise } from 'cancelable-promise' + import { debounce } from 'lodash-es' export let modal: OmnisearchVaultModal export let previousQuery: string | undefined @@ -59,10 +60,7 @@ createInCurrentPaneKey = 'shift ↵' } $: if (searchQuery) { - searching = true - updateResults().then(() => { - searching = false - }) + updateResultsDebounced() } else { searching = false resultNotes = [] @@ -79,11 +77,11 @@ indexingStepDesc = 'Indexing files...' break case IndexingStepType.WritingCache: - updateResults() + updateResultsDebounced() indexingStepDesc = 'Updating cache...' break default: - updateResults() + updateResultsDebounced() indexingStepDesc = '' break } @@ -102,6 +100,7 @@ eventBus.on('vault', Action.PrevSearchHistory, prevSearchHistory) eventBus.on('vault', Action.NextSearchHistory, nextSearchHistory) await NotesIndex.refreshIndex() + await updateResultsDebounced() }) onDestroy(() => { @@ -129,6 +128,7 @@ let cancelableQuery: CancelablePromise | null = null async function updateResults() { + searching = true // If search is already in progress, cancel it and start a new one if (cancelableQuery) { cancelableQuery.cancel() @@ -143,8 +143,11 @@ resultNotes = await cancelableQuery selectedIndex = 0 await scrollIntoView() + searching = false } + const updateResultsDebounced = debounce(updateResults, 100) + function onClick(evt?: MouseEvent | KeyboardEvent) { if (!selectedNote) return if (evt?.ctrlKey) { From 8355489bcd9a2f66edfaf878b5dff233418825d2 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 13:22:06 +0100 Subject: [PATCH 08/13] #304 - Index more tokens, words split by brackets/parentheses --- src/globals.ts | 1 + src/search/omnisearch.ts | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/globals.ts b/src/globals.ts index f12945f..986c7c0 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -125,3 +125,4 @@ const separators = .slice(1, -1) export const SPACE_OR_PUNCTUATION_UNIQUE = new RegExp(`${separators}`, 'u') export const SPACE_OR_PUNCTUATION = new RegExp(`${separators}+`, 'u') +export const BRACKETS_AND_SPACE = /[|\[\]\(\)<>\{\} \t\n\r]/u diff --git a/src/search/omnisearch.ts b/src/search/omnisearch.ts index 6adf19b..4e3f141 100644 --- a/src/search/omnisearch.ts +++ b/src/search/omnisearch.ts @@ -1,6 +1,11 @@ import MiniSearch, { type Options, type SearchResult } from 'minisearch' import type { DocumentRef, IndexedDocument, ResultNote } from '../globals' -import { chsRegex, getChsSegmenter, SPACE_OR_PUNCTUATION } from '../globals' +import { + BRACKETS_AND_SPACE, + chsRegex, + getChsSegmenter, + SPACE_OR_PUNCTUATION, +} from '../globals' import { settings } from '../settings' import { chunkArray, @@ -17,6 +22,8 @@ import { sortBy } from 'lodash-es' import { getMatches, stringsToRegex } from 'src/tools/text-processing' const tokenize = (text: string): string[] => { + const words = text.split(BRACKETS_AND_SPACE) + let tokens = text.split(SPACE_OR_PUNCTUATION) // Split hyphenated tokens @@ -25,15 +32,22 @@ const tokenize = (text: string): string[] => { // Split camelCase tokens into "camel" and "case tokens = [...tokens, ...tokens.flatMap(splitCamelCase)] + // Add whole words (aka "not tokens") + tokens = [...tokens, ...words] + // When enabled, we only use the chsSegmenter, // and not the other custom tokenizers const chsSegmenter = getChsSegmenter() if (chsSegmenter) { - tokens = tokens.flatMap(word => + const chs = tokens.flatMap(word => chsRegex.test(word) ? chsSegmenter.cut(word) : [word] ) + tokens = [...tokens, ...chs] } + // Remove duplicates + tokens = [...new Set(tokens)] + return tokens } From 8832ce7b78c30edcaa503ca995b6c7f825131774 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 14:02:45 +0100 Subject: [PATCH 09/13] #310 - Server notice display is now opt-out --- src/settings.ts | 14 ++++++++++++++ src/tools/api-server.ts | 8 ++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 04dda3f..7abf9a5 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -61,6 +61,7 @@ export interface OmnisearchSettings extends WeightingSettings { fuzziness: '0' | '1' | '2' httpApiEnabled: boolean httpApiPort: string + httpApiNotice: boolean } /** @@ -504,6 +505,18 @@ export class SettingsTab extends PluginSettingTab { await saveSettings(this.plugin) }) }) + + new Setting(containerEl) + .setName('Show a notification when the server starts') + .setDesc( + 'Will display a notification if the server is enabled, at Obsidian startup.' + ) + .addToggle(toggle => + toggle.setValue(settings.httpApiNotice).onChange(async v => { + settings.httpApiNotice = v + await saveSettings(this.plugin) + }) + ) } //#endregion HTTP Server @@ -613,6 +626,7 @@ export const DEFAULT_SETTINGS: OmnisearchSettings = { httpApiEnabled: false, httpApiPort: '51361', + httpApiNotice: true, welcomeMessage: '', verboseLogging: false, diff --git a/src/tools/api-server.ts b/src/tools/api-server.ts index b4708b6..05bce47 100644 --- a/src/tools/api-server.ts +++ b/src/tools/api-server.ts @@ -47,7 +47,9 @@ export function getServer() { }, () => { console.log(`Omnisearch - Started HTTP server on port ${port}`) - new Notice(`Omnisearch - Started HTTP server on port ${port}`) + if (settings.httpApiNotice) { + new Notice(`Omnisearch - Started HTTP server on port ${port}`) + } } ) @@ -61,7 +63,9 @@ export function getServer() { close() { server.close() console.log(`Omnisearch - Terminated HTTP server`) - new Notice(`Omnisearch - Terminated HTTP server`) + if (settings.httpApiNotice) { + new Notice(`Omnisearch - Terminated HTTP server`) + } }, } } From 1e6478d83e0341add21ebb162acf42f2de91a8e5 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 1 Nov 2023 14:51:07 +0100 Subject: [PATCH 10/13] Cleaned some warnings from the deprecated global app object --- src/components/ModalInFile.svelte | 5 +++-- src/components/ModalVault.svelte | 5 ++++- src/components/ResultItemVault.svelte | 3 ++- src/components/modals.ts | 2 ++ src/main.ts | 20 ++++++++++---------- src/settings.ts | 8 ++++---- src/tools/api-server.ts | 2 +- 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/components/ModalInFile.svelte b/src/components/ModalInFile.svelte index b73814f..21363d9 100644 --- a/src/components/ModalInFile.svelte +++ b/src/components/ModalInFile.svelte @@ -1,7 +1,7 @@