From efbd5773b5f49237588eac8ed36dad1af78644c3 Mon Sep 17 00:00:00 2001 From: olivier Date: Wed, 25 Feb 2026 11:35:15 -0500 Subject: [PATCH] feat: select next occurrence --- src/main.ts | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ src/settings.ts | 4 ++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 08cb4e3..e9ae182 100644 --- a/src/main.ts +++ b/src/main.ts @@ -560,6 +560,8 @@ export default class BindThemPlugin extends Plugin { this.addConditionalCommand({ id: 'go-to-next-word', name: 'Go to next word', icon: 'arrow-right', editorCallback: (e) => e.exec('goWordRight') }); this.addConditionalCommand({ id: 'insert-cursor-above', name: 'Insert cursor above', icon: 'plus-circle', editorCallback: (e) => this.insertCursor(e, -1) }); this.addConditionalCommand({ id: 'insert-cursor-below', name: 'Insert cursor below', icon: 'plus-circle', editorCallback: (e) => this.insertCursor(e, 1) }); + this.addConditionalCommand({ id: 'select-next-occurrence', name: 'Select next occurrence', icon: 'text-cursor', editorCallback: (e) => this.selectOccurrence(e, 'next') }); + this.addConditionalCommand({ id: 'select-prev-occurrence', name: 'Select previous occurrence', icon: 'text-cursor', editorCallback: (e) => this.selectOccurrence(e, 'prev') }); // File Operations this.addConditionalCommand({ id: 'duplicate-file', name: 'Duplicate file', icon: 'copy', editorCallback: (e, v) => { if (v instanceof MarkdownView) void this.duplicateFile(v); } }); @@ -641,6 +643,78 @@ export default class BindThemPlugin extends Plugin { editor.setSelections([...editor.listSelections(), ...newSels]); } + private selectOccurrence(editor: Editor, direction: 'next' | 'prev'): void { + const selections = editor.listSelections(); + if (selections.length === 0) return; + + // Get the selected text from the last selection (or first for prev) + const lastSelection = direction === 'next' ? selections[selections.length - 1] : selections[0]; + const range = selectionToRange(lastSelection); + const selectedText = editor.getRange(range.from, range.to); + + // If no text is selected, select the word under cursor first + if (!selectedText) { + this.selectWord(editor); + return; + } + + // Get the entire document content + const fullText = editor.getValue(); + + // Find all occurrences of the selected text + const occurrences: { from: number; to: number }[] = []; + let searchPos = 0; + while (true) { + const idx = fullText.indexOf(selectedText, searchPos); + if (idx === -1) break; + occurrences.push({ from: idx, to: idx + selectedText.length }); + searchPos = idx + 1; + } + + if (occurrences.length <= 1) return; // No other occurrences + + // Convert current selection to offset + const currentOffset = editor.posToOffset(range.from); + + // Find the next/previous occurrence + let targetOccurrence: { from: number; to: number } | null = null; + + if (direction === 'next') { + // Find first occurrence after current position + for (const occ of occurrences) { + if (occ.from > currentOffset) { + targetOccurrence = occ; + break; + } + } + // Wrap around to first occurrence if not found + if (!targetOccurrence) { + targetOccurrence = occurrences[0]; + } + } else { + // Find first occurrence before current position + for (let i = occurrences.length - 1; i >= 0; i--) { + if (occurrences[i].from < currentOffset) { + targetOccurrence = occurrences[i]; + break; + } + } + // Wrap around to last occurrence if not found + if (!targetOccurrence) { + targetOccurrence = occurrences[occurrences.length - 1]; + } + } + + if (targetOccurrence) { + const from = editor.offsetToPos(targetOccurrence.from); + const to = editor.offsetToPos(targetOccurrence.to); + + // Add new selection to existing selections + const newSelections = [...selections, { anchor: from, head: to }]; + editor.setSelections(newSelections); + } + } + private goToHeading(editor: Editor, direction: 'next' | 'prev'): void { const file = this.app.workspace.getActiveFile(); const cache = file ? this.app.metadataCache.getFileCache(file) : null; diff --git a/src/settings.ts b/src/settings.ts index 2a8b063..504c5d9 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -104,7 +104,9 @@ export const COMMANDS: Record