基于 VSCode/Monaco 的 iOS 编辑器(一)
// 本文首发于专栏 Better Naming,聊一聊编辑器与 IDE 的开发
经常有朋友问我能不能把 VSCode 跑在某个他们心爱的平台上,包括并不见限于树莓派、 iPhone、iPad、Windows Phone,再或者上 Windows Store (UWP)。有点想法着实有趣,比如在 iPad Pro 上编辑代码或者 Markdown 文本。而最近 SourceGraph (就是垠神的前前...前公司) 把整个 VSCode 剪裁了放到了浏览器当中,让我对 port 到其他平台这件事情产生了兴趣,做了一点小小的尝试。
# VSCode 的架构
移植 VSCode 的想法由于过于狂野,为了避免一些不切实际的妄想,我还是要先冷静下来回顾一下 VSCode 的架构,这样才知道哪些是可以操作的,而哪些基本属于扯淡。
首先按照 UI 结构来划分
- VSCode 中的编辑区域是 Monaco Editor,是完全基于浏览器的 Code/Text Editor,塞到 WebView 里就好了。
- 左侧 Sidebar
- File Explorer 虽然 iOS 应用操作文件的方式跟 PC 区别比较大,但是模拟一下没啥问题。SourceGraph 就把文件 API 替换成了 Rest 服务。
- Search VSCode 用 ripgrep,只能用别的方案实现了。
- Git 必须得用 iOS 平台的 Git 方案来代替。
- Debug 这个咱还是先不要在这个上面浪费脑细胞了。
- Extension VSCode 的插件都是运行在 node 上的,不过 Monaco 本身也有一套 extension api。所以把换一整套插件中心 (逃
- 底侧 Panel
- Terminal 在 iOS 上一个 Terminal Emulator 除了支持 ssh 比较有优势以外,其他干不了太多事情。
- Task/Output/Errors 这些都跟语言功能和插件功能有关,UI 肯定能 port,但是功能有待商榷。
我表示很尴尬,Sidebar 和 Panel 里的功能,要么是假设你在 PC 上 (Explorer, Terminal, ripgrep),要么就跟语言的支持有关。做起来比较无痛的只有
Monaco Editor
当然还有半个 Extension Viewlet,但是整个生态得换成 Monaco 的插件体系。接着我们来看下 Language 的支持情况:
- Intellisense 无论一门语言是使用 LSP 还是别的方式,提供真的抑或是假的 Intellisense 如果要搬上 iOS,这就意味着这套代码分析的工具得运行在 iOS 上。
- TypeScript Monaco 自带 TypeScript/JavaScript Intellisense 支持,方法是把 TypeScript 的 LSP 跑在 Web Worker 里。不过这个 LSP 只处理单个文件,放在浏览器里还是比较合理的,但是在 iOS 上,用户应该更希望能够处理本地的整个项目。需要一定的魔改。
- Ruby、C#、Java 等可以把 VM 一起 ship 到应用里语言,难度参考楼上。
- 其他。我都不敢想。
- Auto Complete
- 同上,如果没有 JavaScript 实现的代码分析,那么只有 word base auto complete。
- Tokenization
- VSCode 支持 TextMate 的 Grammar,但是这套系统的 Regex Engine 还没法 Port 到浏览器里(WebAssembly 可能能解决问题)。
- Monaco 有一套自己的语法方案 Monaco Editor Monarch 。现在只有 TypeScript、Markdown、JSON 和 XML 的语法,不确定社区有没有别的语言支持。当然可以把 TextMate 的 Grammar 降维到 Monarch。
# 我们退一步
如果你没兴趣看上面的分析也没关系,结论其实很简单。现阶段,就我们已有的代码和框架,我们能够做的是
- 把 Monaco Editor 移植到 iOS 上,使用某种 WebView 方案加载。
- 用 Swift 实现一套文件管理
- 做一个 JavaScript 和 Swift 代码之间的 Bridge
- 优化 Markdown、TS/JS、HTML、JSON/XML 的书写
虽然从来没有写过 iOS 应用,但我花了一个周末尝试了一下,做出了下面这个代码/文本编辑应用
## Markdown
Monaco on iOS Markdown—在线播放—优酷网,视频高清在线观看http://v.youku.com/v_show/id_XMjg0NTY1MDAxMg==.html?spm=a2h3j.8428770.3416059.1## TypeScript
# 结果只能说差强人意
拿着这个简单的 demo,我比对了一下 钟颖Cyan - 知乎 老师在他的文章 实现简易的代码编辑器 - 知乎专栏 中提到的一个可被接受的代码编辑器需要具备的条件
- 实时代码高亮
- 自动折行
- 自动保持缩进
- 自动插入花括号
- 方便输入符号
前四个都实现了,最后一个由于我使用了 WKWebView,暂时没有找到添加 inputAccessoryView 的正确方法。
但是真正令人略有沮丧的是,Monaco Editor 并没有处理对 Touch 进行处理。大家知道,VSCode/Monaco 在编辑代码时那个跳动的光标还有文本选择(selection),都是我们手动绘制出来的,而真正的 textarea 只是一个肉眼不可见的 1px by 1px 的点。在这种情况下,Monaco 不仅无法进行长按选择文字这种操作,更别说什么 3D touch 了,2D 都没有。此外,iOS Safari 里一个 hidden 的 textarea 无法接收到 Tab/Arrows 等 event,这就意味着在你的 iPad 上暂时没法使用方向键来操控光标。
# 下一步
相比 钟颖 老师在他的 iOS 代码编辑器里使用的方案则很有意思,直接 JSCore 来处理 JavaScript 操作,然后利用 TextKit 绘制原生的编辑器。也许我们可以把 Monaco 的 Rendering Layer 和 Model 完全分开,然后在 iOS 上把 Rendering Layer 换成原生 TextKit,Model 和 View Coordinates 的计算依然放在 JSCore 中。这是一个值得尝试的思路。
此外,由于 Monaco 的可扩展性,这样的编辑器是可以做到允许用户使用 JavaScript 去改变编辑器行为的。比如改变高亮、修改 Markdown 语法等等。简言之,这个编辑器可以有一个自己的插件中心。
Stay tuned.