node-client: Reduce complexity of the plugin API

I think API should be vanilla NodeJS friendly. Babel and friends don’t help developers at this point and using legacy decorators and other early features shouldn’t be recommended. Please keep the API simple.

I could write the plugins like this now without Babel configurations but decorators looks bad to be honest.

const { Plugin, Command } = require('neovim')

class TestPlugin {
	splitV() {
		this.nvim.command('vsplit')
	}
}

Command('Vsplit')(TestPlugin.prototype.splitV)

module.exports = Plugin({ dev: true })(TestPlugin)

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 1
  • Comments: 26 (17 by maintainers)

Commits related to this issue

Most upvoted comments

I don’t know if any work has been done on this, but I’ll offer another suggestion! My preference would be strongly against any global object being either injected or required.

Defining a plugin by exporting a single function which takes nvim as an argument would be ideal for testing via dependency injection etc. The functions to register commands could exist on the nvim object.

This would allow whatever programming style you prefer, functional or OO, eg:

function someCommand() {}
function someAutocmd() {}

class StatefulThing {
  aMethod() {}
}

class AnotherClass {
  constructor(nvim) {
    nvim.registerCommand('AnotherCommand', [this, this.anotherMethod]);
  }
  anotherMethod() {}
}

module.exports = (nvim) => {
  nvim.registerCommand('CommandName', someCommand, { option: true });
  nvim.registerAutocmd('BufWritePre', someAutocmd, { pattern: '*' });

  const stateful = new StatefulThing();
  nvim.registerCommand('AnotherCommand', [stateful, stateful.aMethod]);

  const anotherInstance = new AnotherClass(nvim);
};

I would also love an official way to listen for arbitrary events sent by rpcnotify. I’m currently hacking around this with the following:

@Plugin({ dev: true })
export default class ListenerPlugin {
  @Command('AddListener')
  async addListener() {
    this.nvim.command(`au CursorMoved * call rpcnotify(${this.nvim._channel_id}, '${PLUGIN_PATH}:command:Handler', 'Test')`);
  }

  @Command('Handler')
  async handler(...args) {
    console.log(args);
  }
}

It would be nice to have nvim.registerRPCHandler('EventName', fn) instead.

I’m happy to put in a PR for a different plugin API if it won’t be duplicating work.

I agree, I’ll explore a simpler API for creating plugins

Now that #54 is merged, how does this affect local testing such as https://github.com/neovim/neovim/blob/master/test/functional/provider/nodejs_spec.lua? I worked on this with @justinmk but I’m not satisfied with the global dependency of the neovim module because it leaks the abstraction of the nodejs host into the plugin. Is require('neovim') still required in the user plugin?