nvim-treesitterに依存するプラグインのテストをnixでやる


nvim-tree-docsのfork版にテストを足したい。

fennelで書かれているが、これの挙動が確認できるテストがないのでluaに書き換えたときに同じ動作をする担保ができない。

辛うじてあるテストは以下のfennelだけだった。

(module example.main-test)

(deftest something-simple
  (t.= 1 1 "1 should equal 1, I hope!"))

#vustedをnixで動かしたい

luaのテストフレームワークにbustedがある。

これをnvimでラップしたものがvustedである。

ただし設定は.vustedではなく.bustedに書く。

これらはnixpkgsにあるのでnixでそのまま使える。

{
  description = "sample";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
    }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = import nixpkgs {
          inherit system;
        };
      in
      {
        devShells = {
          default = pkgs.mkShell {
            buildInputs = [
              pkgs.neovim
              pkgs.lua51Packages.vusted
            ];
          };
        };
      }
    );
}

これでvim.api...のようなnvimのAPIにアクセスする関数もテストが書ける。

ただ、nvim-tree-docsはnvim-treesitterに依存しているため、これにrtpを通したnvimを使わないといけない。

nvim-treesitter自体はnixpkgsにあるがperserなどをいいかんじにいれるのは大変らしい。

以下のようにいろいろやるとparserなどにrtpを通したnvimを使ってvustedを実行できる。

{
  description = "sample";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    neovim-nightly-overlay.url = "github:nix-community/neovim-nightly-overlay";
  };

  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
      neovim-nightly-overlay,
    }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [
            neovim-nightly-overlay.overlays.default
          ];
        };
        nvim-treesitter = (
          pkgs.symlinkJoin {
            name = "nvim-treesitter";
            paths = [
              pkgs.vimPlugins.nvim-treesitter
            ]
            ++ pkgs.vimPlugins.nvim-treesitter.withAllGrammars.dependencies;
          }
        );
        customInitVim = pkgs.stdenvNoCC.mkDerivation {
          name = "init-vim";
          src = ./.;
          buildCommand =
            let
              init-vim = ''
                set runtimepath+=${nvim-treesitter}
              '';
            in
            ''
              mkdir -p $out
              echo "${init-vim}" > $out/init.vim
            '';
        };
        wrappedVusted = pkgs.symlinkJoin {
          name = "vusted-custom";
          paths = [ pkgs.lua51Packages.vusted ];
          nativeBuildInputs = [ pkgs.makeWrapper ];
          postBuild = ''
            wrapProgram $out/bin/vusted \
              --set VUSTED_ARGS "--headless --clean -u ${customInitVim}/init.vim"
          '';
        };
      in
      {
        devShells = {
          default = pkgs.mkShel {
            buildInputs = [
              pkgs.neovim
              wrappedVusted
            ];
          };
        };
      }
    );
}

ちゃんと理解できていないのでもっと簡潔に書くこともできると思われる。

describe("typescript jsdoc", function()
  it("should generate typescript jsdoc", function()
    local bufnr = vim.api.nvim_create_buf(false, false)
    vim.api.nvim_set_current_buf(bufnr)
    vim.bo.filetype = "typescript"
    local contents = {
      "function sample(a: string, b: number): string {",
      "  return a + b;",
      "}",
    }
    vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, contents)
    vim.treesitter.get_parser(bufnr, "typescript"):parse()
    vim.api.nvim_win_set_cursor(0, { 1, 9 })

    require("nvim-tree-docs.internal").doc_node_at_cursor()

    assert.same({
      "/**",
      " * The sample description",
      " *",
      " * @param a - The a param",
      " * @param b - The b param",
      " * @returns The result",
      " */",
      "function sample(a: string, b: number): string {",
      "  return a + b;",
      "}",
    }, vim.api.nvim_buf_get_lines(bufnr, 0, -1, false))
  end)
end)
    vim.treesitter.get_parser(bufnr, "typescript"):parse()

これをテストの実行前にやっておく必要がある(vim.treesitter.start()でよい可能性)。

これで最低限のハーネスができたので、AIなどでガードレールを張った状態で暴走させられる。