Skip to content

Commit dbe9c61

Browse files
authored
fix: task auto completion should not add waste ] (#105)
1 parent 8a21e4a commit dbe9c61

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

src/features/editor/codemirror/tasklist/auto-complete.browser.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ describe("taskAutoComplete", () => {
8282
expect(result.cursorPosition).toBe(6);
8383
});
8484

85+
test("auto-complete removes existing closing bracket for '-[]' pattern", () => {
86+
const result = testAutoComplete("-[]", 2, " ");
87+
88+
expect(result.before).toBe("-[]");
89+
expect(result.after).toBe("- [ ] ");
90+
expect(result.cursorPosition).toBe(6);
91+
});
92+
8593
test("auto-complete with indented '- [ ' pattern", () => {
8694
const result = testAutoComplete(" - [", 5, " ");
8795

src/features/editor/codemirror/tasklist/auto-complete.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,37 @@ import type { Extension } from "@codemirror/state";
22
import { EditorView } from "@codemirror/view";
33

44
export const taskAutoComplete: Extension = EditorView.inputHandler.of((view, from, to, text) => {
5-
const isValidInput = text === " " && from === to && from >= 2;
6-
if (!isValidInput) return false;
5+
const isWhitespaceInput = from === to && text.length > 0 && /^[ \t]+$/.test(text);
6+
if (!isWhitespaceInput) return false;
77

88
const doc = view.state.doc;
99
const line = doc.lineAt(from);
10-
const linePrefix = doc.sliceString(line.from, from);
10+
const before = doc.sliceString(line.from, from);
11+
const after = doc.sliceString(from, line.to);
1112

12-
const patterns = [
13-
{ suffix: "- [", offset: 3 },
14-
{ suffix: "-[", offset: 2 },
15-
];
13+
const bulletMatch = before.match(/[-*]\s*\[$/);
14+
if (!bulletMatch) return false;
1615

17-
const matchedPattern = patterns.find(({ suffix }) => linePrefix.endsWith(suffix));
18-
if (!matchedPattern) return false;
16+
const bulletStart = before.length - bulletMatch[0].length;
17+
const indent = before.slice(0, bulletStart);
18+
if (!/^[ \t]*$/.test(indent)) return false;
1919

20-
const insertFrom = from - matchedPattern.offset;
21-
if (insertFrom < line.from) return false;
20+
// Avoid re-triggering on existing task list items like "- [ ]" or "- [x]"
21+
if (/^[ \t]*(?:[xX]\]| \])/.test(after)) return false;
2222

23-
const replacement = "- [ ] ";
23+
const insertFrom = line.from;
24+
const bullet = bulletMatch[0][0];
25+
const replacement = `${indent}${bullet} [ ] `;
26+
// don't remove waste `]`
27+
const replaceTo = after.startsWith("]") && from + 1 <= line.to ? from + 1 : from;
2428

2529
view.dispatch({
2630
changes: {
2731
from: insertFrom,
28-
to: from,
32+
to: replaceTo,
2933
insert: replacement,
3034
},
35+
userEvent: "input.taskAutoComplete",
3136
selection: { anchor: insertFrom + replacement.length },
3237
});
3338

0 commit comments

Comments
 (0)