UNPKG

@chemzqm/neovim

Version:

NodeJS client API for vim8 and neovim

116 lines (115 loc) 5.02 kB
"use strict"; 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;