pull/662/head
Zef Hemel 2024-01-26 11:10:35 +01:00
parent 63083d1e05
commit 43adb13fb2
6 changed files with 81 additions and 3 deletions

View File

@ -15,6 +15,14 @@ export function getText(): Promise<string> {
return syscall("editor.getText");
}
/**
* This updates the editor text, but in a minimal-diff way:
* it compares the current editor text with the new text, and only sends the changes to the editor, thereby preserving cursor location
*/
export function setText(newText: string) {
return syscall("editor.setText", newText);
}
export function getCursor(): Promise<number> {
return syscall("editor.getCursor");
}

View File

@ -5,6 +5,7 @@ import { editor, markdown, space, sync } from "$sb/syscalls.ts";
import {
addParentPointers,
collectNodesMatching,
findNodeMatching,
findNodeOfType,
findParentMatching,
nodeAtPos,
@ -337,3 +338,34 @@ export async function postponeCommand() {
},
});
}
export async function removeCompletedTasksCommand() {
const tree = await markdown.parseMarkdown(await editor.getText());
addParentPointers(tree);
// Taking this ugly approach because the tree is modified in place
// Just finding and removing one task at a time and then repeating until nothing changes
while (true) {
const completedTaskNode = findNodeMatching(tree, (node) => {
return node.type === "Task" &&
["x", "X"].includes(node.children![0].children![1].text!);
});
if (completedTaskNode) {
// Ok got one, let's remove it
const listItemNode = completedTaskNode.parent!;
const bulletListNode = listItemNode.parent!;
// Remove the list item
const listItemIdx = bulletListNode.children!.indexOf(listItemNode);
let removeItems = 1;
if (bulletListNode.children![listItemIdx + 1]?.text === "\n") {
removeItems++;
}
bulletListNode.children!.splice(listItemIdx, removeItems);
} else {
// No completed tasks left, we're done
break;
}
}
await editor.setText(renderToText(tree));
}

View File

@ -32,4 +32,9 @@ functions:
taskComplete:
path: ./complete.ts:completeTaskState
events:
- editor:complete
- editor:complete
removeCompletedTasksCommand:
path: task.ts:removeCompletedTasksCommand
command:
name: "Task: Remove Completed"

View File

@ -19,9 +19,11 @@ class CheckboxWidget extends WidgetType {
checkbox.type = "checkbox";
checkbox.checked = this.checked;
checkbox.addEventListener("click", (e) => {
// Let the click handler handle this
e.stopPropagation();
e.preventDefault();
});
checkbox.addEventListener("mouseup", (e) => {
e.stopPropagation();
this.clickCallback(this.pos);
});
wrap.appendChild(checkbox);

23
web/syscalls/cm_util.ts Normal file
View File

@ -0,0 +1,23 @@
import diff, { DELETE, INSERT } from "https://esm.sh/fast-diff@1.3.0";
import type { ChangeSpec } from "@codemirror/state";
export function diffAndPrepareChanges(
oldString: string,
newString: string,
): ChangeSpec[] {
// Use the fast-diff library to compute the changes
const diffs = diff(oldString, newString);
// Convert the diffs to CodeMirror transactions
let startIndex = 0;
const changes: ChangeSpec[] = [];
for (const part of diffs) {
if (part[0] === INSERT) {
changes.push({ from: startIndex, insert: part[1] });
} else if (part[0] === DELETE) {
changes.push({ from: startIndex, to: startIndex + part[1].length });
}
startIndex += part[1].length;
}
return changes;
}

View File

@ -15,6 +15,7 @@ import type { FilterOption } from "../types.ts";
import { UploadFile } from "../../plug-api/types.ts";
import { PageRef } from "$sb/lib/page.ts";
import { openSearchPanel } from "../deps.ts";
import { diffAndPrepareChanges } from "./cm_util.ts";
export function editorSyscalls(client: Client): SysCallMapping {
const syscalls: SysCallMapping = {
@ -24,6 +25,13 @@ export function editorSyscalls(client: Client): SysCallMapping {
"editor.getText": () => {
return client.editorView.state.sliceDoc();
},
"editor.setText": (_ctx, newText: string) => {
const currentText = client.editorView.state.sliceDoc();
const allChanges = diffAndPrepareChanges(currentText, newText);
client.editorView.dispatch({
changes: allChanges,
});
},
"editor.getCursor": (): number => {
return client.editorView.state.selection.main.from;
},