Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/rhysd/neovim-component
<neovim-editor> WebComponent to embed Neovim to your app with great ease
https://github.com/rhysd/neovim-component
electron neovim webcomponents
Last synced: 5 days ago
JSON representation
<neovim-editor> WebComponent to embed Neovim to your app with great ease
- Host: GitHub
- URL: https://github.com/rhysd/neovim-component
- Owner: rhysd
- License: mit
- Created: 2015-11-23T17:07:39.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2020-07-07T01:34:47.000Z (over 4 years ago)
- Last Synced: 2024-12-17T18:10:15.308Z (12 days ago)
- Topics: electron, neovim, webcomponents
- Language: TypeScript
- Homepage: https://github.com/rhysd/NyaoVim
- Size: 367 KB
- Stars: 194
- Watchers: 10
- Forks: 18
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
`` Web Component
===============================
[![Build Status](https://travis-ci.org/rhysd/neovim-component.svg?branch=master)](https://travis-ci.org/rhysd/neovim-component)This component provides ``, an HTML custom element built on [Polymer v2](https://github.com/Polymer/polymer)
and [flux](https://github.com/facebook/flux). It provides a frontend for the [Neovim editor](https://github.com/neovim/neovim)
using Neovim's MessagePack API. It allows you to easily embed a Neovim-backed editor into your application.**This component assumes to be used in Node.js environment. (i.e. Electron)**
You can use this component for modern desktop application frameworks such as [Electron](https://github.com/atom/electron)
or [NW.js](https://github.com/nwjs/nw.js). You can even use it in Electron-based editors such as [Atom](http://atom.io/)
or [VS Code](https://github.com/Microsoft/vscode).This component is designed around the [Flux architecture](https://facebook.github.io/flux/docs/overview.html).
You can access the UI event notifications and can call Neovim APIs directly via ``'s
APIs.You can install this component as an [npm package](https://www.npmjs.com/package/neovim-component).
```
$ npm install neovim-component
```Current supported `nvim` version is v0.1.6 or later.
## Examples
Each example only takes 100~300 lines.
### [Minimal Example](/example/minimal)
```html
```
Minimal [Electron](https://github.com/atom/electron) app can be found in the [example directory](/example/minimal).
This is a good start point to use this package and it shows how the component works.![main screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/main.gif)
How to run minimal example is:
```sh
$ git clone https://github.com/rhysd/neovim-component.git
$ cd neovim-component
$ npm start
```### [Markdown Editor Example](/example/markdown)
For a more complicated and realistic example, see the [markdown editor example](/example/markdown).
The markdown previewer is integrated with the Neovim GUI using the `` component.![markdown example screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/markdown-example.gif)
### [Image Popup Example](/example/image-popup)
This is an image popup widget example [here](/example/image-popup). The `gi` mapping is defined
to show an image under the cursor in a tooltip.![image popup example screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/popup-image-example.gif)
### [Mini Browser Example](/example/mini-browser)
This example shows how to include a mini web-browser using the
[`` tag from Electron](https://github.com/atom/electron/blob/master/docs/api/web-view-tag.md).![mini browser example screenshot](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/mini-browser.gif)
## Why Did You Create This?
Vim has very powerful editing features, but Vim is an editor (see `:help design-not`) and unfortunately
lacks support for many graphical tools that writers and programmers like. NyaoVim adds support for
graphical features without losing Vim's powerful text editing abilities.
[Neovim's msgpack APIs](https://neovim.io/doc/user/msgpack_rpc.html) provide a perfect way to add
a GUI layer using HTML and CSS. [NyaoVim](https://github.com/rhysd/NyaoVim) is a GUI frontend as
a proof of concept.## Architecture
![data flow](https://raw.githubusercontent.com/rhysd/ss/master/neovim-component/flow.png)
`` has an `editor` property to access the internal APIs of the component.
- `editor.screen` is a view of the component (using canvas). It receives user input and dispatches
input actions to the data store.
- `editor.process` is a process handler to interact with the backing Neovim process via msgpack-rpc
APIs. You can call Neovim's APIs via the Neovim client (`editor.getClient()` helper).
- `editor.store` is the state of this component. You can access the current state of the editor through
this object.## `` Properties
You can customize `` with the following properties:
| Name | Description | Default |
| ------------------- | -------------------------------------------| ------------- |
| `width` | Width of the editor in pixels. | `null` |
| `height` | Height of the editor in pixels. | `null` |
| `font` | Name of the editor's monospace font. | `"monospace"` |
| `font-size` | Font-size in pixels. | `12` |
| `line-height` | Line height rate relative to font size. | `1.3` |
| `nvim-cmd` | Command used to start Neovim. | `"nvim"` |
| `argv` | Arguments passed with the Neovim command. | `[]` |
| `on-quit` | Callback function to run when Neovim quits.| `null` |
| `on-error` | Callback function for Neovim errors. | `null` |
| `disable-alt-key` | Do not send alt key input to Neovim. | `false` |
| `disable-meta-key` | Do not send meta key input to Neovim. | `false` |
| `cursor-draw-delay` | Delay in millisec before drawing cursor. | `10` |
| `no-blink-cursor` | Blink cursor or not. | `false` |
| `window-title` | Specify first window title. | `"Neovim"` |## `` APIs
### Receive internal various events
You can receive various events (including UI redraw notifications) from the **store**.
The `store` is a part of flux architecture. It's a global instance of [EventEmitter](https://nodejs.org/api/events.html).You can also access the state of editor via the `store`. Note that all values are read only.
Do not change the values of the `store` directly, it will break the internal state of the component.```javascript
const neovim_element = document.getElementById('neovim');
const Store = neovim_element.editor.store;// Handle cursor movements
Store.on('cursor', () => console.log('Cursor is moved to ', Store.cursor));// Handle mode changes
Store.on('mode', () => console.log('Mode is changed to ', Store.mode));// Handle text redraws
Store.on('put', () => console.log('UI was redrawn'));// Accessing the state of the editor.
const bounds = [ Store.size.lines, Store.size.cols ];
const cursor_pos = [ Store.cursor.line, Store.cursor.col ];
```### Call Neovim APIs
You can call [Neovim APIs](https://neovim.io/doc/user/msgpack_rpc.html#msgpack-rpc-api) via the **client**.
When you call APIs via the client, it sends the call to the underlying Neovim process via MessagePack
RPC and will return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
which resolves to the returned value.`` uses [promised-neovim-client](https://github.com/rhysd/promised-neovim-client) package.
You can see the all API definitions [here](https://github.com/rhysd/promised-neovim-client/blob/promisified/index.d.ts).
If you know further about Neovim APIs, [python client implementation](https://github.com/neovim/python-client)
may be helpful.```javascript
const neovim_element = document.getElementById('neovim');
const client = neovim_element.editor.getClient();// Send a command
client.command('vsplit');// Send input
client.input('');// Evaluate a Vim script expression
client.eval('"aaa" . "bbb"').then(result => console.log(result));// Get the 'b:foo' variable
client.getCurrentBuffer()
.then(buf => buf.getVar('foo'))
.then(v => console.log(v));// Query something (windows, buffers, etc.)
// Move to the neighbor window and show its information.
client.getWindows()
.then(windows => client.secCurrentWindow(windows[1]))
.then(() => client.getCurrentWindow())
.then(win => console.log(win));// Receive an RPC request from Neovim
client.on('request', (n, args, res) => console.log(`Name: ${n}, Args: ${JSON.stringify(args)}, Response: ${res}`));
```### Editor lifecycle
You can receive notifications related to lifecycle of the editor.
```javascript
const neovim_element = document.getElementById('neovim');// Called when the Neovim background process attaches
neovim_element.editor.on('process-attached', () => console.log('Neovim process is ready'));// Called when the Neovim process is disconnected (usually by :quit)
neovim_element.editor.on('quit', () => console.log('Neovim process died'));// Called when the detaches
neovim_element.editor.on('detach', () => console.log('Element does not exist in DOM.'));// Called upon experiencing an error in the internal process
neovim_element.editor.on('error', err => alert(err.message));
```### View APIs
- Resize screen
```javascript
const editor = document.getElementById('neovim').editor;
editor.screen.resize(80, 100); // Resize screen to 80 lines and 100 columns
editor.screen.resizeWithPixels(1920, 1080); // Resize screen to 1920px x 1080px
```- Change font size
```javascript
const editor = document.getElementById('neovim').editor;
editor.screen.changeFontSize(18); // Change font size to 18px
```- Convert pixels to lines/cols.
```javascript
const editor = document.getElementById('neovim').editor;const loc = editor.screen.convertPositionToLocation(80, 24);
console.log(loc.x, loc.y); // Coordinates in pixels of (line, col) = (80, 24)const pos = editor.screen.convertLocationToPosition(400, 300);
const.log(pos.col, pos.line); // line/col of location (400px, 300px)
```- Notify of screen-size changes:
When some process has changed the screen-size **you must notify the `screen`**. The internal ``
element has a fixed size and must update itself if there are size changes. Call `screen.checkShouldResize()`
if the screen size may have changed. Note that you don't need to care about `resize` event of ``
element. `` component automatically detects this particular resize event and updates
automatically. `screen.checkShouldResize()` will simply be ignored if nothing has actually changed.```javascript
const editor = document.getElementById('neovim').editor;function showUpSomeElementInNeovim() {
const e = document.getElementById('some-elem');// New element shows up! The screen may be resized by the change.
// 'none' -> 'block'
e.style.display = 'block';// This call tells to editor to adjust itself in the case that it has been resized
editor.screen.checkShouldResize();
}
```### Other APIs
- Setting arguments afterwards:
If your app doesn't use Polymer you can set arguments afterwards using JavaScript
Note that it is better to use `argv` property of `` if possible.```javascript
const editor = document.getElementById('neovim').editor;
editor.setArgv(['README.md']);
```- Focusing the editor
`` is just a web-component, so it can be focused just like other elements.
If it loses focus the editor won't receive any input events.
The `editor` instance has a method to re-focus the editor in JavaScript.
The `store` instance contains the current focus state.```javascript
const editor = document.getElementById('neovim').editor;
console.log(editor.store.focused);
editor.store.on('focus-changed', () => {
console.log('Focus was changed: ' + editor.store.focused);
});// Refocus the editor to ensure it receives user input.
editor.focus();
```### Log Levels
`` prints logs in the browser console. The log level is controlled by the `NODE_ENV`
environment variable:- `NODE_ENV=debug` will log everything.
- `NODE_ENV=production` ignores all logs except for warnings and errors.
- Setting `NODE_ENV` to empty string or some other value enables logging for info, warnings, and errors.## TODOs
- [ ] WebGL rendering (using [pixi.js](http://www.pixijs.com/) or [CreateJS](http://www.createjs.com/)).
[#2](https://github.com/rhysd/neovim-component/issues/2)
- [ ] Follow dynamic device pixel ratio change. [#18](https://github.com/rhysd/neovim-component/issues/18)