diff --git a/src/renderer/editor/codemirror/commands.ts b/src/renderer/editor/codemirror/commands.ts index cc37066..52105b7 100644 --- a/src/renderer/editor/codemirror/commands.ts +++ b/src/renderer/editor/codemirror/commands.ts @@ -483,6 +483,7 @@ export const toggleBlockquoteCommand = ( export const toggleFencedCodeBlockCommand = ( view: import("@codemirror/view").EditorView ): boolean => { + const { from, to } = view.state.selection.main; const { start, end } = getSelectedLineNumbers(view); const doc = view.state.doc; const firstLine = doc.line(start); @@ -504,6 +505,18 @@ export const toggleFencedCodeBlockCommand = ( return true; } + if (from === to && firstLine.text.trim() === "") { + const indent = firstLine.text.match(/^\s*/)?.[0] ?? ""; + const snippet = `${indent}\`\`\`\n${indent}\n${indent}\`\`\``; + const cursor = firstLine.from + indent.length + 4 + indent.length; + view.dispatch({ + changes: { from: firstLine.from, to: firstLine.to, insert: snippet }, + selection: { anchor: cursor }, + scrollIntoView: true, + }); + return true; + } + const before = firstLine.from; const after = lastLine.to; diff --git a/tests/controllerShortcuts.test.ts b/tests/controllerShortcuts.test.ts index 46ff10c..a9ab012 100644 --- a/tests/controllerShortcuts.test.ts +++ b/tests/controllerShortcuts.test.ts @@ -196,6 +196,24 @@ runTest("code block command wraps and unwraps selected lines", () => { assert.equal(view.text, "const x = 1;"); }); +runTest("code block command inserts editable empty fenced block", () => { + const view = new FakeView("", { from: 0, to: 0 }); + + toggleFencedCodeBlockCommand(view as unknown as EditorView); + + assert.equal(view.text, "```\n\n```"); + assert.deepEqual(view.state.selection.main, { from: 4, to: 4 }); +}); + +runTest("code block command preserves indentation for empty fenced blocks", () => { + const view = new FakeView(" ", { from: 2, to: 2 }); + + toggleFencedCodeBlockCommand(view as unknown as EditorView); + + assert.equal(view.text, " ```\n \n ```"); + assert.deepEqual(view.state.selection.main, { from: 8, to: 8 }); +}); + if (process.exitCode && process.exitCode !== 0) { throw new Error("One or more tests failed."); }