From 287e74ce42a334aada927168d2b2627e553390c1 Mon Sep 17 00:00:00 2001 From: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:16:24 +0530 Subject: [PATCH 1/2] feat(plugins): expose static CodeMirror highlighter --- .babelrc | 2 +- src/lib/acode.js | 22 ++++ src/lib/editorFile.js | 6 ++ src/test/editor.tests.js | 66 ++++++++++++ src/utils/codeHighlight.js | 180 ++++++++++++++++++++++++++++--- tests/unit/codeHighlight.test.js | 154 ++++++++++++++++++++++++++ 6 files changed, 413 insertions(+), 17 deletions(-) create mode 100644 tests/unit/codeHighlight.test.js diff --git a/.babelrc b/.babelrc index d50502316..e5efe292f 100644 --- a/.babelrc +++ b/.babelrc @@ -15,6 +15,6 @@ "@babel/plugin-transform-runtime", "@babel/plugin-transform-block-scoping" ], - "compact": true, + "compact": false, "sourceMaps": "inline" } diff --git a/src/lib/acode.js b/src/lib/acode.js index 15cc4b6f9..6d9310d24 100644 --- a/src/lib/acode.js +++ b/src/lib/acode.js @@ -69,6 +69,15 @@ import appSettings from "lib/settings"; import FileBrowser from "pages/fileBrowser"; import ThemeBuilder from "theme/builder"; import themes from "theme/list"; +import { + applyHighlightStyles, + clearHighlightCache, + getHighlightStyleSheet, + getHighlightStyles, + HIGHLIGHT_CLASS, + highlightCodeBlock, + highlightLine, +} from "utils/codeHighlight"; import Color from "utils/color"; import encodings, { decode, encode } from "utils/encodings"; import helpers from "utils/helpers"; @@ -312,6 +321,17 @@ class Acode { }, }; + const codeHighlightModule = Object.freeze({ + highlightLine, + highlightCodeBlock, + highlight: highlightCodeBlock, + clearCache: clearHighlightCache, + applyStyles: applyHighlightStyles, + getStyles: getHighlightStyles, + getStyleSheet: getHighlightStyleSheet, + HIGHLIGHT_CLASS, + }); + const codemirrorModule = Object.freeze({ autocomplete: cmAutocomplete, commands: cmCommands, @@ -326,6 +346,7 @@ class Acode { search: cmSearch, state: cmState, view: cmView, + highlight: codeHighlightModule, }); const configProxy = new Proxy(config, { @@ -414,6 +435,7 @@ class Acode { this.define("terminal", terminalModule); this.define("webview", webview); this.define("codemirror", codemirrorModule); + this.define("codeHighlight", codeHighlightModule); this.define("@codemirror/autocomplete", cmAutocomplete); this.define("@codemirror/commands", cmCommands); this.define("@codemirror/language", cmLanguage); diff --git a/src/lib/editorFile.js b/src/lib/editorFile.js index 449d8ea4b..2aee9b500 100644 --- a/src/lib/editorFile.js +++ b/src/lib/editorFile.js @@ -23,6 +23,7 @@ import startDrag from "handlers/editorFileTab"; import actions from "handlers/quickTools"; import tag from "html-tag-js"; import mimeTypes from "mime-types"; +import { applyHighlightStyles } from "utils/codeHighlight"; import helpers from "utils/helpers"; import Path from "utils/Path"; import { readRemoteFilePreview } from "utils/remoteFilePreview"; @@ -329,6 +330,7 @@ function maybeRecommendLanguageModeExtension(file, modeInfo) { * @property {string} [paneId] target editor pane id * @property {object} [pane] target editor pane * @property {boolean} [isPanePlaceholder] temporary empty tab for an empty pane + * @property {boolean} [highlightStyles] adopt static CodeMirror highlight CSS into the custom tab shadow root */ export default class EditorFile { @@ -590,6 +592,10 @@ export default class EditorFile { this.#addCustomStyles(options.stylesheets, shadow); } + if (options.highlightStyles) { + applyHighlightStyles(shadow); + } + const content =
; if (typeof options.content === "string") { diff --git a/src/test/editor.tests.js b/src/test/editor.tests.js index 4003dfc8c..4af037e88 100644 --- a/src/test/editor.tests.js +++ b/src/test/editor.tests.js @@ -213,6 +213,72 @@ export async function runCodeMirrorTests(writeOutput) { ); }); + runner.test( + "Acode exposes the static CodeMirror highlighter", + async (test) => { + const codeHighlight = acode.require("codeHighlight"); + const codemirror = acode.require("codemirror"); + + test.assert(codeHighlight != null, "codeHighlight module should exist"); + test.assertEqual( + typeof codeHighlight.highlightCodeBlock, + "function", + "highlightCodeBlock should be a function", + ); + test.assertEqual( + typeof codeHighlight.highlightLine, + "function", + "highlightLine should be a function", + ); + test.assertEqual( + typeof codeHighlight.applyStyles, + "function", + "applyStyles should be a function", + ); + test.assertEqual( + typeof codeHighlight.getStyles, + "function", + "getStyles should be a function", + ); + test.assertEqual( + codeHighlight.HIGHLIGHT_CLASS, + "cm-highlighted", + "HIGHLIGHT_CLASS should match the internal token wrapper", + ); + test.assertEqual( + codemirror.highlight, + codeHighlight, + "codemirror.highlight should be the same highlighter module", + ); + + const css = codeHighlight.getStyles(); + test.assert( + typeof css === "string" && css.includes(".tok-keyword"), + "getStyles should return token CSS", + ); + + const highlighted = await codeHighlight.highlightCodeBlock( + 'const value = "acode";', + "javascript", + ); + test.assert( + highlighted.includes("value") && !highlighted.includes("