feat: select next occurrence
This commit is contained in:
74
src/main.ts
74
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;
|
||||
|
||||
@@ -104,7 +104,9 @@ export const COMMANDS: Record<keyof typeof COMMAND_CATEGORIES, CommandDefinition
|
||||
{ id: 'go-to-prev-word', name: 'Go to previous word' },
|
||||
{ id: 'go-to-next-word', name: 'Go to next word' },
|
||||
{ id: 'insert-cursor-above', name: 'Insert cursor above' },
|
||||
{ id: 'insert-cursor-below', name: 'Insert cursor below' }
|
||||
{ id: 'insert-cursor-below', name: 'Insert cursor below' },
|
||||
{ id: 'select-next-occurrence', name: 'Select next occurrence' },
|
||||
{ id: 'select-prev-occurrence', name: 'Select previous occurrence' }
|
||||
],
|
||||
fileOperations: [
|
||||
{ id: 'duplicate-file', name: 'Duplicate file' },
|
||||
|
||||
Reference in New Issue
Block a user