neovim

Neovim node.js 客户端

CI (node >= 14, Linux/macOS/Windows) 覆盖率 npm
ci Coverage Badge npm version

对于“远程插件”,Nvim Node.js 提供者 预期 neovim 包已全局安装

npm install -g neovim

或者,对于非插件用途,neovim 像任何其他 NPM 包一样工作。请参见下面的快速入门示例,您可以立即复制并运行。

neovim 包提供了以下函数

  • attach():主要接口。接受一个进程、套接字或一对写入/读取流,并返回连接到 nvim 进程的 NeovimClient
  • findNvim():尝试在当前系统上找到一个可用的 nvim 二进制文件。
  • 在加载时,neovim 模块用其 logger 接口替换(“猴子补丁”)console,因此 console.log 将调用 logger.info 而不是写入标准输出(这将破坏 stdio RPC 通道)。
    • 要跳过此对 console.log 的修补,请向 attach() 传递自定义 logger
    • 在任何情况下,最佳实践是使用 attach() 返回的 NeovimClient 中提供的 logger,而不是 console 日志记录函数。
  • $NVIM_NODE_LOG_FILE 环境变量设置为(也)将日志写入文件。
  • $ALLOW_CONSOLE 环境变量设置为(也)将日志写入标准输出。这将破坏任何(stdio)RPC 通道,因为写入标准输出的日志是无效的 RPC 消息。

以下是完整的可运行示例。

  1. 在任何目录中本地安装 neovim 包(即不使用 -g。如果脚本导入全局安装的包,Node 会抛出 ERR_MODULE_NOT_FOUND)。
    npm install neovim
    
  2. 将下面的脚本粘贴到 demo.mjs 文件中并运行它!
    ALLOW_CONSOLE=1 node demo.mjs
    
    • 必须设置 $ALLOW_CONSOLE 环境变量,因为日志通常不会打印到标准输出。
      • 注意:$ALLOW_CONSOLE 仅用于演示目的。它不能用于远程插件或任何时候 stdio 都是 RPC 通道的地方,因为将日志写入标准输出将破坏 RPC 通道。
    • 脚本
    import * as child_process from 'node:child_process'
    import * as assert from 'node:assert'
    import { attach, findNvim } from 'neovim'

    // Find `nvim` on the system and open a channel to it.
    (async function() {
    const found = findNvim({ orderBy: 'desc', minVersion: '0.9.0' })
    console.log(found);
    const nvim_proc = child_process.spawn(found.matches[0].path, ['--clean', '--embed'], {});
    const nvim = attach({ proc: nvim_proc });

    nvim.command('vsp | vsp | vsp');

    const windows = await nvim.windows;
    assert.deepStrictEqual(windows.length, 4);
    assert.ok(windows[0] instanceof nvim.Window);

    nvim.window = windows[2];
    const win = await nvim.window;
    assert.ok(win.id !== windows[0].id);
    assert.deepStrictEqual(win.id, windows[2].id);

    const buf = await nvim.buffer;
    assert.ok(buf instanceof nvim.Buffer);
    const lines = await buf.lines;
    assert.deepStrictEqual(lines, []);

    await buf.replace(['line1', 'line2'], 0);
    const newLines = await buf.lines;
    assert.deepStrictEqual(newLines, ['line1', 'line2']);

    if (nvim_proc.disconnect) {
    nvim_proc.disconnect();
    }
    nvim.quit();
    while (nvim_proc.exitCode === null) {
    await new Promise(resolve => setTimeout(resolve, 100))
    console.log('waiting for Nvim (pid %d) to exit', nvim_proc.pid);
    }
    console.log('Nvim exit code: %d', nvim_proc.exitCode);
    })();

Neovim 支持 远程插件,它们是作为 Nvim API 客户端实现的插件。此包包含“API 客户端”(与 nvim 交谈)和“远程插件主机”(发现并运行 Nvim node.js 远程插件)。

您可以在 Nvim 的 'runtimepath' 上的 rplugin/node/ 目录中定义一个远程插件作为文件或文件夹。如果插件是一个文件夹,则将加载 package.json 中的 main 脚本。

插件必须导出一个函数,该函数以 NvimPlugin 对象作为其唯一参数。然后,您可以通过调用 NvimPlugin 对象上的方法来注册自动命令、命令和函数。在此阶段避免进行繁重的初始化或异步函数,因为 Nvim 可能只在收集有关您的插件的信息,而不想实际使用它。相反,请等待您的自动命令、命令或函数之一被调用,然后再开始任何处理。

请参见 examples/ 以获取远程插件示例。

  NvimPlugin.nvim

这是您可以用来从插件发送命令到 nvim 的 nvim api 对象。

  NvimPlugin.setOptions(options: NvimPluginOptions);

interface NvimPluginOptions {
dev?: boolean;
alwaysInit?: boolean;
}

