Monaco 核心概念:Model / Editor / View 与 Theia 抽象
这一篇集中把 Monaco 里最基础的那几块概念理一理:文本模型(Model)、编辑器实例(Editor)、视图(View),
再对照一下 Theia 里的TextEditor、EditorManager和编辑器 Widget,方便之后看源码时不迷路。
文本模型(ITextModel):真正存放代码内容的地方
在 Monaco 里,ITextModel 是“文本内容 + 标记”的核心载体:
- 负责存储文本文字本身;
- 管理行信息、换行、EOL 风格;
- 承载语法高亮 token、装饰器范围、折叠区域等元数据。
创建一个最简单的模型示例:
1const model = monaco.editor.createModel(
2 'function hello() {\n console.log("hello");\n}\n',
3 'javascript',
4 monaco.Uri.parse('file:///example.js'),
5);
特点:
- 一个
ITextModel不依赖具体的编辑器实例,可以在没有任何可见编辑器的情况下存在; - 同一个模型可以被多个编辑器共享(例如“分屏查看同一个文件”)。
在 Theia 里,对应的概念是文本文档模型,通常由文档服务/编辑器服务管理,
编辑器 Widget 更多是“挂在这个模型上提供视图和交互”的角色。
编辑器实例(IStandaloneCodeEditor):操作模型的入口
Monaco 的编辑器实例最常用的是 IStandaloneCodeEditor:
1const editor = monaco.editor.create(domNode, {
2 model,
3 language: 'javascript',
4 readOnly: false,
5 automaticLayout: true,
6});
这个实例负责:
- 在指定 DOM 节点里渲染视图;
- 处理键盘、鼠标等输入;
- 提供一系列操作 API,例如:
getModel()/setModel()getPosition()/setPosition()executeEdits()/getSelections()- 滚动、聚焦、布局等。
可以简单地把它看成“一个挂在特定 DOM 节点上的编辑器视图 + 控制器”,
而真正的数据和结构性信息仍然在底层的 ITextModel 里。
在 Theia 中,MonacoEditor 正是对这个编辑器实例的一层封装,
并通过 TextEditor 接口暴露出更稳定的抽象供其它扩展使用。
一个 Model 可以挂多个 Editor
Monaco 允许多个编辑器实例共享同一个模型,常见场景是“分屏查看同一个文件”:
1const model = monaco.editor.createModel('...', 'typescript', monaco.Uri.parse('file:///a.ts'));
2
3const editor1 = monaco.editor.create(domNode1, { model });
4const editor2 = monaco.editor.create(domNode2, { model });
效果:
editor1和editor2显示同一份文本;- 在其中一个编辑器里修改内容,另一个会同步更新(因为底层模型是同一个);
- 两个编辑器可以有各自的滚动位置、光标位置、装饰器(部分装饰器可以绑定在视图侧)。
Theia 里的分屏行为背后就是利用了这一点:
只要有合适的抽象和 Widget 组合,就可以在不同布局区域贴上多个共享同一模型的 Monaco 视图。
View 的角度:模型是数据,编辑器是视图 + 控制
从 MVC/MVVM 的角度看,可以粗略这样对应:
- Model(ITextModel):负责数据和元信息;
- View + Controller(Editor 实例):负责渲染和交互;
- 语言服务 / 装饰器:可以类比为各种“服务层”,对模型和视图提供额外能力。
这套划分在 Theia 里的映射大致是:
- 文本模型 → 文档模型服务(背后还是基于 Monaco 的
ITextModel); - Monaco 编辑器实例 →
MonacoEditor实现类; - 编辑器 Widget → 把
MonacoEditor包到 Lumino Widget 里,参与布局。
理解这一点之后,再看 Theia 的接口设计时会更自然:
很多 API 是围绕“文档/模型”和“编辑器/视图”两条线分别展开的。
小结:先牢牢记住“一个模型,多种视图”的图景
后面在聊语言服务、装饰器、命令操作时,这几个基本点会经常被用到:
- 文本内容和高亮、折叠等结构性信息存放在
ITextModel里; - 编辑器实例负责把模型展示出来,并处理编辑操作;
- Theia 在这个基础上加了一层自己的抽象(
TextEditor、Widget、Manager),
既不直接暴露 Monaco 的所有细节,又保留了足够的能力去做 IDE 级别的功能。
记住这张图,对之后阅读 Monaco 与 Theia 相关源码会很有帮助。**