From 6c9632ffb0e70ff55bad01e2450c6b9adf77a816 Mon Sep 17 00:00:00 2001 From: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:30:06 +0530 Subject: [PATCH] chore(modes): drop legacy modes provided by the Additional Language Modes plugin Stop registering the legacy stream-mode Clojure, ClojureScript, edn, Gas, Kotlin, LaTeX, sTeX, Lua and Swift modes, and stop HTML claiming .hbs and .handlebars, so the acode.additional.langmodes plugin's Lezer modes take their canonical names and file extensions. --- src/cm/supportedModes.ts | 26 ++++++- tests/unit/pluginProvidedModes.test.js | 104 +++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 tests/unit/pluginProvidedModes.test.js diff --git a/src/cm/supportedModes.ts b/src/cm/supportedModes.ts index 12febc9f9..f16746a74 100644 --- a/src/cm/supportedModes.ts +++ b/src/cm/supportedModes.ts @@ -152,6 +152,27 @@ addMode( () => [], ); +// Languages that @codemirror/language-data only covers with legacy stream +// tokenizers and that the official Additional Language Modes plugin +// (acode.additional.langmodes) provides as Lezer grammars. They are left out +// so the plugin registers them under their canonical names; without it, these +// files fall back to plain text and Acode recommends the plugin. +const PLUGIN_PROVIDED_LANGUAGES = new Set([ + "clojure", + "clojurescript", + "edn", + "gas", + "kotlin", + "latex", + "stex", + "lua", + "swift", +]); + +// Extensions other modes claim in @codemirror/language-data but that the +// plugin has dedicated modes for: HTML lists Handlebars templates. +const PLUGIN_PROVIDED_EXTENSIONS = new Set(["hbs", "handlebars"]); + // 2) Register all languages provided by @codemirror/language-data // We convert extensions like [".js", ".mjs"] into a modelist pattern: "js|mjs" // and preserve aliases and filename regexes for languages like C++ and Dockerfile. @@ -159,6 +180,7 @@ for (const lang of languages as readonly LanguageDescription[]) { try { const name = String(lang?.name || "").trim(); if (!name) continue; + if (PLUGIN_PROVIDED_LANGUAGES.has(normalizeModeKey(name))) continue; const aliases = collectAliases(name, lang.alias); const modeId = getModeId(name, aliases); @@ -248,7 +270,9 @@ for (const lang of languages as readonly LanguageDescription[]) { for (const e of langExtensions) { if (typeof e !== "string") continue; const cleaned = e.replace(/^\./, "").trim(); - if (cleaned) parts.push(cleaned); + if (cleaned && !PLUGIN_PROVIDED_EXTENSIONS.has(cleaned.toLowerCase())) { + parts.push(cleaned); + } } const filenameMatchers: RegExp[] = []; diff --git a/tests/unit/pluginProvidedModes.test.js b/tests/unit/pluginProvidedModes.test.js new file mode 100644 index 000000000..959bf4897 --- /dev/null +++ b/tests/unit/pluginProvidedModes.test.js @@ -0,0 +1,104 @@ +import { afterEach, describe, expect, it } from "vitest"; +import "cm/supportedModes"; +import { addMode, getMode, getModeForPath, removeMode } from "cm/modelist"; + +// Modes the Additional Language Modes plugin (acode.additional.langmodes) +// replaces with Lezer grammars, with the extensions it registers. +const pluginModes = [ + { name: "assembly", extensions: ["asm", "s", "S", "nasm"] }, + { name: "c", extensions: ["c", "h", "ino"] }, + { name: "clojure", extensions: ["clj", "cljs", "cljc", "cljx", "edn"] }, + { name: "kotlin", extensions: ["kt", "kts"] }, + { name: "latex", extensions: ["tex", "ltx", "sty", "cls", "latex"] }, + { name: "lua", extensions: ["lua"] }, + { name: "swift", extensions: ["swift"] }, + { name: "handlebars", extensions: ["hbs", "handlebars"] }, + { name: "mustache", extensions: ["mustache"] }, +]; + +/** The plugin's registration rule: keep Acode's mode, add "-enhanced". */ +function registerLikePlugin({ name, extensions }) { + const registered = getMode(name) ? `${name}-enhanced` : name; + addMode(registered, extensions, registered, () => []); + return registered; +} + +describe("legacy modes replaced by the Additional Language Modes plugin", () => { + const registered = []; + + afterEach(() => { + for (const name of registered.splice(0)) removeMode(name); + }); + + it.each([ + "clojure", + "clojurescript", + "edn", + "gas", + "kotlin", + "latex", + "tex", + "stex", + "lua", + "swift", + ])("does not ship a built-in %s mode", (name) => { + expect(getMode(name)).toBeNull(); + }); + + it.each([ + "a.kt", + "a.kts", + "a.lua", + "a.swift", + "a.clj", + "a.cljs", + "a.edn", + "a.s", + "a.tex", + "a.hbs", + "a.handlebars", + ])("falls back to plain text for %s without the plugin", (path) => { + expect(getModeForPath(path).name).toBe("text"); + }); + + it("keeps C, C++, HTML and Luau built in", () => { + expect(getModeForPath("a.html").name).toBe("html"); + expect(getModeForPath("a.c").name).toBe("c"); + expect(getModeForPath("a.cpp").name).toBe("cpp"); + expect(getModeForPath("a.luau").name).toBe("luau"); + }); + + it("opens .text files as plain text instead of LaTeX", () => { + expect(getModeForPath("notes.text").name).toBe("text"); + }); + + it("lets the plugin register the replaced modes under canonical names", () => { + for (const mode of pluginModes) registered.push(registerLikePlugin(mode)); + + expect(registered).toEqual([ + "assembly", + "c-enhanced", + "clojure", + "kotlin", + "latex", + "lua", + "swift", + "handlebars", + "mustache", + ]); + expect(getModeForPath("a.kt").name).toBe("kotlin"); + expect(getModeForPath("a.lua").name).toBe("lua"); + expect(getModeForPath("a.swift").name).toBe("swift"); + expect(getModeForPath("a.cljs").name).toBe("clojure"); + expect(getModeForPath("a.edn").name).toBe("clojure"); + expect(getModeForPath("a.s").name).toBe("assembly"); + expect(getModeForPath("a.tex").name).toBe("latex"); + expect(getModeForPath("a.c").name).toBe("c-enhanced"); + expect(getModeForPath("a.hbs").name).toBe("handlebars"); + expect(getModeForPath("a.handlebars").name).toBe("handlebars"); + expect(getModeForPath("a.mustache").name).toBe("mustache"); + expect(getModeForPath("a.html").name).toBe("html"); + // Luau keeps its own mode even though "lua" now comes from the plugin. + expect(getModeForPath("a.luau").name).toBe("luau"); + }); +});