Problem
When typing three backticks to close a fenced code block in the Markdown editor, a spurious 4th backtick is inserted. This only happens when no language is specified at the opening fence (e.g. ``` with no sql, js, etc. after it).
Issue #12569
Root Cause
The editor uses CodeMirror's closeBrackets extension for auto-pairing characters including backtick. This extension works correctly for a single backtick (inline code), but has no awareness of sequences. When the 3rd backtick is typed, closeBrackets sees it as a new opening bracket and inserts a closing one, producing 4 backticks instead of 3.
Fix
packages/editor/CodeMirror/editorCommands/handleBacktick.ts — new file,
import { EditorSelection, StateCommand } from '@codemirror/state';
const handleBacktick: StateCommand = ({ state, dispatch }) => {
const changes = state.changeByRange(range => {
if (!range.empty) return { range };
const pos = range.from;
const textBefore = state.doc.sliceString(Math.max(0, pos - 2), pos);
const charAfter = state.doc.sliceString(pos, pos + 1);
const backticksBefore = textBefore.length - textBefore.replace(/`+$/, '').length;
if (backticksBefore >= 2) {
return {
range: EditorSelection.cursor(pos + 1),
changes: { from: pos, to: pos, insert: '`' },
};
}
if (backticksBefore === 0) {
return {
range: EditorSelection.cursor(pos + 1),
changes: { from: pos, to: pos, insert: '``' },
};
}
if (backticksBefore === 1 && charAfter === '`') {
return {
range: EditorSelection.cursor(pos + 1),
};
}
return { range };
});
if (changes.changes.empty && changes.selection.eq(state.selection)) return false;
dispatch(state.update(changes, { scrollIntoView: true, userEvent: 'input' }));
return true;
};
export default handleBacktick;
All other characters continue to use closeBrackets unchanged. The deleteMarkupBackward backspace behavior is also unaffected. The fix is gated behind the existing "Auto-match braces" setting — disabling that setting disables this behavior too.
What is not changed
-
No changes to behavior for
(),[],"",''or any other auto-paired character -
Plugin behavior is unaffected
Files changed
-
packages/editor/CodeMirror/editorCommands/handleBacktick.ts— new file, the command -
packages/editor/CodeMirror/configFromSettings.ts— remove backtick fromopeningBrackets, import and register the new command