From 47f3b7557e404d592def285a597b509c82d9f4fb Mon Sep 17 00:00:00 2001 From: Amit Haridas Date: Wed, 4 Mar 2026 15:31:42 +0530 Subject: [PATCH] feat: add CodeMirror 6 wrapper module --- src/editor/codemirror-setup.js | 121 +++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/editor/codemirror-setup.js diff --git a/src/editor/codemirror-setup.js b/src/editor/codemirror-setup.js new file mode 100644 index 0000000..8c7cfab --- /dev/null +++ b/src/editor/codemirror-setup.js @@ -0,0 +1,121 @@ +// CodeMirror 6 wrapper module +// Provides createEditor() and getLanguageExtension() for the rest of the app. + +const { + EditorView, + keymap, + lineNumbers, + highlightActiveLine, + drawSelection, +} = require('@codemirror/view'); +const { EditorState } = require('@codemirror/state'); +const { markdown, markdownLanguage } = require('@codemirror/lang-markdown'); +const { javascript } = require('@codemirror/lang-javascript'); +const { html } = require('@codemirror/lang-html'); +const { css } = require('@codemirror/lang-css'); +const { json } = require('@codemirror/lang-json'); +const { python } = require('@codemirror/lang-python'); +const { + defaultKeymap, + history, + historyKeymap, + indentWithTab, +} = require('@codemirror/commands'); +const { + searchKeymap, + highlightSelectionMatches, +} = require('@codemirror/search'); +const { + autocompletion, + completionKeymap, +} = require('@codemirror/autocomplete'); +const { + bracketMatching, + foldGutter, + indentOnInput, +} = require('@codemirror/language'); +const { oneDark } = require('@codemirror/theme-one-dark'); + +/** + * Create a CodeMirror 6 editor instance. + * + * @param {HTMLElement} parentElement - DOM element to mount the editor in + * @param {Object} options + * @param {string} options.content - initial document content (default '') + * @param {Function} options.onChange - called with new content string on every doc change + * @param {boolean} options.isDark - apply oneDark theme when true (default false) + * @param {boolean} options.showLineNumbers - show line-number gutter (default true) + * @returns {EditorView} the created editor view + */ +function createEditor(parentElement, options = {}) { + const { + content = '', + onChange = () => {}, + isDark = false, + showLineNumbers = true, + } = options; + + const extensions = [ + markdown({ base: markdownLanguage }), + history(), + drawSelection(), + highlightActiveLine(), + bracketMatching(), + indentOnInput(), + highlightSelectionMatches(), + autocompletion(), + foldGutter(), + keymap.of([ + ...defaultKeymap, + ...historyKeymap, + ...searchKeymap, + ...completionKeymap, + indentWithTab, + ]), + EditorView.updateListener.of((update) => { + if (update.docChanged) { + onChange(update.state.doc.toString()); + } + }), + EditorView.lineWrapping, + ]; + + if (showLineNumbers) { + extensions.push(lineNumbers()); + } + + if (isDark) { + extensions.push(oneDark); + } + + const state = EditorState.create({ doc: content, extensions }); + const view = new EditorView({ state, parent: parentElement }); + return view; +} + +/** + * Return the appropriate CodeMirror language extension for a given language name. + * + * Supported values: javascript, js, html, css, json, python, py, markdown. + * Falls back to markdown when the language is unrecognised. + * + * @param {string} lang - language identifier + * @returns {Extension} CodeMirror language extension + */ +function getLanguageExtension(lang) { + const languages = { + javascript, + js: javascript, + html, + css, + json, + python, + py: python, + markdown: () => markdown({ base: markdownLanguage }), + }; + + const factory = languages[lang]; + return factory ? factory() : markdown({ base: markdownLanguage }); +} + +module.exports = { createEditor, getLanguageExtension };