npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

neovim-component

v0.10.1

Published

Polymer component for Neovim frontend

Downloads

38

Readme

<neovim-editor> Web Component

Build Status

This component provides <neovim-editor>, an HTML custom element built on Polymer and flux. It provides a frontend for the Neovim editor using Neovim's MessagePack API. It allows you to easily embed a Neovim-backed editor into your application.

This component assumes you have Node.js installed.

You can use this component for modern desktop application frameworks such as Electron or NW.js.
You can even use it in Electron-based editors such as Atom or VS Code.

This component is designed around the Flux architecture. You can access the UI event notifications and can call Neovim APIs directly via <neovim-editor>'s APIs.

You can install this component as an npm package.

$ npm install neovim-component

Current supported nvim version is v0.1.6 or later.

Examples

Each example only takes 100~300 lines.

Minimal Example

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <script src="/path/to/webcomponents-lite.min.js"></script>
    <link rel="import" href="/path/to/polymer.html" />
    <link rel="import" href="/path/to/neovim-editor.html" />
  </head>
  <body>
    <neovim-editor></neovim-editor>
  </body>
</html>

Minimal Electron app can be found in the example directory. This is a good start point to use this package and it shows how the component works.

main screenshot

How to run minimal example is:

$ git clone https://github.com/rhysd/neovim-component.git
$ cd neovim-component
$ npm start

Markdown Editor Example

For a more complicated and realistic example, see the markdown editor example. The markdown previewer is integrated with the Neovim GUI using the <neovim-editor> component.

markdown example screenshot

Image Popup Example

This is an image popup widget example here. The gi mapping is defined to show an image under the cursor in a tooltip.

image popup example screenshot

Mini Browser Example

This example shows how to include a mini web-browser using the <webview> tag from Electron.

mini browser example screenshot

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 provide a perfect way to add a GUI layer using HTML and CSS. NyaoVim is a GUI frontend as a proof of concept.

Architecture

data flow

<neovim-editor> 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.

<neovim-editor> Properties

You can customize <neovim-editor> 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 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" |

<neovim-editor> 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.

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.

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 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 which resolves to the returned value.

<neovim-component> uses promised-neovim-client package. You can see the all API definitions here. If you know further about Neovim APIs, python client implementation may be helpful.

const neovim_element = document.getElementById('neovim');
const client = neovim_element.editor.getClient();

// Send a command
client.command('vsplit');

// Send input
client.input('<C-w><C-l>');

// Evaluate a Vimscript 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.

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 <neovim-component> 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
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
const editor = document.getElementById('neovim').editor;
editor.screen.changeFontSize(18); // Change font size to 18px
  • Convert pixels to lines/cols.
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 <canvas> 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 need not care about resize event of <body> element. <neovim-editor> component automatically detects this particular resize event and updates automatically. screen.checkShouldResize() will simply be ignored if nothing has actually changed.

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 <neovim-element> if possible.

const editor = document.getElementById('neovim').editor;
editor.setArgv(['README.md']);
  • Focusing the editor

<neovim-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.

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

<neovim-component> 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 or CreateJS). #2
  • [ ] Follow dynamic device pixel ratio change. #18