@chemzqm/neovim
Version:
NodeJS client API for vim8 and neovim
116 lines (115 loc) • 5.02 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const util = require("util");
const attach_1 = require("../attach");
const factory_1 = require("./factory");
const debug = util.debuglog('nvim-host');
class Host {
constructor() {
// Map for loaded plugins
this.loaded = {};
this.handler = this.handler.bind(this);
this.handlePlugin = this.handlePlugin.bind(this);
}
getPlugin(filename, options = {}) {
let plugin = this.loaded[filename];
const shouldUseCachedPlugin = plugin && plugin.shouldCacheModule && !plugin.alwaysInit;
if (shouldUseCachedPlugin) {
debug('getPlugin.useCachedPlugin');
return plugin;
}
plugin = factory_1.loadPlugin(filename, this.nvim, Object.assign({}, options, { cache: plugin && plugin.shouldCacheModule }));
this.loaded[filename] = plugin;
return plugin;
}
// Route incoming request to a plugin
handlePlugin(method, args) {
return __awaiter(this, void 0, void 0, function* () {
// ignore methods that start with nvim_ prefix (e.g. when attaching to buffer and listening for notifications)
if (method.startsWith('nvim_'))
return null;
debug(`host.handlePlugin: ${method}`);
// Parse method name
const procInfo = method.split(':');
if (process.platform === 'win32') {
// Windows-style absolute paths is formatted as [A-Z]:\path\to\file.
// Forward slash as path separator is ok
// so Neovim uses it to avoid escaping backslashes.
//
// For absolute path of cmd.exe with forward slash as path separator,
// method.split(':') returns ['C', '/Windows/System32/cmd.exe', ...].
// procInfo should be ['C:/Windows/System32/cmd.exe', ...].
const networkDrive = procInfo.shift();
procInfo[0] = `${networkDrive}:${procInfo[0]}`;
}
const filename = procInfo[0];
const type = procInfo[1];
const procName = `${procInfo.slice(2).join(' ')}`;
const plugin = this.getPlugin(filename);
if (!plugin) {
const msg = `Could not load plugin: ${filename}`;
debug(msg);
throw new Error(msg);
}
return plugin.handleRequest(procName, type, args);
});
}
handleRequestSpecs(method, args, res) {
const filename = args[0];
debug(`requested specs for ${filename}`);
// Can return null if there is nothing defined in plugin
const plugin = this.getPlugin(filename);
const specs = (plugin && plugin.specs) || [];
debug(JSON.stringify(specs));
res.send(specs);
debug(`specs: ${util.inspect(specs)}`);
}
handler(method, args, res) {
return __awaiter(this, void 0, void 0, function* () {
debug(`request received: ${method}`);
// 'poll' and 'specs' are requests by neovim,
// otherwise it will
if (method === 'poll') {
// Handshake for neovim
res.send('ok');
}
else if (method === 'specs') {
// Return plugin specs
this.handleRequestSpecs(method, args, res);
}
else {
try {
const plugResult = yield this.handlePlugin(method, args);
res.send(!plugResult || typeof plugResult === 'undefined' ? null : plugResult);
}
catch (err) {
res.send(err.toString(), true);
}
}
});
}
start({ proc }) {
return __awaiter(this, void 0, void 0, function* () {
debug('host.start');
// stdio is reversed since it's from the perspective of Neovim
const nvim = attach_1.attach({ reader: proc.stdin, writer: proc.stdout });
this.nvim = nvim;
if (nvim) {
nvim.on('request', this.handler);
nvim.on('notification', this.handlePlugin);
nvim.on('disconnect', () => {
debug('host.disconnected');
});
}
});
}
}
exports.Host = Host;