From ce00f56a9b57b3dd07b35a496d0e3e7f7545ef18 Mon Sep 17 00:00:00 2001 From: Nicky Nicolson Date: Wed, 29 Nov 2023 16:11:51 +0000 Subject: [PATCH] rm suggesters --- .../suggesters/FileNameFormatSuggester.ts | 83 -------- src/settings/suggesters/FileSuggester.ts | 30 --- src/settings/suggesters/FolderSuggester.ts | 30 --- src/settings/suggesters/suggest.ts | 180 ------------------ 4 files changed, 323 deletions(-) delete mode 100644 src/settings/suggesters/FileNameFormatSuggester.ts delete mode 100644 src/settings/suggesters/FileSuggester.ts delete mode 100644 src/settings/suggesters/FolderSuggester.ts delete mode 100644 src/settings/suggesters/suggest.ts diff --git a/src/settings/suggesters/FileNameFormatSuggester.ts b/src/settings/suggesters/FileNameFormatSuggester.ts deleted file mode 100644 index db5246a..0000000 --- a/src/settings/suggesters/FileNameFormatSuggester.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { App } from 'obsidian'; -import { TextInputSuggest } from './suggest'; - -// == Format Syntax Suggestion == // -export const DATE_SYNTAX = '{{DATE}}'; -export const DATE_FORMAT_SYNTAX = '{{DATE:}}'; -export const DATE_SYNTAX_SUGGEST_REGEX = /{{D?A?T?E?}?}?$/i; -export const DATE_FORMAT_SYNTAX_SUGGEST_REGEX = /{{D?A?T?E?:?$|{{DATE:[^\n\r}]*}}$/i; - -export const AUTHOR_SYNTAX = '{{author}}'; -export const AUTHOR_SYNTAX_SUGGEST_REGEX = /{{a?u?t?h?o?r?}?}?$/i; - -export const TITLE_SYNTAX = '{{title}}'; -export const TITLE_SYNTAX_SUGGEST_REGEX = /{{t?i?t?l?e?}?}?$/i; - -export class FileNameFormatSuggest extends TextInputSuggest { - private lastInput = ''; - - constructor(public app: App, public inputEl: HTMLInputElement | HTMLTextAreaElement) { - super(app, inputEl); - } - - getSuggestions(inputStr: string): string[] { - const cursorPosition: number = this.inputEl.selectionStart; - const lookbehind = 15; - const inputBeforeCursor = inputStr.substr(cursorPosition - lookbehind, lookbehind); - const suggestions: string[] = []; - - this.processToken(inputBeforeCursor, (match: RegExpMatchArray, suggestion: string) => { - this.lastInput = match[0]; - suggestions.push(suggestion); - }); - - return suggestions; - } - - selectSuggestion(item: string): void { - const cursorPosition: number = this.inputEl.selectionStart; - const lastInputLength: number = this.lastInput.length; - const currentInputValue: string = this.inputEl.value; - let insertedEndPosition = 0; - - const insert = (text: string, offset = 0) => { - return `${currentInputValue.substr( - 0, - cursorPosition - lastInputLength + offset, - )}${text}${currentInputValue.substr(cursorPosition)}`; - }; - - this.processToken(item, (_match, suggestion) => { - if (item.contains(suggestion)) { - this.inputEl.value = insert(item); - insertedEndPosition = cursorPosition - lastInputLength + item.length; - - if (item === DATE_FORMAT_SYNTAX) { - insertedEndPosition -= 2; - } - } - }); - - this.inputEl.trigger('input'); - this.close(); - this.inputEl.setSelectionRange(insertedEndPosition, insertedEndPosition); - } - - renderSuggestion(value: string, el: HTMLElement): void { - if (value) el.setText(value); - } - - private processToken(input: string, callback: (match: RegExpMatchArray, suggestion: string) => void) { - const dateFormatMatch = DATE_FORMAT_SYNTAX_SUGGEST_REGEX.exec(input); - if (dateFormatMatch) callback(dateFormatMatch, DATE_FORMAT_SYNTAX); - - const dateMatch = DATE_SYNTAX_SUGGEST_REGEX.exec(input); - if (dateMatch) callback(dateMatch, DATE_SYNTAX); - - const authorMatch = AUTHOR_SYNTAX_SUGGEST_REGEX.exec(input); - if (authorMatch) callback(authorMatch, AUTHOR_SYNTAX); - - const titleMatch = TITLE_SYNTAX_SUGGEST_REGEX.exec(input); - if (titleMatch) callback(titleMatch, TITLE_SYNTAX); - } -} diff --git a/src/settings/suggesters/FileSuggester.ts b/src/settings/suggesters/FileSuggester.ts deleted file mode 100644 index 8d602ec..0000000 --- a/src/settings/suggesters/FileSuggester.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes - -import { TAbstractFile, TFile } from 'obsidian'; -import { TextInputSuggest } from './suggest'; - -export class FileSuggest extends TextInputSuggest { - getSuggestions(inputStr: string): TFile[] { - const abstractFiles = this.app.vault.getAllLoadedFiles(); - const files: TFile[] = []; - const lowerCaseInputStr = inputStr.toLowerCase(); - - abstractFiles.forEach((file: TAbstractFile) => { - if (file instanceof TFile && file.extension === 'md' && file.path.toLowerCase().contains(lowerCaseInputStr)) { - files.push(file); - } - }); - - return files; - } - - renderSuggestion(file: TFile, el: HTMLElement): void { - el.setText(file.path); - } - - selectSuggestion(file: TFile): void { - this.inputEl.value = file.path; - this.inputEl.trigger('input'); - this.close(); - } -} diff --git a/src/settings/suggesters/FolderSuggester.ts b/src/settings/suggesters/FolderSuggester.ts deleted file mode 100644 index c3ea705..0000000 --- a/src/settings/suggesters/FolderSuggester.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes - -import { TAbstractFile, TFolder } from 'obsidian'; -import { TextInputSuggest } from './suggest'; - -export class FolderSuggest extends TextInputSuggest { - getSuggestions(inputStr: string): TFolder[] { - const abstractFiles = this.app.vault.getAllLoadedFiles(); - const folders: TFolder[] = []; - const lowerCaseInputStr = inputStr.toLowerCase(); - - abstractFiles.forEach((folder: TAbstractFile) => { - if (folder instanceof TFolder && folder.path.toLowerCase().contains(lowerCaseInputStr)) { - folders.push(folder); - } - }); - - return folders; - } - - renderSuggestion(file: TFolder, el: HTMLElement): void { - el.setText(file.path); - } - - selectSuggestion(file: TFolder): void { - this.inputEl.value = file.path; - this.inputEl.trigger('input'); - this.close(); - } -} diff --git a/src/settings/suggesters/suggest.ts b/src/settings/suggesters/suggest.ts deleted file mode 100644 index f043e12..0000000 --- a/src/settings/suggesters/suggest.ts +++ /dev/null @@ -1,180 +0,0 @@ -// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes - -import { App, ISuggestOwner, Scope } from 'obsidian'; -import { createPopper, Instance as PopperInstance } from '@popperjs/core'; - -const wrapAround = (value: number, size: number): number => { - return ((value % size) + size) % size; -}; - -class Suggest { - private owner: ISuggestOwner; - private values: T[]; - private suggestions: HTMLDivElement[]; - private selectedItem: number; - private containerEl: HTMLElement; - - constructor(owner: ISuggestOwner, containerEl: HTMLElement, scope: Scope) { - this.owner = owner; - this.containerEl = containerEl; - - containerEl.on('click', '.suggestion-item', this.onSuggestionClick.bind(this)); - containerEl.on('mousemove', '.suggestion-item', this.onSuggestionMouseover.bind(this)); - - scope.register([], 'ArrowUp', event => { - if (!event.isComposing) { - this.setSelectedItem(this.selectedItem - 1, true); - return false; - } - }); - - scope.register([], 'ArrowDown', event => { - if (!event.isComposing) { - this.setSelectedItem(this.selectedItem + 1, true); - return false; - } - }); - - scope.register([], 'Enter', event => { - if (!event.isComposing) { - this.useSelectedItem(event); - return false; - } - }); - } - - onSuggestionClick(event: MouseEvent, el: HTMLDivElement): void { - event.preventDefault(); - - const item = this.suggestions.indexOf(el); - this.setSelectedItem(item, false); - this.useSelectedItem(event); - } - - onSuggestionMouseover(_event: MouseEvent, el: HTMLDivElement): void { - const item = this.suggestions.indexOf(el); - this.setSelectedItem(item, false); - } - - setSuggestions(values: T[]) { - this.containerEl.empty(); - const suggestionEls: HTMLDivElement[] = []; - - values.forEach(value => { - const suggestionEl = this.containerEl.createDiv('suggestion-item'); - this.owner.renderSuggestion(value, suggestionEl); - suggestionEls.push(suggestionEl); - }); - - this.values = values; - this.suggestions = suggestionEls; - this.setSelectedItem(0, false); - } - - useSelectedItem(event: MouseEvent | KeyboardEvent) { - const currentValue = this.values[this.selectedItem]; - if (currentValue) { - this.owner.selectSuggestion(currentValue, event); - } - } - - setSelectedItem(selectedIndex: number, scrollIntoView: boolean) { - const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length); - const prevSelectedSuggestion = this.suggestions[this.selectedItem]; - const selectedSuggestion = this.suggestions[normalizedIndex]; - - prevSelectedSuggestion?.removeClass('is-selected'); - selectedSuggestion?.addClass('is-selected'); - - this.selectedItem = normalizedIndex; - - if (scrollIntoView) { - selectedSuggestion.scrollIntoView(false); - } - } -} - -export abstract class TextInputSuggest implements ISuggestOwner { - private popper: PopperInstance; - private scope: Scope; - private suggestEl: HTMLElement; - private suggest: Suggest; - - constructor(protected app: App, protected inputEl: HTMLInputElement | HTMLTextAreaElement) { - this.scope = new Scope(); - - this.suggestEl = createDiv('suggestion-container'); - const suggestion = this.suggestEl.createDiv('suggestion'); - this.suggest = new Suggest(this, suggestion, this.scope); - - this.scope.register([], 'Escape', this.close.bind(this)); - - this.inputEl.addEventListener('input', this.onInputChanged.bind(this)); - this.inputEl.addEventListener('focus', this.onInputChanged.bind(this)); - this.inputEl.addEventListener('blur', this.close.bind(this)); - this.suggestEl.on('mousedown', '.suggestion-container', (event: MouseEvent) => { - event.preventDefault(); - }); - } - - onInputChanged(): void { - const inputStr = this.inputEl.value; - const suggestions = this.getSuggestions(inputStr); - - if (!suggestions) { - this.close(); - return; - } - - if (suggestions.length > 0) { - this.suggest.setSuggestions(suggestions); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this.open((this.app).dom.appContainerEl, this.inputEl); - } else { - this.close(); - } - } - - open(container: HTMLElement, inputEl: HTMLElement): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.app).keymap.pushScope(this.scope); - - container.appendChild(this.suggestEl); - this.popper = createPopper(inputEl, this.suggestEl, { - placement: 'bottom-start', - modifiers: [ - { - name: 'sameWidth', - enabled: true, - fn: ({ state, instance }) => { - // Note: positioning needs to be calculated twice - - // first pass - positioning it according to the width of the popper - // second pass - position it with the width bound to the reference element - // we need to early exit to avoid an infinite loop - const targetWidth = `${state.rects.reference.width}px`; - if (state.styles.popper.width === targetWidth) { - return; - } - state.styles.popper.width = targetWidth; - instance.update(); - }, - phase: 'beforeWrite', - requires: ['computeStyles'], - }, - ], - }); - } - - close(): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.app).keymap.popScope(this.scope); - - this.suggest.setSuggestions([]); - if (this.popper) this.popper.destroy(); - this.suggestEl.detach(); - } - - abstract getSuggestions(inputStr: string): T[]; - abstract renderSuggestion(item: T, el: HTMLElement): void; - abstract selectSuggestion(item: T): void; -}