# vim-wasm
**Repository Path**: mirrors/vim-wasm
## Basic Information
- **Project Name**: vim-wasm
- **Description**: vim.wasm 是 Vim editor 的实验分支,该项目的目标是通过将 Vim C 源编译为 WebAssembly 来在浏览器上运行 Vim 编辑器
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: wasm
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 1
- **Created**: 2019-04-26
- **Last Updated**: 2026-01-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
vim.wasm: Vim Ported to WebAssembly
================================================================================
[![Build Status][travis-ci-badge]][travis-ci]
[![npm version][npm-badge]][npm-package]
This project is an experimental fork of [Vim editor][] by [@rhysd][] to compile
it into [WebAssembly][] using [emscripten][] and [binaryen][]. Vim runs on [Web Worker][]
and interacts with the main thread via [`SharedArrayBuffer`][shared-array-buffer].
The goal of this project is running Vim editor on browsers without losing Vim's powerful
functionalities by compiling Vim C sources into WebAssembly.
## [Try it with your browser][try it]
- **USAGE**
- Almost all Vim's powerful features (syntax highlighting, Vim script, text objects,
...) including the latest features (popup window, ...) are supported.
- Drag&Drop files to browser tab opens them in Vim.
- `:write` only writes file on memory. Download current buffer by `:export` or
specific file by `:export {file}`.
- Clipboard register `"*` is supported. For example, paste system clipboard text
to Vim with `"*p` or `:put *`, and copy text in Vim to system clipboard with
`"*y` or `:yank *`.
If you want to synchronize Vim's clipboard with system clipboard,
`:set clipboard=unnamed` should work like normal Vim.
- Files under `~/.vim` directory is persistently stored in [Indexed DB][idb].
Please write your favorite configuration in `~/.vim/vimrc` (NOT `~/.vimrc`).
- `file={filepath}={url}` fetches a file from `{url}` to `{filepath}`. Arbitrary
remote files can be opened (care about CORS).
- Default colorscheme is [onedark.vim][onedark], but [vim-monokai][monokai] is
also available as high-contrast colorscheme.
- `:!/path/to/file.js` evaluates the JavaScript code in browser. `:!%` evaluates
current buffer.
- vimtutor is available by `:e tutor`.
- Add `arg=` query parameters (e.g. `?arg=~%2f.vim%2fvimrc&arg=hello.txt`) to
add `vim` command line arguments.
- Please read [the usage documentation](./wasm/DEMO_USAGE.md) for more details.
- **NOTICE**
- Please access from desktop Chrome, Firefox, Safari or Chromium based browsers
since this project uses `SharedArrayBuffer` and `Atomics`. On Firefox or Safari,
feature flags (`javascript.options.shared_memory` for Firefox) must be enabled
for now.
- vim.wasm takes key inputs from DOM `keydown` event. Please disable your browser
extensions which intercept key events (incognito mode would be the best).
- This project is very early phase of experiment. You may notice soon on
trying it... it's buggy :)
- If inputting something does not change anything, please try to click somewhere
in the page. Vim may have lost the focus.
- Vim exits on `:quit`, but it does not close a browser tab. Please close it
manually :)
This project is packaged as [`vim-wasm` npm pacakge][npm-package] to be used in
web application easily. Please read [the documentation](./wasm/README.md) for
more details.
The current ported Vim version is 8.2.0055 with 'normal' and 'small' features sets.
Please check [changelog](./wasm/CHANGELOG.md) for update history.
### Related Projects
Following projects are related to this npm package and may be more suitable for your use case.
- [react-vim-wasm](https://github.com/rhysd/react-vim-wasm): [React](https://reactjs.org/)
component for vim.wasm. Vim editor can be embedded in your React web application.
- [vimwasm-try-plugin](https://github.com/rhysd/vimwasm-try-plugin): Command line tool
to open vim.wasm including specified Vim plugin instantly. You can try Vim plugin
without installing it!
- [vim.wasm.ipynb](https://github.com/nat-chan/vim.wasm.ipynb): Jupyter Notebook integration
with vim.wasm. [Try it online!](https://mybinder.org/v2/gh/nat-chan/vim.wasm.ipynb/gh-pages?filepath=vim.wasm.ipynb)
### Presentations and Blog Posts
- Presentation slides
- [(English) VimConf 2018 (Nov. 24th, 2018)](https://speakerdeck.com/rhysd/vim-ported-to-webassembly-vimconf-2018)
- [(Japanese) Emscripten&WebAssembly night!! #8 (Jul. 24th, 2019)](https://speakerdeck.com/rhysd/vim-compiled-to-webassembly)
- Japanese blog posts
[1](https://rhysd.hatenablog.com/entry/2018/07/09/090115)
[2](https://rhysd.hatenablog.com/entry/2019/06/13/090519)
## How It Works
### User Interaction

In worker thread, Vim is running by compiled into Wasm. The worker thread is spawned
as dedicated Web Worker from main thread when opening the page.
Let's say you input something with keyboard. Browser takes it as `KeyboardEvent` on
`keydown` event. JavaScript in main thread catches the event and store keydown
information to a shared memory buffer.
The buffer is shared with the worker thread. Vim waits and gets the keydown information
by polling the shared memory buffer via JavaScript's `Atomics` API. When key information
is found in the buffer, it loads the information and calculates key sequence. Via
JS to Wasm API thanks to emscripten, the sequence is added to Vim's input buffer
in Wasm.
The sequence in input buffer is processed by core editor logic (update buffer,
screen, ...). Due to the updates, some draw events happen such as draw text, draw
rects, scroll regions, ...
These draw events are sent to JavaScript in worker thread from Wasm thanks to emscripten's
JS to C API. Considering device pixel ratio and `` API, how to render the
events is calculated and these calculated rendering events are passed from worker thread
to main thread via message passing with `postMessage()`.
Main thread JavaScript receives and enqueues these rendering events. On animation
frame, it renders them to ``.
Finally you can see the rendered screen in the page.
### Build Process

WebAssembly frontend for Vim is implemented as a new GUI frontend of Vim like other GUI such as GTK frontend. C sources are
compiled to each LLVM bitcode files and then they are linked to one bitcode file
`vim.bc` by `emcc`. `emcc` will finally compile the `vim.bc` into `vim.wasm` binary
using binaryen and generates HTML/JavaScript runtime.
The difference I faced at first was the lack of terminal library such as ncurses.
I modified `configure` script to ignore the terminal library check. It's OK since
GUI frontend for Wasm is always used instead of CUI frontend. I needed many
workarounds to pass `configure` checks.
emscripten provides Unix-like environment. So `os_unix.c` can support Wasm. However,
some features are not supported by emscripten. I added many `#ifdef FEAT_GUI_WASM`
guards to disable features which cannot be supported by Wasm (i.e. `fork (2)`
support, PTY support, signal handlers are stubbed, ...etc).
I created `gui_wasm.c` heavily referencing `gui_mac.c` and `gui_w32.c`. Event loop
(`gui_mch_update()` and `gui_mch_wait_for_chars()`) is simply implemented with
blocking wait. And almost all UI rendering events are passed to JavaScript layer
by calling JavaScript functions from C thanks to emscripten.
C sources are compiled (with many optimizations) into LLVM bitcode with [Clang][]
which is integrated to emscripten. Then all bitcode files (`.o`) are linked to
one bitcode file `vim.bc` with `llvm-link` linker (also integrated to emscripten).
And I created JavaScript runtime in TypeScript to draw the rendering events sent
from C. JavaScript runtime is separated into two parts; main thread and worker
thread. `wasm/main.ts` is for main thread. It starts Vim in worker thread and
draws Vim screen to `