☰
massCode 编辑器语言支持全览:162 种语法的声明、加载与扩展机制
2026/10/15 15:29:45 网站建设 项目流程
  • 开发工具
  • 桌面应用

【免费下载链接】massCode

A free, open-source developer workspace. Snippets, notes, HTTP requests, calculations, and dev tools in one local-first app.

项目地址:https://gitcode.com/gh_mirrors/ma/massCode
点击查看免费下载

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)valuescopeName
ABAPabapsource.abap
ABCabctext.abcnotation
ActionScriptactionscriptsource.actionscript.3
ADAadasource.ada
Aldaaldasource.alda
Apache Confapache_confsource.apacheconf
Apexapexsource.apex
Apple Scriptapplescriptsource.applescript
AsciiDocasciidoctext.asciidoc
ASLaslsource.asl
ASP vb.NET (VBScript)asp_vb_netsource.asp.vb.net
Assembly x86assembly_x86source.asm
AutoHotkey / AutoItautohotkeysource.ahk
Bashshsource.shell
BatchFilebatchfilesource.batchfile
Bicepbicepsource.bicep
C and C++c_cppsource.cpp
C#csharpsource.cs
Cirrucirrusource.cirru
Clojureclojuresource.clojure
Cobolcobolsource.cobol
CoffeeScriptcoffeesource.coffee
ColdFusioncoldfusiontext.cfml.basic
Crystalcrystalsource.crystal
Csoundcsound_orchestrasource.csound
Csound Documentcsound_documentsource.csound-document
Csound Scorecsound_scoresource.csound-score
CSScsssource.css
Curlycurlytext.html.curly
Ddsource.d
Dartdartsource.dart
Diffdiffsource.diff
Djangodjangosource.python.django
Dockerfiledockerfilesource.dockerfile
Dotdotsource.dot
Droolsdroolssource.drools
Edifactedifacttext.plain.edifact
Eiffeleiffelsource.eiffel
EJSejstext.html.js
Elixirelixirsource.elixir
Elmelmsource.elm
Erlangerlangsource.erlang

F–K

语言(name)valuescopeName
Forthforthsource.forth
Fortranfortransource.fortran
F#fsharpsource.fsharp
Gcodegcodesource.gcode
Gherkingherkintext.gherkin.feature
Gitignoregitignoresource.gitignore
Glslglslsource.glsl
Gogolangsource.go
GraphQLgraphqlschemasource.graphql
Groovygroovysource.groovy
HAMLhamltext.haml
Handlebarshandlebarstext.html.handlebars
Haskell Cabalhaskell_cabalsource.cabal
Haskellhaskellsource.haskell
haXehaxesource.hx
Hjsonhjsonsource.hjson
HTML (Elixir)html_elixirtext.html.elixir
HTML (Ruby)html_rubytext.html.erb
HTMLhtmltext.html.basic
INIinisource.ini
Ioiosource.io
Javajavasource.java
JavaScriptjavascriptsource.js
JSONjsonsource.json
JSON5json5source.json5
JSONiqjsoniqsource.jsoniq
JSPjsptext.html.jsp
JSXjsxsource.jsx
Juliajuliasource.julia
Kotlinkotlinsource.kotlin
Kusto (KQL)kustosource.kusto

L–R

