neovim
Version:
Nvim msgpack API client and remote plugin provider
718 lines (717 loc) • 23.3 kB
JavaScript
"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;