- 开发工具
- 桌面应用
【免费下载链接】massCode
A free, open-source developer workspace. Snippets, notes, HTTP requests, calculations, and dev tools in one local-first app.
massCode 是一款本地优先的开源开发者工作台,其内置代码编辑器基于 CodeMirror + TextMate 语法体系构建,官方在 src/renderer/components/editor/README.md 中维护了一份完整的“支持语言清单”,共列出 162 种语言。本文以这份清单为骨架,结合仓库源码逐层剖析:每种语言在languages.ts中如何声明(显示名、mode 标识、TextMate scope、语法文件四要素)、loadGrammars()如何在启动时通过 onigasm WASM 将语法注册进编辑器、语言选择在界面中如何切换与持久化,以及如何基于现有结构为 massCode 扩展新的语言。读完本文,你既能完整掌握这 162 种语言与内部标识的对照关系,也能理解整套语法加载链路的底层原理。
一、语言清单是什么:一份 162 种语法的官方索引
src/renderer/components/editor/README.md是编辑器子模块的说明文档,其正文只有一段引言——“This is a list of language that supports in massCode”,随后按字母顺序列出全部支持的语言名称。从 ABAP 到 Zeek,共计162 个条目,覆盖了:
- 主流通用语言:C/C++、C#、Java、JavaScript/TypeScript、Go、Rust、Python、Ruby、PHP、Swift、Kotlin、Dart、Scala 等;
- Web 前端与样式:HTML、CSS、JSX/TSX、Vue、SCSS/SASS/LESS/Stylus 等;
- 数据与配置格式:JSON/JSON5、YAML、TOML、INI、Properties、Protobuf、Hjson、Nix、Prisma、Gitignore 等;
- 数据库与查询:SQL、SQLServer、MySQL、pgSQL、GraphQL、Kusto (KQL)、XQuery 等;
- 模板引擎:EJS、HAML、Handlebars、Pug、Slim、Twig、Liquid、Nunjucks、Soy Template、PHP (Blade Template) 等;
- 文档与标记:Markdown、AsciiDoc、LaTeX、Tex、Textile、MediaWiki、RST、Diff、Dot 等;
- 运维与云:Bash、Powershell、BatchFile、Dockerfile、Makefile、Nginx、Apache Conf、Terraform、Puppet、NSIS、Mikrotik 等;
- 科学计算与领域语言:MATLAB、SAS、R、Julia、Glsl、OpenGL、Gcode、SCAD、MEL、Praat、Csound 系列、LSL、Apex、Drools、Gherkin、Pig、Zeek 等。
这份清单不是一份“宣传名录”,而是与编辑器实现一一对应的可执行配置索引——清单中的每个名字都能在 languages.ts 的languages数组中找到对应的LanguageOption条目,并绑定一个实际的 TextMate 语法文件(见下文第三、四节)。
二、完整语言清单与内部标识对照表
清单中的“语言显示名”只是给人看的;编辑器内部真正使用的是三类标识,其定义见 LanguageOption 接口:
| 字段 | 含义 | 示例 |
|---|---|---|
name | 下拉框与文档中展示的语言显示名 | Bash |
value | 该语言的内部标识,作为 CodeMirror 的mode值存储进 snippet 数据 | sh |
scopeName | 该语言对应的 TextMate 语法作用域(scope),是语法匹配的根锚点 | source.shell |
grammar | 懒加载的*.tmLanguage.json语法文件加载函数 | () => import('./grammars/shell-unix-bash.tmLanguage.json') |
其中value的取值范围由 Language 联合类型 约束(如'abap'、'sh'、'c_cpp'),保证类型安全。下面按字母区间给出全部 162 种语言的name → value → scopeName完整对照,数据以 languages.ts 为准。
A–E
| 语言(name) | value | scopeName |
|---|---|---|
| ABAP | abap | source.abap |
| ABC | abc | text.abcnotation |
| ActionScript | actionscript | source.actionscript.3 |
| ADA | ada | source.ada |
| Alda | alda | source.alda |
| Apache Conf | apache_conf | source.apacheconf |
| Apex | apex | source.apex |
| Apple Script | applescript | source.applescript |
| AsciiDoc | asciidoc | text.asciidoc |
| ASL | asl | source.asl |
| ASP vb.NET (VBScript) | asp_vb_net | source.asp.vb.net |
| Assembly x86 | assembly_x86 | source.asm |
| AutoHotkey / AutoIt | autohotkey | source.ahk |
| Bash | sh | source.shell |
| BatchFile | batchfile | source.batchfile |
| Bicep | bicep | source.bicep |
| C and C++ | c_cpp | source.cpp |
| C# | csharp | source.cs |
| Cirru | cirru | source.cirru |
| Clojure | clojure | source.clojure |
| Cobol | cobol | source.cobol |
| CoffeeScript | coffee | source.coffee |
| ColdFusion | coldfusion | text.cfml.basic |
| Crystal | crystal | source.crystal |
| Csound | csound_orchestra | source.csound |
| Csound Document | csound_document | source.csound-document |
| Csound Score | csound_score | source.csound-score |
| CSS | css | source.css |
| Curly | curly | text.html.curly |
| D | d | source.d |
| Dart | dart | source.dart |
| Diff | diff | source.diff |
| Django | django | source.python.django |
| Dockerfile | dockerfile | source.dockerfile |
| Dot | dot | source.dot |
| Drools | drools | source.drools |
| Edifact | edifact | text.plain.edifact |
| Eiffel | eiffel | source.eiffel |
| EJS | ejs | text.html.js |
| Elixir | elixir | source.elixir |
| Elm | elm | source.elm |
| Erlang | erlang | source.erlang |
F–K
| 语言(name) | value | scopeName |
|---|---|---|
| Forth | forth | source.forth |
| Fortran | fortran | source.fortran |
| F# | fsharp | source.fsharp |
| Gcode | gcode | source.gcode |
| Gherkin | gherkin | text.gherkin.feature |
| Gitignore | gitignore | source.gitignore |
| Glsl | glsl | source.glsl |
| Go | golang | source.go |
| GraphQL | graphqlschema | source.graphql |
| Groovy | groovy | source.groovy |
| HAML | haml | text.haml |
| Handlebars | handlebars | text.html.handlebars |
| Haskell Cabal | haskell_cabal | source.cabal |
| Haskell | haskell | source.haskell |
| haXe | haxe | source.hx |
| Hjson | hjson | source.hjson |
| HTML (Elixir) | html_elixir | text.html.elixir |
| HTML (Ruby) | html_ruby | text.html.erb |
| HTML | html | text.html.basic |
| INI | ini | source.ini |
| Io | io | source.io |
| Java | java | source.java |
| JavaScript | javascript | source.js |
| JSON | json | source.json |
| JSON5 | json5 | source.json5 |
| JSONiq | jsoniq | source.jsoniq |
| JSP | jsp | text.html.jsp |
| JSX | jsx | source.jsx |
| Julia | julia | source.julia |
| Kotlin | kotlin | source.kotlin |
| Kusto (KQL) | kusto | source.kusto |
L–R
| 语言(name) | value | scopeName |
|---|---|---|
| LaTeX | latex | text.tex.latex |
| Latte | latte | source.latte |
| LESS | less | source.css.less |
| Liquid | liquid | source.liquid |
| Lisp | lisp | source.lisp |
| LiveScript | livescript | source.livescript |
| LSL | lsl | source.lsl |
| Lua | lua | source.lua |
| Makefile | makefile | source.makefile |
| Markdown | markdown | text.html.markdown |
| Mask | mask | source.mask |
| MATLAB | matlab | source.matlab |
| MediaWiki | mediawiki | text.html.mediawiki |
| MEL | mel | source.mel |
| Mikrotik | mikrotik | source.mikrotik-script |
| MIPS | mips | source.mips |
| MySQL | mysql | source.sql.mysql |
| Nginx | nginx | source.nginx |
| Nim | nim | source.nim |
| Nix | nix | source.nix |
| NSIS | nsis | source.nsis |
| Nunjucks | nunjucks | text.html.nunjucks |
| Objective-C | objectivec | source.objc |
| OCaml | ocaml | source.ocaml |
| OpenGL | glsl | source.glsl |
| Pascal | pascal | source.pascal |
| Perl | perl | source.perl |
| pgSQL | pgsql | source.pgsql |
| PHP (Blade Template) | php_laravel_blade | text.html.php.blade |
| PHP | php | source.php |
| Pig | pig | source.pig |
| Plain Text | plain_text | text.plain |
| Powershell | powershell | source.powershell |
| Praat | praat | source.praat |
| Prisma | prisma | source.prisma |
| Prolog | prolog | source.prolog |
| Properties | properties | source.tm-properties |
| Protobuf | protobuf | source.proto |
| Pug | pug | text.pug |
| Puppet | puppet | source.puppet |
| Python | python | source.python |
| QML | qml | source.qml |
| R | r | source.r |
| Raku | raku | source.perl.6 |
| Razor | razor | text.aspnetcorerazor |
| Red | red | source.red |
| RegExp | regexp | source.regexp |
| RST | rst | source.rst |
| Ruby | ruby | source.ruby |
| Rust | rust | source.rust |
S–Z
| 语言(name) | value | scopeName |
|---|---|---|
| SAS | sas | source.sas |
| SASS | sass | source.sass |
| SCAD | scad | source.scad |
| Scala | scala | source.scala |
| Scheme | scheme | source.scheme |
| sCrypt | scrypt | source.scrypt |
| SCSS | scss | source.css.scss |
| SJS | sjs | source.sjs |
| Slim | slim | text.slim |
| Smalltalk | smalltalk | source.smalltalk |
| Smarty | smarty | source.smarty |
| Smithy | smithy | source.smithy |
| Solidity | solidity | source.solidity |
| Soy Template | soy_template | source.soy |
| SQL | sql | source.sql |
| SQLServer | sqlserver | source.sqlserver |
| Stylus | stylus | source.stylus |
| SVG | svg | text.xml.svg |
| Swift | swift | source.swift |
| Tcl | tcl | source.tcl |
| Terraform | terraform | source.terraform |
| Tex | tex | text.tex |
| Textile | textile | text.html.textile |
| TOML | toml | source.toml |
| TSX | tsx | source.tsx |
| Twig | twig | text.html.twig |
| TypeScript | typescript | source.ts |
| Vala | vala | source.vala |
| Velocity | velocity | text.velocity |
| Verilog | verilog | source.systemverilog |
| VHDL | vhdl | source.vhdl |
| Visualforce | visualforce | text.visualforce.markup |
| Vue | vue | text.html.vue |
| Wollok | wollok | source.wollok |
| XML | xml | text.xml |
| XSL | xsl | text.xml.xsl |
| XQuery | xquery | source.xquery |
| YAML | yaml | source.yaml |
| Zeek | zeek | source.zeek |
从上表可以观察到几类值得留意的细节:
- 共享语法文件:
Glsl与OpenGL的value同为glsl,都指向glsl.tmLanguage.json;SQL与SQLServer虽value不同(sql/sqlserver),但grammar都指向sql.tmLanguage.json;Stylus则复用了less.tmLanguage.json。 - 语法文件与语言名不完全同名:
Verilog实际加载的是systemverilog.tmLanguage.json;Makefile加载的是make.tmLanguage.json;Markdown加载的是markdown.tmLanguage.json(注意区分grammars/markdown.tmLanguage.json与辅助语法grammars-aux.ts中的source.md)。这一层“显示名 → mode → scope → 文件”的间接映射正是语言系统的设计核心。
三、语法注册链路:loadGrammars()与 onigasm WASM
清单中的每一项最终都要变成编辑器里可用的高亮语法,这一过程由 grammars.ts 的loadGrammars()完成:
export const loadGrammars = async () => { const grammars: Record<string, GrammarOption> = {} languages .filter(i => i.grammar) .forEach(async i => { if (!i.scopeName || !i.grammar) return grammars[i.scopeName] = { grammar: i.grammar, language: i.value, priority: 'defer' } }) auxGrammars.forEach(i => { grammars[i.source] = { grammar: i.grammar, language: i.language as Language, priority: 'defer' } }) await Promise.all( Object.keys(grammars).map(async scopeName => { const { grammar, language, priority } = grammars[scopeName] const { default: grammarDoc } = await grammar() try { addGrammar(scopeName, grammarDoc) if (language) { const prom = activateLanguage(scopeName, language, priority) if (priority === 'now') await prom } } catch (err) { console.error(err) } }) ) }其执行逻辑可拆解为四步:
- 收集语法:遍历
languages数组,将每个条目按scopeName作为键、{ grammar, language, priority: 'defer' }作为值放入grammars注册表。priority: 'defer'表示延迟激活,避免应用启动时同步等待全部语法解析完成。 - 并入辅助语法:再将
auxGrammars(见 grammars-aux.ts,共 40 个条目)并入同一注册表。辅助语法解决的是嵌入场景——例如source.scss、source.css.nunjucks、source.c++、source.x86、text.git-commit、text.jade等 scope,它们可能是主语言的子作用域或旧标识的兜底。 - 并行加载:
Promise.all逐个await grammar()动态导入对应的*.tmLanguage.json。 - 注册与激活:调用
codemirror-textmate的addGrammar(scopeName, grammarDoc)注册语法,再以activateLanguage(scopeName, language, priority)将 TextMate 语法激活到对应mode(即该语言的value)。
这条链路的上游在应用入口 App.vue 中触发:loadWASM(onigasmFile)先加载 onigasm 的正则引擎 WASM(onigasm 是 TextMate 语法正则匹配的运行时基础),随后await loadGrammars()完成全部语法的注册。也就是说,这 162 种语言的高亮能力在应用启动阶段就已就绪,后续编辑时只需按mode切换。
3.1 辅助语法:主清单之外的嵌入语法
grammars-aux.ts 中的条目不直接对应 README 清单,而是为组合语言与边界场景提供支持,典型如:
source.sassdoc→sassdoc:Sass 文档注释;source.js.jquery→jquery:复用javascript.tmLanguage.json的 jQuery 作用域;source.c/source.c++/source.cpp.embedded.macro:C/C++ 及其嵌入宏;source.x86/source.x86_64:汇编的分架构作用域;source.json.comments→json-comment:带注释的 JSON(JSONC);source.regexp.javascript/python/posix/extended:多套正则方言;text.bibtex、source.gnuplot、source.asymptote、source.arm、text.log、text.git-rebase、text.git-commit、text.html.javadoc、source.postscript等。
这些条目证明:语言清单只是“顶层入口”,真正的语法世界是分层作用域组成的——一个source.css.scss可以嵌套在text.html中,这正是 TextMate 语法体系相对传统 CodeMirror mode 的优势。
四、语言在界面中如何切换与持久化
4.1 编辑器底栏的下拉选择器
语言选择入口位于编辑器组件的底部状态栏。在 EditorCodemirror.vue 中,<select class="lang-selector">直接遍历languages数组渲染全部 162 个选项:
<select v-model="localLang" class="lang-selector"> <option v-for="i in languages" :key="i.value" :value="i.value"> {{ i.name }} </option> </select>localLang是双向绑定计算属性:get返回当前 snippet 的语言,set触发update:lang事件;切换后通过editor.setOption('mode', lang)(setLang)即时更换编辑器 mode。与此同时,底栏还实时显示光标行列位置(line / column),方便定位。
4.2 语言值的持久化与埋点
语言变更的落库逻辑在 SnippetsView.vue:
const lang = computed({ get: () => snippetStore.currentLanguage || 'plain_text', set: v => { snippetStore.patchCurrentSnippetContentByKey('language', v) track('snippets/set-language', v) } })即:语言标识以language键写入当前 snippet 的内容数据(patchCurrentSnippetContentByKey),并通过track('snippets/set-language', v)记录到分析埋点;默认值为plain_text。这意味着每个 snippet 的语言选择是独立持久化的,重新打开应用后仍保持上次设置。
4.3 语言与预览、截图功能的联动
在 SnippetsView.vue 中,lang还被透传给多个视图组件:EditorCodemirror(编辑)、EditorPreview(代码预览)、TheScreenshot(截图导出)等。也就是说,语言标识不只为高亮服务,还参与渲染预览、生成带语法样式的截图等下游功能,是 snippet 内容模型中的一等公民。
五、版本迁移:v1 旧语言标识映射
massCode 从 v1 升级到当前版本时,部分语言的内部标识发生了变化,因此 languages.ts 末尾定义了oldLanguageMap用于新旧标识的桥接:
export const oldLanguageMap: Record<any, Language> = { azcli: 'plain_text', bat: 'sh', cameligo: 'plain_text', coffeescript: 'coffee', c: 'c_cpp', csp: 'plain_text', go: 'golang', graphql: 'graphqlschema', msdax: 'plain_text', 'objective-c': 'objectivec', pascaligo: 'plain_text', postiats: 'plain_text', powerquery: 'plain_text', pug: 'jade', redis: 'plain_text', sb: 'plain_text', shell: 'sh', sol: 'plain_text', aes: 'plain_text', st: 'plain_text', vb: 'vbscript' }该映射把 v1 时代的旧值(如bat、shell、coffeescript、c、go、graphql、'objective-c')归一化到当前版本的语言标识(如sh、coffee、c_cpp、golang、graphqlschema、objectivec),其中部分语言在当前版本中已不再作为独立条目提供高亮(如cameligo、redis、sol),统一回退为plain_text;pug → jade则与辅助语法中text.jade(复用pug.tmLanguage.json)相互印证。这套映射保证了老用户数据在升级后仍能正确解析语言字段。
六、语言与格式化(Prettier)的配合
语言标识还决定“格式化代码”功能是否可用。在 EditorCodemirror.vue 的format()中,维护了一个 22 种语言的availableLang白名单:
const availableLang: Language[] = [ 'css', 'dockerfile', 'gitignore', 'graphqlschema', 'html', 'ini', 'jade', 'java', 'javascript', 'json', 'json5', 'less', 'markdown', 'php', 'properties', 'sass', 'scss', 'sh', 'toml', 'typescript', 'xml', 'yaml' ]只有当 snippet 的value命中白名单时,格式化才被触发,且解析器会做一次映射:
javascript→babel(Babel 解析器);graphqlschema→graphql;dockerfile/gitignore/properties/ini→sh(shell 风格解析器)。
格式化请求通过 IPCmain:prettier转发给主进程的 prettier 服务 执行,成功后回写内容并埋点snippets/format。这说明:语言清单不只是高亮开关,也是格式化、预览等编辑能力的路由表。
七、如何为 massCode 扩展一种新语言
结合源码结构(非官方文档声明,属实现层面推断),新增语言通常只需三步:
- 放置语法文件:将语言对应的 TextMate 语法 JSON(
*.tmLanguage.json)放入 src/renderer/components/editor/grammars 目录(当前该目录已收录 195 个语法文件,包含清单 162 项及其变体)。 - 声明条目:在 languages.ts 的
languages数组末尾追加一个LanguageOption对象,四要素缺一不可:name(显示名)、value(唯一 mode 标识,需同步补充到 Language 联合类型)、grammar(() => import('./grammars/xxx.tmLanguage.json')懒加载函数)、scopeName(语法文件的根 scope)。 - 按需补充辅助语法:若新语言存在嵌入子作用域,可在 grammars-aux.ts 中追加对应条目。
由于loadGrammars()在启动时统一遍历languages注册,新条目会自动出现在编辑器底栏的下拉框中,无需改动任何 UI 代码。同理,删除清单条目即可在语言列表中移除对应语言。
八、边界情况与注意事项
- 同名异值:
Glsl与OpenGL共用glslmode,切换其中任何一个,另一个的代码高亮行为一致——这是从源码中value相同这一事实推断出的行为。 - 语法复用:
Stylus复用less.tmLanguage.json、Verilog加载systemverilog.tmLanguage.json、Makefile加载make.tmLanguage.json等,意味着这些语言的高亮规则继承自其源语法,主题色表现可能不完全等同于专用语法。 - 待校对注释:languages.ts 与
Haskell Cabal条目旁保留了俄语注释// Возможно несоответствие(意为“可能存在不匹配”),说明ABC(scopetext.abcnotation)与Haskell Cabal(scopesource.cabal)两条语法的 scope 声明在仓库中仍标记为待校验项。 - 主题配合:语法着色最终还要与主题配合呈现,themes 目录 内置 12 个
*.tmTheme.json(Dracula、Monokai、One Dark、Tokyo Night 等),由 themes.ts 注册到codemirror-textmate。语言 × 主题共同决定最终渲染效果。
结语
src/renderer/components/editor/README.md这份看似只有语言列表的文档,实际上是整个编辑器语法体系的索引入口:162 个名字背后,是languages.ts的声明、195 个tmLanguage.json语法文件、loadGrammars()+ onigasm WASM 的注册链路、codemirror-textmate的作用域激活,以及语言标识在持久化、格式化和预览中的复用。理解这张对照表与加载链路,不仅能帮你快速定位任意语言在 massCode 中的内部标识,也为自定义扩展语言提供了清晰的路径。
- 开发工具
- 桌面应用
【免费下载链接】massCode
A free, open-source developer workspace. Snippets, notes, HTTP requests, calculations, and dev tools in one local-first app.
相关推荐
突破语言壁垒:为Kilo编辑器扩展多语言语法高亮支持
突破语言壁垒:为Kilo编辑器扩展多语言语法高亮支持 你是否曾因Kilo编辑器仅支持C/C++语法高亮而感到受限?作为一款精简到极致的开源文本编辑器(不到100
代码编辑器CLITabby 终端完整上手指南:如何用一款跨平台终端搞定本地 Shell、SSH 与串口调试
Tabby 终端完整上手指南:如何用一款跨平台终端搞定本地 Shell、SSH 与串口调试 Tabby(原名 Terminus)是一款面向现代开发者的跨平台终端
桌面应用网络通信Cangjie-TPC/editor4cj语言支持扩展教程:添加新编程语言
Cangjie TPC/editor4cj语言支持扩展教程:添加新编程语言 还在为编辑器不支持你心爱的编程语言而烦恼?想要为开源编辑器贡献自己的力量却不知从何下
OpenHarmonyUI组件代码编辑器前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考