Skip to content

Commit

Permalink
fix(plugin): preserve undo stack
Browse files Browse the repository at this point in the history
  • Loading branch information
magic-akari committed Apr 2, 2024
1 parent d580530 commit 9c7956a
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
10 changes: 8 additions & 2 deletions src/plugins/closing_pairs.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setRangeText } from "./common.js";
import type { EditorPlugin } from "./index.js";

export type ClosingPair = readonly [open: string, close: string];
Expand Down Expand Up @@ -73,9 +74,10 @@ export function hookClosingPairs(...pairs_rule_list: readonly ClosingPairsRules[
const text = input.value.slice(selectionStart, selectionEnd);
const left = e.key;
const right = config.auto_closing_pairs_open_by_start.get(left)!;
input.setRangeText(left + text + right, selectionStart, selectionEnd, "select");
setRangeText(input, left + text + right, selectionStart, selectionEnd, "select");
input.dispatchEvent(new Event("input"));
input.dispatchEvent(new Event("change"));
input.setSelectionRange(selectionStart + 1, selectionEnd + 1);
return;
}

Expand All @@ -85,9 +87,13 @@ export function hookClosingPairs(...pairs_rule_list: readonly ClosingPairsRules[
config.auto_closing_pairs_open_by_start.has(e.key) &&
should_auto_close.includes(input.value[selectionStart] || "")
) {
e.preventDefault();
const left = e.key;
const right = config.auto_closing_pairs_open_by_start.get(left)!;
input.setRangeText(right, selectionStart, selectionEnd, "start");
setRangeText(input, left + right, selectionStart, selectionEnd, "start");
input.dispatchEvent(new Event("input"));
input.dispatchEvent(new Event("change"));
input.setSelectionRange(selectionStart + 1, selectionEnd + 1);
return;
}

Expand Down
31 changes: 31 additions & 0 deletions src/plugins/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,34 @@ export function visibleWidthLeadingSpace(line: string, tabSize: number): [width:
}
return [width, i];
}

/**
* Instead of using the `setRangeText` method,
* prefer to use the `execCommand` method to preserve the undo stack.
*/
export function setRangeText(
input: HTMLTextAreaElement,
replacement: string,
start: number,
end: number,
selectionMode?: SelectionMode,
) {
input.setSelectionRange(start, end);
input.ownerDocument.execCommand("insertText", false, replacement);
switch (selectionMode) {
case "start": {
input.setSelectionRange(start, start);
break;
}
case "end": {
input.setSelectionRange(start + replacement.length, start + replacement.length);
break;
}

case "select":
default: {
input.setSelectionRange(start, start + replacement.length);
break;
}
}
}
6 changes: 3 additions & 3 deletions src/plugins/tab.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ceilTab, floorTab, visibleWidthFromLeft, visibleWidthLeadingSpace } from "./common.js";
import { ceilTab, floorTab, setRangeText, visibleWidthFromLeft, visibleWidthLeadingSpace } from "./common.js";
import type { IDisposeable, ShikiEditor } from "./index.js";

export interface IndentConfig {
Expand Down Expand Up @@ -407,7 +407,7 @@ export function hookTab({ input }: ShikiEditor, config: IndentConfig): IDisposea
const action = e.shiftKey ? outdentText : indentText;
const { patch, select } = action(e.target as HTMLTextAreaElement, config);
if (patch) {
input.setRangeText(patch.value, patch.start, patch.end, patch.mode);
setRangeText(input, patch.value, patch.start, patch.end, patch.mode);
input.dispatchEvent(new Event("input"));
input.dispatchEvent(new Event("change"));
}
Expand All @@ -424,7 +424,7 @@ export function hookTab({ input }: ShikiEditor, config: IndentConfig): IDisposea
e.preventDefault();
}
if (patch) {
input.setRangeText(patch.value, patch.start, patch.end, patch.mode);
setRangeText(input, patch.value, patch.start, patch.end, patch.mode);
input.dispatchEvent(new Event("input"));
input.dispatchEvent(new Event("change"));
}
Expand Down

0 comments on commit 9c7956a

Please sign in to comment.