neovim
Version:
Nvim msgpack API client and remote plugin provider
126 lines (125 loc) • 5.88 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Host = void 0;
const attach_1 = require("../attach/attach");
const factory_1 = require("./factory");
class Host {
constructor() {
// Map for loaded plugins
this.loaded = {};
this.handler = this.handler.bind(this);
this.handlePlugin = this.handlePlugin.bind(this);
}
getPlugin(filename, options = {}) {
var _a;
let plugin = this.loaded[filename];
const shouldUseCachedPlugin = plugin && plugin.shouldCacheModule && !plugin.alwaysInit;
if (shouldUseCachedPlugin) {
(_a = this.nvim) === null || _a === void 0 ? void 0 : _a.logger.debug('getPlugin.useCachedPlugin');
return plugin;
}
if (!this.nvim) {
throw Error();
}
plugin = (0, factory_1.loadPlugin)(filename, this.nvim, Object.assign(Object.assign({}, options), { cache: plugin && plugin.shouldCacheModule }));
this.nvim.logger.debug('getPlugin.alwaysInit', plugin && !plugin.alwaysInit);
if (plugin) {
this.loaded[filename] = plugin;
}
return plugin;
}
// Route incoming request to a plugin
handlePlugin(method, args) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
// ignore methods that start with nvim_ prefix (e.g. when attaching to buffer and listening for notifications)
if (method.startsWith('nvim_'))
return null;
(_a = this.nvim) === null || _a === void 0 ? void 0 : _a.logger.debug('host.handlePlugin: %s', 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}`;
(_b = this.nvim) === null || _b === void 0 ? void 0 : _b.logger.error(msg);
throw new Error(msg);
}
return plugin.handleRequest(procName, type, args);
});
}
handleRequestSpecs(_method, args, res) {
var _a, _b, _c;
const filename = args[0];
(_a = this.nvim) === null || _a === void 0 ? void 0 : _a.logger.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) || [];
(_b = this.nvim) === null || _b === void 0 ? void 0 : _b.logger.debug(JSON.stringify(specs));
res.send(specs);
(_c = this.nvim) === null || _c === void 0 ? void 0 : _c.logger.debug('specs: %O', specs);
}
handler(method, args, res) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
(_a = this.nvim) === null || _a === void 0 ? void 0 : _a.logger.debug('request received: %s', 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 (e) {
const err = e;
res.send(err.toString(), true);
}
}
});
}
start(_a) {
return __awaiter(this, arguments, void 0, function* ({ proc }) {
// stdio is reversed since it's from the perspective of Neovim
const nvim = (0, attach_1.attach)({ reader: proc.stdin, writer: proc.stdout });
this.nvim = nvim;
this.nvim.logger.debug('host.start');
nvim.on('request', this.handler);
nvim.on('notification', this.handlePlugin);
nvim.on('disconnect', () => {
var _a;
(_a = this.nvim) === null || _a === void 0 ? void 0 : _a.logger.debug('host.disconnected');
});
});
}
}
exports.Host = Host;