Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/cm/baseExtensions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
acceptCompletion,
closeBrackets,
closeBracketsKeymap,
completionKeymap,
} from "@codemirror/autocomplete";
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
Expand Down Expand Up @@ -75,7 +76,12 @@ export default function createBaseExtensions(
Prec.highest(keymap.of([{ key: "Tab", run: acceptCompletion }])),
);
extensions.push(
keymap.of([...completionKeymap, ...defaultKeymap, ...historyKeymap]),
keymap.of([
...(autoCloseBrackets ? closeBracketsKeymap : []),
...completionKeymap,
...defaultKeymap,
...historyKeymap,
]),
);
extensions.push(
// This prevents tooltips from being going out of the editor area
Expand Down
67 changes: 62 additions & 5 deletions src/test/editor.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "@codemirror/language";
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
import { EditorSelection, EditorState } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { EditorView, runScopeHandlers } from "@codemirror/view";
import createBaseExtensions from "cm/baseExtensions";
import indentGuides from "cm/indentGuides";
import {
Expand All @@ -33,7 +33,7 @@ import { TestRunner } from "./tester";
export async function runCodeMirrorTests(writeOutput) {
const runner = new TestRunner("CodeMirror 6 Editor Tests");

function createEditor(doc = "", extensions = []) {
function createEditor(doc = "", extensions = [], baseExtensionOptions = {}) {
const container = document.createElement("div");
container.style.width = "500px";
container.style.height = "300px";
Expand All @@ -42,18 +42,31 @@ export async function runCodeMirrorTests(writeOutput) {

const state = EditorState.create({
doc,
extensions: [...createBaseExtensions(), ...extensions],
extensions: [
...createBaseExtensions(baseExtensionOptions),
...extensions,
],
});

const view = new EditorView({ state, parent: container });
return { view, container };
}

async function withEditor(test, fn, initialDoc = "", extensions = []) {
async function withEditor(
test,
fn,
initialDoc = "",
extensions = [],
baseExtensionOptions = {},
) {
let view, container;

try {
({ view, container } = createEditor(initialDoc, extensions));
({ view, container } = createEditor(
initialDoc,
extensions,
baseExtensionOptions,
));
test.assert(view != null, "EditorView instance should be created");
await new Promise((resolve) => setTimeout(resolve, 100));
await fn(view);
Expand Down Expand Up @@ -139,6 +152,50 @@ export async function runCodeMirrorTests(writeOutput) {
container.remove();
});

runner.test("Backspace deletes an auto-closed bracket pair", async (test) => {
await withEditor(
test,
async (view) => {
view.dispatch({ selection: { anchor: 1 } });
const handled = runScopeHandlers(
view,
new KeyboardEvent("keydown", { key: "Backspace" }),
"editor",
);

test.assert(
handled,
"Backspace should be handled between a bracket pair",
);
test.assertEqual(view.state.doc.toString(), "");
},
"()",
);
});

runner.test(
"Backspace behaves normally when auto-close is disabled",
async (test) => {
await withEditor(
test,
async (view) => {
view.dispatch({ selection: { anchor: 1 } });
const handled = runScopeHandlers(
view,
new KeyboardEvent("keydown", { key: "Backspace" }),
"editor",
);

test.assert(handled, "Backspace should retain its default behavior");
test.assertEqual(view.state.doc.toString(), ")");
},
"()",
[],
{ autoCloseBrackets: false },
);
},
);

runner.test("State access", async (test) => {
await withEditor(test, async (view) => {
const state = view.state;
Expand Down