neovim/node-client

Name: node-client

Owner: Neovim

Description: Nvim Node.js client and plugin host

Created: 2015-02-11 14:23:57.0

Updated: 2018-05-24 12:30:16.0

Pushed: 2018-05-24 12:30:33.0

Homepage:

Size: 585

Language: TypeScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

neovim-client

| CI (Linux, macOS) | CI (Windows) | Coverage | npm | Gitter | |——————-|————–|———-|—–|——–| | Build Status Badge | Windows Build Status Badge | Coverage Badge | npm version | Gitter Badge |

Currently tested for node >= 8

Installation

Install the neovim package globally using npm.

install -g neovim
Usage

This package exports a single attach() function which takes a pair of write/read streams and invokes a callback with a Nvim API object.

attach
t cp = require('child_process');
t attach = require('neovim').attach;

t nvim_proc = cp.spawn('nvim', ['-u', 'NONE', '-N', '--embed'], {});

ttach to neovim process
nc function() {
nst nvim = await attach({ proc: nvim_proc });
im.command('vsp');
im.command('vsp');
im.command('vsp');
nst windows = await nvim.windows;

 expect(windows.length).toEqual(4);
 expect(windows[0] instanceof nvim.Window).toEqual(true);
 expect(windows[1] instanceof nvim.Window).toEqual(true);

im.window = windows[2];
nst win = await nvim.window;

 expect(win).not.toEqual(windows[0]);
 expect(win).toEqual(windows[2]);

nst buf = await nvim.buffer;
 expect(buf instanceof nvim.Buffer).toEqual(true);

nst lines = await buf.lines;
 expect(lines).toEqual(['']);

ait buf.replace(['line1', 'line2'], 0);
nst newLines = await buf.lines;
 expect(newLines).toEqual(['line1', 'line2']);

im.quit();
im_proc.disconnect();
;
Writing a Plugin

If you are a plugin developer, I'd love to hear your feedback on the plugin API.

A plugin can either be a file or folder in the rplugin/node directory. If the plugin is a folder, the main script from package.json will be loaded.

The plugin should export a function which takes a NvimPlugin object as it's only parameter. You may then register autocmds, commands and functions by calling methods on the NvimPlugin object. You should not do any heavy initialisation or start any async functions at this stage, as nvim may only be collecting information about your plugin without wishing to actually use it. You should wait for one of your autocmds, commands or functions to be called before starting any processing.

console has been replaced by a winston interface and console.log will call winston.info.

API (Work In Progress)
imPlugin.nvim

This is the nvim api object you can use to send commands from your plugin to vim.

imPlugin.setOptions(options: NvimPluginOptions);

terface NvimPluginOptions {
dev?: boolean;

Set your plugin to dev mode, which will cause the module to be reloaded on each invokation.

imPlugin.registerAutocmd(name: string, fn: Function, options: AutocmdOptions): void;
imPlugin.registerAutocmd(name: string, fn: [any, Function], options: AutocmdOptions): void;

terface AutocmdOptions {
pattern: string;
eval?: string;
sync?: boolean;

Registers an autocmd for the event name, calling your function fn with options. Pattern is the only required option. If you wish to call a method on an object you may pass fn as an array of [object, object.method].

By default autocmds, commands and functions are all treated as asynchronous and should return Promises (or should be async functions).

imPlugin.registerCommand(name: string, fn: Function, options?: CommandOptions): void;
imPlugin.registerCommand(name: string, fn: [any, Function], options?: CommandOptions): void;

terface CommandOptions {
sync?: boolean;
range?: string;
nargs?: string;

Registers a command named by name, calling function fn with options. This will be invoked from nvim by entering :name in normal mode.

imPlugin.registerFunction(name: string, fn: Function, options?: NvimFunctionOptions): void;
imPlugin.registerFunction(name: string, fn: [any, Function], options?: NvimFunctionOptions): void;

terface NvimFunctionOptions {
sync?: boolean;
range?: string;
eval?: string;

Registers a function with name name, calling function fn with options. This will be invoked from nvim by entering eg :call name() in normal mode.

Examples
Functional style
tion onBufWrite() {
nsole.log('Buffer written!');


le.exports = (plugin) => {
ugin.registerAutocmd('BufWritePre', onBufWrite, { pattern: '*' });

Class style
s MyPlugin {
nstructor(plugin) {
this.plugin = plugin;

plugin.registerCommand('SetMyLine', [this, this.setLine]);


tLine() {
this.plugin.nvim.setLine('A line, for your troubles');



le.exports = (plugin) => new MyPlugin(plugin);

r for convenience, exporting the class itself is equivalent to the above

le.exports = MyPlugin;
Prototype style
tion MyPlugin(plugin) {
is.plugin = plugin;
ugin.registerFunction('MyFunc', [this, MyPlugin.prototype.func]);


ugin.prototype.func = function() {
is.plugin.nvim.setLine('A line, for your troubles'); 


rt default MyPlugin;

r

rt default (plugin) => new MyPlugin(plugin);
Decorator style

The decorator api is still supported. The NvimPlugin object is passed as a second parameter in case you wish to dynamically register further commands in the constructor.

rt { Plugin, Function, Autocmd, Command } from 'neovim';

f `Plugin` decorator can be called with options
gin({ dev: true })
rt default class TestPlugin {
nstructor(nvim, plugin) {


unction('Vsplit', { sync: true })
litMe(args, done) {
this.nvim.command('vsplit');


ommand('LongCommand')
ync longCommand(args) {
console.log('Output will be routed to $NVIM_NODE_LOG_FILE');
const bufferName = await this.nvim.buffer.name;
return bufferName;


ommand('UsePromises')
omiseExample() {
return this.nvim.buffer.name.then((name) => {
  console.log(`Current buffer name is ${name}`);
});


Debugging / troubleshooting

Here are a few env vars you can set while starting neovim, that can help debugging and configuring logging:

NVIM_NODE_HOST_DEBUG

Will spawn the node process that calls neovim-client-host with --inspect-brk so you can have a debugger. Pair that with this Node Inspector Manager Chrome plugin

Logging

Logging is done using winston through the logger module. Plugins have console replaced with this interface.

NVIM_NODE_LOG_LEVEL

Sets the logging level for winston. Default is debug, available levels are { error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }

NVIM_NODE_LOG_FILE

Sets the log file path

Usage through node REPL
NVIM_LISTEN_ADDRESS

First, start Nvim with a known address (or use the $NVIM_LISTEN_ADDRESS of a running instance):

$ NVIM_LISTEN_ADDRESS=/tmp/nvim nvim In another terminal, connect a node REPL to Nvim

nvim;
scripts/nvim` will detect if `NVIM_LISTEN_ADDRESS` is set and use that unix socket
therwise will create an embedded `nvim` instance
ire('neovim/scripts/nvim').then((n) => nvim = n);

.command('vsp');

The tests and scripts can be consulted for more examples.

Contributors

This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.