将您的插件设置为开发模式,这将导致模块在每次调用时重新加载。alwaysInit 将始终尝试尝试重新实例化插件。例如,您的插件类将在每次调用您的插件命令时始终被调用。

  NvimPlugin.registerAutocmd(name: string, fn: Function, options: AutocmdOptions): void;
NvimPlugin.registerAutocmd(name: string, fn: [any, Function], options: AutocmdOptions): void;

interface AutocmdOptions {
pattern: string; // See `:help autocmd-pattern`.
eval?: string; // Vimscript expression evaluated by the Nvim peer.
sync?: boolean; // Force blocking (non-async) behavior.
}

为事件 name 注册自动命令,使用 options 调用您的函数 fn。模式是唯一必需的选项。如果您希望调用对象上的方法,您可以将 fn 作为 [object, object.method] 的数组传递。

默认情况下,自动命令、命令和函数都被视为异步函数,应返回 Promises(或应为 async 函数)。

  NvimPlugin.registerCommand(name: string, fn: Function, options?: CommandOptions): void;
NvimPlugin.registerCommand(name: string, fn: [any, Function], options?: CommandOptions): void;

interface CommandOptions {
sync?: boolean; // Force blocking (non-async) behavior.
range?: string; // See `:help :range`.
nargs?: string; // See `:help :command-nargs`.
}

注册一个名为 name 的命令,使用 options 调用函数 fn。这将从 nvim 中通过在正常模式下输入 :name 来调用。

  NvimPlugin.registerFunction(name: string, fn: Function, options?: NvimFunctionOptions): void;
NvimPlugin.registerFunction(name: string, fn: [any, Function], options?: NvimFunctionOptions): void;

interface NvimFunctionOptions {
sync?: boolean; // Force blocking (non-async) behavior.
range?: string; // See `:help :range`.
eval?: string; // Vimscript expression evaluated by the Nvim peer.
}

注册一个名为 name 的函数,使用 options 调用函数 fn。这将从 nvim 中通过在正常模式下输入例如 :call name() 来调用。

为了调试和配置日志记录,您可以设置以下环境变量,这些环境变量由 neovim 包(或在注释中提到的 nvim 本身)使用

  • NVIM_NODE_HOST_DEBUG:使用 --inspect-brk 生成调用 neovim-client-host 的节点进程,以便您可以使用调试器。将其与这个 Node Inspector Manager Chrome 插件 配合使用
  • 日志记录:日志记录是通过 logger 模块使用 winston 完成的。此包将 console 替换为此接口。
    • NVIM_NODE_LOG_LEVEL:设置 winston 的日志级别。默认值为 debug。可用级别:{ error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }
    • NVIM_NODE_LOG_FILE:设置日志文件路径。
  • 通过 node REPL 使用
    • NVIM_LISTEN_ADDRESS:
      1. 使用已知地址启动 Nvim(或使用正在运行实例的 $NVIM_LISTEN_ADDRESS)
        $ NVIM_LISTEN_ADDRESS=/tmp/nvim nvim
        
      2. 在另一个终端中,将 node REPL 连接到 Nvim
        // `scripts/nvim` will detect if `NVIM_LISTEN_ADDRESS` is set and use that unix socket
        // Otherwise will create an embedded `nvim` instance
        require('neovim/scripts/nvim').then((nvim) => {
        nvim.command('vsp');
        });

请参见测试和 scripts 以获取更多示例。

克隆存储库后,运行 npm install 以安装开发依赖项。主 neovim 库位于 packages/neovim 中。

npm run build && NVIM_NODE_LOG_FILE=log npm run test

只有 neovim NPM 包 的维护者才能发布版本。请按照以下步骤发布版本

  1. 更新 CHANGELOG.md
  2. 更新版本。构建并发布包。标记版本并推送。
    # Choose major/minor/patch as needed.
    npm version --no-git-tag-version patch
    npm version -w packages/neovim/ patch
    git add package*.json packages/neovim/package.json
    git commit -m 'release'
    # Note: this copies the top-level README.md/CHANGELOG.md to packages/neovim/.
    npm run publish:neovim
    export _VERSION=$(grep -o 'version": "[^"]\+' packages/neovim/package.json | sed 's/.*"//')
    git tag "v${_VERSION}"
    git push --tags
    git push
  3. 发布后任务
    • CHANGELOG.md 中添加存根。
    • 提升并提交。
      npm version --no-git-tag-version prerelease --preid dev
      npm version -w packages/neovim/ --no-git-tag-version prerelease --preid dev
      git add package*.json packages/neovim/package.json
      git commit -m bump
      git push

文档网站目前未自动化。请按照以下步骤重新生成它

npm run doc -w packages/neovim
git checkout gh-pages
mv -f packages/neovim/doc/assets/* assets/
mv -f packages/neovim/doc/classes/* classes/
mv -f packages/neovim/doc/functions/* functions/
mv -f packages/neovim/doc/types/* types/
mv packages/neovim/doc/* .
rm -r packages/
git add *
git commit -m 'publish docs'
git push origin HEAD:gh-pages