vim.wasm :VIM移植到WebAssembly
该项目是@RHYSD的VIM编辑器实验叉,可将其编译为使用Emscripten和Binaryen的WebAssembly。 VIM在Web Worker上运行,并通过共享ARNEARRAYBUFFER与主线程进行交互。
该项目的目的是在浏览器上运行VIM编辑器,而不会通过将VIM C源编译到WebAssembly中而丢失VIM强大的功能。
使用浏览器尝试
-
用法
- 几乎所有VIM的功能强大功能(语法突出显示,VIM脚本,文本对象等)都得到了最新功能(弹出窗口,…)。
- 将文件拖放到浏览器选项卡中,在VIM中打开它们。
- :仅在内存上写入文件。下载当前缓冲区:导出或特定文件:导出{file}。
- 剪贴板寄存器“*得到支持。
- 〜/.vim目录下的文件持续存储在索引DB中。请在〜/.vim/vimrc(非〜/.vimrc)中写出您喜欢的配置。
- file = {filepath} = {url}将文件从{url}获取到{filepath}。可以打开任意远程文件(关心CORS)。
- 默认的Colorscheme是OneDark.vim,但Vim-Monokai也可以作为高对比度Colorscheme提供。
- :!/path/to/file.js在浏览器中评估JavaScript代码。 :!%评估当前缓冲区。
- Vimtutor可供选择:e Tutor。
- 添加arg =查询参数(例如?
- 请阅读使用文档以获取更多详细信息。
-
注意
- 请从桌面铬,Firefox,Safari或基于铬的浏览器访问,因为该项目使用共享ArneararayBuffer和Atomics。在Firefox或Safari上,必须暂时启用功能标志(javascript.options.shared_memory)。
- vim.wasm从DOM KEYDOWN事件中获取密钥输入。请禁用您的浏览器扩展名截取关键事件(隐身模式将是最好的)。
- 这个项目是实验的早期阶段。您可能很快就会注意到它…这是越野车:)
- 如果输入某物没有任何更改,请尝试单击页面中的某个地方。 VIM可能失去了焦点。
- VIM退出:退出,但不会关闭浏览器选项卡。请手动关闭它:)
该项目被包装为VIM-WASM NPM PACAKGE,可轻松在Web应用程序中使用。请阅读文档以获取更多详细信息。
当前的移植VIM版本为8.2.0055,具有“正常”和“小”功能集。请检查变更记录以获取更新历史记录。
相关项目
以下项目与此NPM软件包有关,可能更适合您的用例。
- 反应 – vim-wasm: vim.wasm的反应成分。 VIM编辑器可以嵌入您的React Web应用程序中。
- vimwast-try-plugin:命令行工具以打开vim.wasm ,包括指定的vim插件。您可以在不安装的情况下尝试VIM插件!
- vim.wasm .ipynb:jupyter笔记本与vim.wasm集成。在线尝试!
演讲和博客文章
- 演示幻灯片
- (英语)VIMCONF 2018(2018年11月24日)
- (日语)Emscripten和WebAssembly Night! #8(2019年7月24日)
- 日本博客文章1 2
它如何工作
用户互动
在Worker线程中,VIM通过编译为WASM运行。打开页面时,将工作线程从主线程中产生为专用的Web Worker。
假设您用键盘输入一些东西。浏览器将其作为键盘事件中的键盘视为。主线程中的JavaScript捕获事件,并将键盘信息存储到共享内存缓冲区中。
缓冲区与工作线程共享。 VIM等待并通过通过JavaScript的Atomics API对共享内存缓冲区进行轮询来获取键盘信息。当在缓冲区中找到密钥信息时,它会加载信息并计算关键序列。通过JS到WASM API得益于Emscripten,该序列被添加到WASM中VIM的输入缓冲区中。
输入缓冲区中的序列由Core Editor Logic(更新缓冲区,屏幕,…)处理。由于更新,某些绘制事件发生了,例如绘制文本,绘制式,滚动区域,…
由于Emscripten的JS至C API,这些抽奖活动将从WASM中的WARSM中发送给JavaScript。考虑到设备像素比和<canvas/> api,如何计算事件,这些计算出的渲染事件将通过postmessage()传递的消息传递到主线程。
主线程JavaScript接收并招募这些渲染事件。在动画框架上,它将它们渲染为<canvas/>。
最后,您可以在页面中看到渲染的屏幕。
构建过程
VIM的WebAssembly前端与其他GUI(例如GTK Frontend)一样,是VIM的新GUI前端。 c源被编译到每个LLVM比特代码文件,然后将它们链接到一个BITCODE文件vim.bc。 EMCC最终将使用二进制将vim.bc编译为vim.wasm二进制,并生成HTML/JavaScript运行时。
我最初面临的差异是缺乏终端库,例如ncurses。我修改了配置脚本以忽略终端库检查。没关系,因为WASM的GUI前端总是使用而不是CUI前端。我需要许多解决方法来传递配置检查。
Emscripten提供类似Unix的环境。因此,OS_UNIX.C可以支持WASM。但是,Emscripten不支持某些功能。我添加了许多#ifdef feat_gui_wasm guards,以禁用WASM(即叉(2)支持,PTY支持,信号处理程序的固定功能,…等等)。
我创建了GUI_WASM.C,大量参考GUI_MAC.C和GUI_W32.C。事件循环(GUI_MCH_UPDATE()和GUI_MCH_WAIT_FOR_CHARS())仅通过阻止等待来实现。而且,几乎所有的UI渲染事件都将通过Emscripten调用C的JavaScript函数传递给JavaScript层。
C源(具有许多优化)与clang的LLVM比特码合并到Emscripten。然后,所有比特代码文件(.O)都链接到带有LLVM-Link Linker(也集成到EMScripten)的一个BitCode文件vim.bc。
我在打字稿中创建了JavaScript运行时,以绘制C. JavaScript运行时发送的渲染事件分为两个部分;主线程和工人线程。 wasm/main.ts用于主线程。它在Worker线程中启动VIM,并将VIM屏幕绘制为<Canvas>从VIM接收绘制事件。 wasm/runtime.ts和wasm/pre.ts用于工作线程。它们是使用Emscripten API编写的。
EMCC(Emscripten的C编译器)使用Binaryen编译了带有预加载的VIM Runtime Files(IE Colorscheme)的vim.wasm ,VIM.JS和VIM.DATA中的vim.bc和runtime.js。运行时文件被加载在Emscripten在浏览器上提供的虚拟文件系统上。在这里,这些文件是用于工作线程的。 wasm/main.js启动了一个专用的Web Worker加载vim.js。
最后,我创建了一个小的wasm/index.html,其中包含<canvas/>以渲染vim屏幕并加载wasm/main.js。
现在,使用Web服务器托管WASM/index.html并使用浏览器打开VIM访问它。有用。
如何在JavaScript上睡觉()
此移植最困难的部分是如何实现阻止等待(通常使用睡眠()完成)。
由于在网页上阻止主线程意味着阻止用户交互,因此基本上禁止它。几乎所有花费时间的操作在JavaScript中都实现为异步API。在主线程上运行的WASM不能阻止线程,除了繁忙的循环。
但是C程序随便使用Sleep()函数,因此移植程序时是一个问题。 VIM的GUI前端也有望通过阻止等待等待用户输入。
Emscripten为此问题提供解决方法,EmterPreter。使用EmterPreter,Emscripten提供(伪)阻止等待功能,例如Emscripten_sleep()。当它们用于C函数时,EMCC将函数编译为EmterPreter字节代码而不是WASM。在运行时,字节代码是在解释器上运行的(在WASM上)。当解释器在调用emscripten_sleep()的点到达时,它暂停字节代码执行并设置计时器(带有Settimeout JS函数)。时间到期后,口译员恢复状态并继续执行。
通过这种机制,JavaScript的异步等待看起来好像来自C World的同步等待。起初,我使用了Emterpreter,并且起作用。但是,有几个问题。
- 它将VIM源分为两个部分;纯WASM代码直接运行,EmterPreter Byte代码在解释器上运行。我需要维护大型功能列表,这些列表应将其编译到EmterPreter字节代码中。当列表错误时,VIM崩溃了
- EmterPreter的速度不是那么快,所以它会减慢整个应用程序
- EmterPreter使程序不稳定。例如JS和C互动在某些情况下不起作用
- Emterpreter使二进制构建更大,汇编更长。将C代码汇编为EmterPreter字节代码非常慢,因为它需要大规模的代码转换。 EmterPreter字节代码非常简单,因此其二进制尺寸更大
我寻找了一个替代品和发现的atomics.wait()。 Atomics.Wait()是低级同步原始函数。它等到共享内存缓冲区中的特定字节更新。它正在阻止等待。当然,它在主线程上不可用。它必须在工作线程上使用。
我将WASM代码基库移至Web Worker上在Worker线程上运行的Web Worker,尽管渲染<canvas/>仍在主线程中完成。
VIM使用Atomics.Wait()通过观看共享内存缓冲区来等待用户输入。当关键事件发生时,主线程将关键事件数据存储到共享内存缓冲区中,并通知Atomics.notify()出现新的密钥事件。 Worker线程检测缓冲区是否通过Atomics.Wait()更新,并从缓冲区加载关键事件数据。 VIM从数据中计算一个密钥序列,并将其添加到输入缓冲区中。最终,VIM处理事件,并通过JavaScript将DRAW事件发送到主线程。
作为奖励,不再阻止用户互动,因为几乎所有逻辑(包括整个VIM)都在工作线程中运行。
发展
请确保安装了Emscripten(我使用的1.38.37)和二进制(我使用的V84)。如果您使用MACOS,则可以使用Brew Install Emscripten Binaryen安装它们。
请使用build.sh脚本黑客入侵此项目。克隆此存储库后,只需运行./build.sh即可。它在WASM/ Directory中构建了vim.wasm 。它需要时间,并且CPU电源很多。
最后,使用Web服务器(例如Python -M HTTP.Server 1234)托管WASM/直接在Localhost上托管。请注意,由于启用了许多调试功能,因此它比发行版本要慢得多。有关更多详细信息,请阅读WASM/readme.md。
请注意,该存储库的WASM分支经常合并最新的VIM/VIM主分支。如果您想入侵此项目,请确保创建自己的分支机构并通过GIT合并将WASM分支合并到您的分支机构中。
已知问题
-
WebAssembly和JavaScript不提供睡眠()。默认情况下,Emscripten将Sleep()编译成一个繁忙的循环。因此, vim.wasm使用的EmterPreter提供了Emscripten_sleep()。一些白名单的功能由EmterPreter运行。但是此功能不是那么稳定。它使构建的二进制文件更大,并且编译更长。这是#30固定的 -
javaScript到C无法完全与EmterPreter一起使用。例如,调用一些C API破坏EmterPreter堆栈。这也意味着从JavaScript调用C函数传递字符串参数不起作用。这是#30固定的 - 默认情况下,仅支持基于铬和铬的浏览器。 Firefox和Safari需要启用功能标志。这是因为由于幽灵安全漏洞,共享arranarayBuffer被禁用。这可以通过异步固定。这项工作正在进行中,并在PR#35进行了跟踪。
托多
开发是在GitHub项目中管理的。
- 考虑支持更大的功能集(“大”和“巨大”)
- 使用WebAssembly的多线程支持与原子说明,而不是JavaScript Atomics API
-
使用屏幕外画布渲染<canvas/>在工作线程中目前不可用。请阅读笔记。 - 鼠标支持
- IME支持
- 包装vim.wasm作为Web组件
特别感谢
该项目受到Lu Wang的令人印象深刻的VIM.JS的启发。
执照
此存储库中的所有其他文件均在与VIM(VIM许可证)相同的许可下获得许可。请参阅:帮助许可以获取更多详细信息。
原始Readme正在关注。
有关此读数的翻译,请参阅结尾。
什么是vim?
VIM是Good Old Unix编辑器VI的大大改进版本。添加了许多新功能:多级撤消,语法突出显示,命令行历史记录,在线帮助,拼写检查,文件名完成,块操作,脚本语言等。还有一个图形用户界面(GUI)。尽管如此,维持VI兼容性,那些“手指”的VI的人会感到宾至如归。有关VI的差异,请参见Runtime/doc/vi_diff.txt。
该编辑器对于编辑程序和其他纯文本文件非常有用。所有命令均以普通键盘字符给出,因此那些可以用十个手指打字的人可以很快工作。此外,功能键可以由用户映射到命令,并且可以使用鼠标。
VIM在MS-Windows(NT,2000,XP,Vista,7,8,10),Macintosh,VM和Unix的几乎所有口味下运行。移植到其他系统应该不是很困难。 VIM的较旧版本在MS-DOS,MS-Windows 95/98/ME,Amiga DOS,Atari Mint,Beos,Risc OS和OS/2上运行。这些不再维护。
分配
您通常可以使用自己喜欢的软件包管理器安装VIM。在Mac和Linux上,预装了VIM的小版本,如果您想要更多功能,仍然需要安装VIM。
对于UNIX,PC,Amiga和其他一些系统,有单独的分布。此readme.md文件附带运行时档案。它包括在运行时使用的文档,语法文件和其他文件。要运行VIM,您必须获得其中一个二进制档案或源档案。您需要哪一个取决于要运行的系统以及您想要还是必须自己编译。检查http://www.v*i**m.org/download.php,以概述当前可用的发行版。
一些受欢迎的地方获得最新的VIM:
- 从Github查看GIT存储库。
- 将源代码作为存档。
- 从VIM-WIN32-Installer存储库中获取Windows可执行文件。
编译
如果您获得了二元分发,则无需编译VIM。如果您获得了源分布,则所有用于编译VIM的内容都在SRC目录中。有关说明,请参见SRC/安装。
安装
有关特定于系统的说明,请参见这些文件之一。在ReadMedir目录(在存储库中)或顶部目录中(如果打开存档):
README_ami.txt Amiga README_unix.txt Unix README_dos.txt MS-DOS and MS-Windows README_mac.txt Macintosh README_vms.txt VMS
根据您使用的分布,还有其他读数_*。txt文件。
文档
VIM导师是初学者一小时的培训课程。通常,它可以作为Vimtutor开始。请参阅:帮助导师以获取更多信息。
最好的是使用:在VIM中提供帮助。如果您还没有可执行文件,请读取运行时/doc/help.txt。它包含其他文档文件的指针。用户手册读起来像一本书,建议学习使用VIM。请参阅:帮助用户手册。
复制
VIM是慈善软件。您可以随意使用并复制它,但鼓励您捐款以帮助乌干达的孤儿。请阅读文件运行时/doc/uganda.txt以获取详细信息(DO:帮助乌干达内部的VIM)。
许可证的摘要:使用或分发未修改的VIM副本没有任何限制。 VIM的一部分也可以分发,但必须始终包括许可文本。对于修改版本,适用一些限制。该许可证兼容GPL,您可以将VIM与GPL库编译并分发。
赞助
修复错误并添加新功能需要大量时间和精力。要表示您对工作的赞赏,并激励Bram和其他人继续研究VIM,请发送捐款。
由于Bram又回到了有偿工作,因此资金现在将用于帮助乌干达的儿童。请参阅Runtime/doc/uganda.txt。但与此同时,捐赠增加了布拉姆继续在VIM上工作的动机!
有关VIM网站上有关赞助外观的最新信息:http://www.vim.org/sponsor/
贡献
如果您想帮助使VIM更好,请参阅contruting.md文件。
信息
有关VIM的最新消息可以在VIM主页上找到:http://www.vim.org/
如果有问题,请查看VIM文档或提示:http://www.vim.org/docs.php http://vim.**wik*ia.com/wiki/wiki/wiki/vim_tips_wiki
如果您仍然有问题或任何其他问题,请使用其中一个邮件列表与VIM用户和开发人员讨论:http://www.vim.org/maillist.php
如果没有其他作用,请直接报告错误:bram moolenaar bram@vim.org
主要作者
将任何其他评论,补丁,鲜花和建议发送到:bram moolenaar bram@vim.org
这是VIM:VI:VI改进的8.2版的Readme.md。
此读数的翻译
韩国人
