UNPKG

neovim

Version:

Nvim msgpack API client and remote plugin provider

718 lines (717 loc) 23.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Neovim = void 0; const Base_1 = require("./Base"); const createChainableApi_1 = require("./utils/createChainableApi"); const Buffer_1 = require("./Buffer"); const Tabpage_1 = require("./Tabpage"); const Window_1 = require("./Window"); /** * Neovim API */ class Neovim extends Base_1.BaseApi { constructor() { super(...arguments); this.prefix = 'nvim_'; this.Buffer = Buffer_1.Buffer; this.Window = Window_1.Window; this.Tabpage = Tabpage_1.Tabpage; } /** * Retrieves nvim API information */ get apiInfo() { return this.request(`${this.prefix}get_api_info`); } /** * Gets the current list of buffer handles * * Includes unlisted (unloaded/deleted) buffers, like `ls!`. Use `buffer.loaded` * to check if a buffer is loaded * * @return {Buffer[]} List of buffer handles */ get buffers() { return this.request(`${this.prefix}list_bufs`); } /** * Gets the current buffer * * @return {Buffer} Buffer handle */ get buffer() { return createChainableApi_1.createChainableApi.call(this, 'Buffer', Buffer_1.Buffer, () => this.request(`${this.prefix}get_current_buf`)); } /** * Sets the current buffer */ set buffer(buffer) { this.request(`${this.prefix}set_current_buf`, [buffer]); } /** * Get information about all open channels * * @return {Channel[]} Array of channels */ get chans() { return this.request(`${this.prefix}list_chans`); } /** * Gets information about a channel * * @param {Number} chan The channel number * @return {Channel} A channel */ getChanInfo(chan) { return this.request(`${this.prefix}get_chan_info`, [chan]); } /** * Gets a map of buffer-local |user-commands|. */ get commands() { return this.getCommands(); } /** * Gets a map of buffer-local |user-commands|. * * @param options Optional parameters (currently not used) * @return Map of maps describing commands */ getCommands(options = {}) { return this.request(`${this.prefix}get_commands`, [options]); } /** * Gets the current list of tabpage handles * * @return {Tabpage[]} List of tagpage handles */ get tabpages() { return this.request(`${this.prefix}list_tabpages`); } /** * Gets the window tabpage * * @return {Tabpage} Tagpage that contains the window */ get tabpage() { return createChainableApi_1.createChainableApi.call(this, 'Tabpage', Tabpage_1.Tabpage, () => this.request(`${this.prefix}get_current_tabpage`)); } /** * Sets the current tabpage */ set tabpage(tabpage) { this.request(`${this.prefix}set_current_tabpage`, [tabpage]); } /** * Gets the current list of window handles * * @return {Window[]} List of window handles */ get windows() { return this.getWindows(); } /** * Gets the current window * * @return Window handle */ get window() { return this.getWindow(); } /** * Sets the current window * * @param win Window handle */ set window(win) { if (win instanceof Window_1.Window) this.setWindow(win); else win.then(win => this.setWindow(win)); } /** * Gets the current list of window handles * * @return {Window[]} List of window handles */ getWindows() { return this.request(`${this.prefix}list_wins`); } /** * Gets the current window * * @return {Window} Window handle */ getWindow() { return createChainableApi_1.createChainableApi.call(this, 'Window', Window_1.Window, () => this.request(`${this.prefix}get_current_win`)); } /** * Sets the current window * * @param win Window handle */ setWindow(win) { // Throw error if win is not instance of Window? return this.request(`${this.prefix}set_current_win`, [win]); } /** * Gets the paths contained in "runtimepath" * * @return {String[]} List of paths */ get runtimePaths() { return this.request(`${this.prefix}list_runtime_paths`); } /** * Changes the global working directory * * @param dir Directory path * */ set dir(dir) { this.request(`${this.prefix}set_current_dir`, [dir]); } /** * Gets the current line * * @return {String} Current line string */ get line() { return this.getLine(); } /** * Sets current line * * @param {String} line Line contents */ set line(line) { // Doing this to satisfy TS requirement that get/setters have to be same type if (typeof line === 'string') { this.setLine(line); } } /** * Gets the current line * * @return {String} Current line string */ getLine() { return this.request(`${this.prefix}get_current_line`); } /** * Sets current line * * @param {String} line Line contents */ setLine(line) { return this.request(`${this.prefix}set_current_line`, [line]); } /** * Gets a list of global (non-buffer-local) |mapping| definitions. * * @param {String} mode Mode short-name ("n", "i", "v", ...) * @return {Object[]} Array of maparg()-like dictionaries describing mappings. The "buffer" key is always zero. */ getKeymap(mode) { return this.request(`${this.prefix}get_keymap`, [mode]); } /** * Gets the current mode. |mode()| "blocking" is true if Nvim is waiting for input. * * @return Mode info */ get mode() { return this.request(`${this.prefix}get_mode`); } /** * Gets map of defined colors * * @return Color map */ get colorMap() { return this.request(`${this.prefix}get_color_map`); } /** * Get color by name * * @param name Color name * @return Color value */ getColorByName(name) { return this.request(`${this.prefix}get_color_by_name`, [name]); } /** * Get highlight by name or id * * @param nameOrId Name or ID * @param isRgb Should export RGB colors * @return Highlight definition map */ getHighlight(nameOrId, isRgb = true) { const functionName = typeof nameOrId === 'string' ? 'by_name' : 'by_id'; return this.request(`${this.prefix}get_hl_${functionName}`, [nameOrId, isRgb]); } /** * Get highlight definition by name * * @param name Highlight group name * @param isRgb Should export RGB colors * @return Highlight definition map */ getHighlightByName(name, isRgb = true) { return this.request(`${this.prefix}get_hl_by_name`, [name, isRgb]); } /** * Get highlight definition by id |hlID()| * * @param id Highlight id as returned by |hlID()| * @param isRgb Should export RGB colors * @return Highlight definition map */ getHighlightById(id, isRgb = true) { return this.request(`${this.prefix}get_hl_by_id`, [id, isRgb]); } /** * Deletes the current line */ deleteCurrentLine() { return this.request(`${this.prefix}del_current_line`); } /** * Evaluates a VimL expression (:help expression). Dictionaries * and Lists are recursively expanded. On VimL error: Returns a * generic error; v:errmsg is not updated. * */ eval(expr) { return this.request(`${this.prefix}eval`, [expr]); } /** * Executes Lua code. */ lua(code, args = []) { const _args = Array.isArray(args) ? args : [args]; return this.request(`${this.prefix}execute_lua`, [code, _args]); } /** * Alias for `lua()` to be consistent with neovim API */ executeLua(code, args = []) { return this.lua(code, args); } /** * Calls a VimL |Dictionary-function| with the given arguments. * * On execution error: fails with VimL error, does not update v:errmsg. */ callDictFunction(dict, fname, args = []) { const _args = Array.isArray(args) ? args : [args]; return this.request(`${this.prefix}call_dict_function`, [dict, fname, _args]); } /** * Calls a VimL function with the given arguments. * * On execution error: fails with VimL error, does not update v:errmsg. */ call(fname, args = []) { const _args = Array.isArray(args) ? args : [args]; return this.request(`${this.prefix}call_function`, [fname, _args]); } /** * Alias for `call` */ callFunction(fname, args = []) { return this.call(fname, args); } /** * Calls many API methods atomically. * * This has two main usages: * - To perform several requests from an async context atomically, i.e. without * interleaving redraws, RPC requests from other clients, or user interactions * (however API methods may trigger autocommands or event processing which have * such side-effects, e.g. |:sleep| may wake timers) * * - To minimize RPC overhead (roundtrips) of a sequence of many requests. */ callAtomic(calls) { return this.request(`${this.prefix}call_atomic`, [calls]); } /** * Executes an ex-command. * * On execution error: fails with VimL error, does not update v:errmsg. * * @param {String} arg Ex-command string */ command(arg) { return this.request(`${this.prefix}command`, [arg]); } /** * Executes an ex-command and returns its (non-error) output. * Shell |:!| output is not captured. * * On execution error: fails with VimL error, does not update v:errmsg. */ commandOutput(arg) { return this.request(`${this.prefix}command_output`, [arg]); } /** * Gets a v: variable * * @param {String} name Variable name * @return {VimValue} Variable value */ getVvar(name) { return this.request(`${this.prefix}get_vvar`, [name]); } /** * Sets a v: variable, if it is not readonly. * * @param {String} name Variable name * @param {VimValue} value Variable value */ setVvar(name, value) { return this.request(`${this.prefix}set_vvar`, [name, value]); } /** * Sends input-keys to Nvim, subject to various quirks controlled * by `mode` flags. This is a blocking call, unlike |nvim_input()|. * * On execution error: does not fail, but updates v:errmsg. * * @param {String} keys To be typed * @param {String} mode Behavior flags, see |feedkeys()| * @param {Boolean} escapeCsi If true, escape K_SPECIAL/CSI bytes in `keys` */ feedKeys(keys, mode, escapeCsi) { return this.request(`${this.prefix}feedkeys`, [keys, mode, escapeCsi]); } /** * Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a * low-level input buffer and the call is non-blocking (input is * processed asynchronously by the eventloop). * * On execution error: does not fail, but updates v:errmsg. * * Note: * |keycodes| like <CR> are translated, so "<" is special. To * input a literal "<", send <LT>. * * Note: * For mouse events use |nvim_input_mouse()|. The pseudokey * form "<LeftMouse><col,row>" is deprecated since * |api-level| 6. * * @param {String} keys To be typed */ input(keys) { return this.request(`${this.prefix}input`, [keys]); } /** * Send mouse event from GUI. * * The call is non-blocking. It doesn't wait on any resulting * action, but queues the event to be processed soon by the event * loop. * * Note: * Currently this doesn't support "scripting" multiple mouse * events by calling it multiple times in a loop: the * intermediate mouse positions will be ignored. It should be * used to implement real-time mouse input in a GUI. The * deprecated pseudokey form ("<LeftMouse><col,row>") of * |nvim_input()| has the same limitiation. * * @param {String} button Mouse button: one of "left", "right", "middle", "wheel". * @param {String} action For ordinary buttons, one of "press", "drag", "release". * For the wheel, one of "up", "down", "left", "right". * @param {String} modifier String of modifiers each represented by a * single char. The same specifiers are used as * for a key press, except that the "-" separator * is optional, so "C-A-", "c-a" and "CA" can all * be used to specify Ctrl+Alt+click. * @param {Number} grid Grid number if the client uses |ui-multigrid|, else 0. * @param {Number} row Mouse row-position (zero-based, like redraw events) * @param {Number} col Mouse column-position (zero-based, like redraw events) */ inputMouse(button, action, modifier, grid, row, col) { return this.request(`${this.prefix}input_mouse`, [button, action, modifier, grid, row, col]); } /** * Parse a VimL Expression * * TODO: return type, see :help */ parseExpression(expr, flags, highlight) { return this.request(`${this.prefix}parse_expression`, [expr, flags, highlight]); } /** * Gets info describing process `pid`. * * @param {Number} pid pid * @return {Proc} Map of process properties, or null if process not found */ getProc(pid) { return this.request(`${this.prefix}get_proc`, [pid]); } /** * Gets the immediate children of process `pid` * * @return {Proc[]} Array of child process ids, empty if process not found */ getProcChildren(pid) { return this.request(`${this.prefix}get_proc_children`, [pid]); } /** * Replaces terminal codes and |keycodes| (<CR>, <Esc>, ...) in a * string with the internal representation. * * @param {String} str String to be converted. * @param {Boolean} fromPart Legacy Vim parameter. Usually true. * @param {Boolean} doIt Also translate <lt>. Ignored if `special` is false. * @param {Boolean} special Replace |keycodes|, e.g. <CR> becomes a "\n" char. */ replaceTermcodes(str, fromPart, doIt, special) { return this.request(`${this.prefix}replace_termcodes`, [str, fromPart, doIt, special]); } /** * Calculates the number of display cells occupied by `text`. * <Tab> counts as one cell. * * @param {String} str Some text * @return {Number} Number of cells */ strWidth(str) { return this.request(`${this.prefix}strwidth`, [str]); } /** Write to output buffer */ outWrite(str) { return this.request(`${this.prefix}out_write`, [str]); } outWriteLine(str) { return this.outWrite(`${str}\n`); } /** Write to error buffer */ errWrite(str) { return this.request(`${this.prefix}err_write`, [str]); } /** Write to error buffer */ errWriteLine(str) { return this.request(`${this.prefix}err_writeln`, [str]); } /** * Gets a list of dictionaries representing attached UIs. * * @return {Ui[]} Array of UI dictionaries * Each dictionary has the following keys: * "height" requested height of the UI * "width" requested width of the UI * "rgb" whether the UI uses rgb colors (false implies cterm colors) * "ext_..." Requested UI extensions, see |ui-options| * "chan" Channel id of remote UI (not present for TUI) */ get uis() { return this.request(`${this.prefix}list_uis`); } uiAttach(width, height, options) { return this.request(`${this.prefix}ui_attach`, [width, height, options]); } uiDetach() { return this.request(`${this.prefix}ui_detach`, []); } /** * TODO: Documentation * * @param {Number} width The new requested width * @param {Number} height The new requested height */ uiTryResize(width, height) { return this.request(`${this.prefix}ui_try_resize`, [width, height]); } /** * Tell Nvim to resize a grid. Triggers a grid_resize event with * the requested grid size or the maximum size if it exceeds size * limits. * * On invalid grid handle, fails with error. * * @param {Number} grid The handle of the grid to be changed * @param {Number} width The new requested width * @param {Number} height The new requested height */ uiTryResizeGrid(grid, width, height) { return this.request(`${this.prefix}ui_try_resize_grid`, [grid, width, height]); } /** * Set UI Option */ uiSetOption(name, value) { return this.request(`${this.prefix}ui_set_option`, [name, value]); } /** * Subscribe to nvim event broadcasts * * @param {String} event Event type string */ subscribe(event) { return this.request(`${this.prefix}subscribe`, [event]); } /** * Unsubscribe to nvim event broadcasts * * @param {String} event Event type string */ unsubscribe(event) { return this.request(`${this.prefix}unsubscribe`, [event]); } /** * Identify the client for nvim. Can be called more than once, * but subsequent calls will remove earlier info, which should be * resent if it is still valid. (This could happen if a library * first identifies the channel, and a plugin using that library * later overrides that info) * */ setClientInfo(name, version, type, methods, attributes) { this.request(`${this.prefix}set_client_info`, [name, version, type, methods, attributes]); } /** * Creates a new namespace, or gets an existing one. * * Namespaces are used for buffer highlights and virtual text, * see |nvim_buf_add_highlight()| and |nvim_buf_set_virtual_text()|. * * Namespaces can be named or anonymous. If `name` matches an * existing namespace, the associated id is returned. If `name` * is an empty string a new, anonymous namespace is created. * * @param name Namespace name or empty string * @return Namespace id */ createNamespace(name = '') { return this.request(`${this.prefix}create_namespace`, [name]); } /** * Alias for `getNamespaces()` */ get namespaces() { return this.getNamespaces(); } /** * Gets existing, non-anonymous namespaces. * * @return {Object} dict that maps from names to namespace ids. */ getNamespaces() { return this.request(`${this.prefix}get_namespaces`); } /** * Selects an item in the completion popupmenu. * * If |ins-completion| is not active this API call is silently * ignored. Useful for an external UI using |ui-popupmenu| to * control the popupmenu with the mouse. Can also be used in a * mapping; use <cmd> |:map-cmd| to ensure the mapping doesn't * end completion mode. * * @param {Number} item Index (zero-based) of the item to select. * Value of -1 selects nothing and restores the original text. * @param {Boolean} insert Whether the selection should be inserted in the buffer. * @param {Boolean} finish Finish the completion and dismiss the popupmenu. * Implies `insert`. * @param {Object} opts Optional parameters. Reserved for future use. */ selectPopupmenuItem(item, insert, finish, opts = {}) { return this.request(`${this.prefix}select_popupmenu_item`, [item, insert, finish, opts]); } /** * Creates a new, empty, unnamed buffer. * * @param {Boolean} listed Controls 'buflisted' * @param {Boolean} scratch Creates a "throwaway" |scratch-buffer| for temporary work (always 'nomodified') * @return {Buffer|Number} Buffer handle, or 0 on error */ createBuf(listed, scratch) { return this.request(`${this.prefix}create_buf`, [listed, scratch]); } /** * Public alias for `createBuf` */ createBuffer(listed, scratch) { return this.createBuf(listed, scratch); } /** * Open a new window. * Currently this is used to open floating and external windows. * Floats are windows that are drawn above the split layout, at * some anchor position in some other window. Floats can be draw * internally or by external GUI with the |ui-multigrid| * extension. External windows are only supported with multigrid * GUIs, and are displayed as separate top-level windows. * * Exactly one of `external` and `relative` must be specified. * * @param {Buffer} buffer Handle of buffer to be displayed in the window * @param {Boolean} enter Whether the window should be entered (made the current window) * @Param {Object} options Options object * @return {Window|Number} The Window handle or 0 when error */ openWin(buffer, enter, options) { return this.request(`${this.prefix}open_win`, [buffer, enter, options]); } /** * Public alias for `openWin` */ openWindow(buffer, enter, options) { return this.openWin(buffer, enter, options); } /** * Configure window position. Currently this is only used to * configure floating and external windows (including changing a * split window to these types). * * See documentation at |nvim_open_win()|, for the meaning of * parameters. Pass in -1 for 'witdh' and 'height' to keep * exiting size. * * When reconfiguring a floating window, absent option keys will * not be changed. The following restriction apply: `row`, `col` * and `relative` must be reconfigured together. Only changing a * subset of these is an error. * * @param window Window handle * @param options height, width of window (in character cells) * @Param Options object */ winConfig(window, options = {}) { return window.config(options); } /** * Public Alias for `winConfig` */ windowConfig(window, options = {}) { return this.winConfig(window, options); } /** * Closes window * * @param {Boolean} force Force close window */ winClose(window, force) { return window.close(force); } /** * Public alias for `winClose` */ windowClose(window, force) { return this.winClose(window, force); } /** * Quit nvim */ quit() { this.command('qa!'); } } exports.Neovim = Neovim;