语言(name)valuescopeName
LaTeXlatextext.tex.latex
Lattelattesource.latte
LESSlesssource.css.less
Liquidliquidsource.liquid
Lisplispsource.lisp
LiveScriptlivescriptsource.livescript
LSLlslsource.lsl
Lualuasource.lua
Makefilemakefilesource.makefile
Markdownmarkdowntext.html.markdown
Maskmasksource.mask
MATLABmatlabsource.matlab
MediaWikimediawikitext.html.mediawiki
MELmelsource.mel
Mikrotikmikrotiksource.mikrotik-script
MIPSmipssource.mips
MySQLmysqlsource.sql.mysql
Nginxnginxsource.nginx
Nimnimsource.nim
Nixnixsource.nix
NSISnsissource.nsis
Nunjucksnunjuckstext.html.nunjucks
Objective-Cobjectivecsource.objc
OCamlocamlsource.ocaml
OpenGLglslsource.glsl
Pascalpascalsource.pascal
Perlperlsource.perl
pgSQLpgsqlsource.pgsql
PHP (Blade Template)php_laravel_bladetext.html.php.blade
PHPphpsource.php
Pigpigsource.pig
Plain Textplain_texttext.plain
Powershellpowershellsource.powershell
Praatpraatsource.praat
Prismaprismasource.prisma
Prologprologsource.prolog
Propertiespropertiessource.tm-properties
Protobufprotobufsource.proto
Pugpugtext.pug
Puppetpuppetsource.puppet
Pythonpythonsource.python
QMLqmlsource.qml
Rrsource.r
Rakurakusource.perl.6
Razorrazortext.aspnetcorerazor
Redredsource.red
RegExpregexpsource.regexp
RSTrstsource.rst
Rubyrubysource.ruby
Rustrustsource.rust

S–Z

语言(name)valuescopeName
SASsassource.sas
SASSsasssource.sass
SCADscadsource.scad
Scalascalasource.scala
Schemeschemesource.scheme
sCryptscryptsource.scrypt
SCSSscsssource.css.scss
SJSsjssource.sjs
Slimslimtext.slim
Smalltalksmalltalksource.smalltalk
Smartysmartysource.smarty
Smithysmithysource.smithy
Soliditysoliditysource.solidity
Soy Templatesoy_templatesource.soy
SQLsqlsource.sql
SQLServersqlserversource.sqlserver
Stylusstylussource.stylus
SVGsvgtext.xml.svg
Swiftswiftsource.swift
Tcltclsource.tcl
Terraformterraformsource.terraform
Textextext.tex
Textiletextiletext.html.textile
TOMLtomlsource.toml
TSXtsxsource.tsx
Twigtwigtext.html.twig
TypeScripttypescriptsource.ts
Valavalasource.vala
Velocityvelocitytext.velocity
Verilogverilogsource.systemverilog
VHDLvhdlsource.vhdl
Visualforcevisualforcetext.visualforce.markup
Vuevuetext.html.vue
Wollokwolloksource.wollok
XMLxmltext.xml
XSLxsltext.xml.xsl
XQueryxquerysource.xquery
YAMLyamlsource.yaml
Zeekzeeksource.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) } }) ) }

其执行逻辑可拆解为四步:

  1. 收集语法:遍历languages数组,将每个条目按scopeName作为键、{ grammar, language, priority: 'defer' }作为值放入grammars注册表。priority: 'defer'表示延迟激活,避免应用启动时同步等待全部语法解析完成。
  2. 并入辅助语法:再将auxGrammars(见 grammars-aux.ts,共 40 个条目)并入同一注册表。辅助语法解决的是嵌入场景——例如source.scss、source.css.nunjucks、source.c++、source.x86、text.git-commit、text.jade等 scope,它们可能是主语言的子作用域或旧标识的兜底。
  3. 并行加载:Promise.all逐个await grammar()动态导入对应的*.tmLanguage.json。
  4. 注册与激活:调用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 扩展一种新语言

结合源码结构(非官方文档声明,属实现层面推断),新增语言通常只需三步:

  1. 放置语法文件:将语言对应的 TextMate 语法 JSON(*.tmLanguage.json)放入 src/renderer/components/editor/grammars 目录(当前该目录已收录 195 个语法文件,包含清单 162 项及其变体)。
  2. 声明条目:在 languages.ts 的languages数组末尾追加一个LanguageOption对象,四要素缺一不可:name(显示名)、value(唯一 mode 标识,需同步补充到 Language 联合类型)、grammar(() => import('./grammars/xxx.tmLanguage.json')懒加载函数)、scopeName(语法文件的根 scope)。
  3. 按需补充辅助语法:若新语言存在嵌入子作用域,可在 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.

项目地址:https://gitcode.com/gh_mirrors/ma/massCode
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询