|
1 | 1 | -- Minimal init for headless tests / CI. |
2 | | --- Clones nvim-treesitter into a temp dir (if not already present), installs the |
3 | | --- yaml parser, and puts this plugin on the runtimepath. |
| 2 | +-- |
| 3 | +-- The plugin only needs the `yaml` treesitter parser available as |
| 4 | +-- `parser/yaml.so` on the runtimepath -- it uses the core `vim.treesitter` API |
| 5 | +-- directly, not nvim-treesitter modules. So instead of depending on |
| 6 | +-- nvim-treesitter's installer (which is brittle in CI), we compile the |
| 7 | +-- tree-sitter-yaml grammar from source into <deps>/parser/yaml.so. |
| 8 | + |
| 9 | +local uv = vim.uv or vim.loop |
4 | 10 |
|
5 | 11 | local function root(suffix) |
6 | 12 | local plugin_dir = vim.fn.fnamemodify(debug.getinfo(1, "S").source:sub(2), ":h:h") |
7 | 13 | return plugin_dir .. (suffix or "") |
8 | 14 | end |
9 | 15 |
|
| 16 | +local function exists(path) |
| 17 | + return uv.fs_stat(path) ~= nil |
| 18 | +end |
| 19 | + |
| 20 | +local function run(cmd) |
| 21 | + local obj = vim.system(cmd, { text = true }):wait() |
| 22 | + if obj.code ~= 0 then |
| 23 | + io.stderr:write(("command failed (%d): %s\n%s\n"):format(obj.code, table.concat(cmd, " "), obj.stderr or "")) |
| 24 | + end |
| 25 | + return obj.code == 0 |
| 26 | +end |
| 27 | + |
10 | 28 | -- Where to keep test dependencies. |
11 | 29 | local deps = os.getenv("OPENAPI_TEST_DEPS") or (vim.fn.stdpath("data") .. "/openapi-test-deps") |
12 | | -vim.fn.mkdir(deps, "p") |
13 | | - |
14 | | --- Use the stable `master` branch: it ships the classic synchronous parser |
15 | | --- installer (`:TSInstallSync`). The plugin itself only needs the `yaml` parser |
16 | | --- on the runtimepath -- it uses the core `vim.treesitter` API, not nvim-treesitter |
17 | | --- modules -- so the branch choice only affects how we obtain that parser in CI. |
18 | | -local treesitter = deps .. "/nvim-treesitter" |
19 | | -if vim.fn.isdirectory(treesitter) == 0 then |
20 | | - vim.fn.system({ |
21 | | - "git", |
22 | | - "clone", |
23 | | - "--branch", |
24 | | - "master", |
25 | | - "--filter=blob:none", |
26 | | - "https://github.com/nvim-treesitter/nvim-treesitter", |
27 | | - treesitter, |
28 | | - }) |
29 | | -end |
| 30 | +vim.fn.mkdir(deps .. "/parser", "p") |
30 | 31 |
|
31 | | --- Put deps and this plugin on the runtimepath. |
32 | | -vim.opt.runtimepath:prepend(treesitter) |
33 | | -vim.opt.runtimepath:prepend(root()) |
| 32 | +local parser_so = deps .. "/parser/yaml.so" |
| 33 | + |
| 34 | +if not exists(parser_so) then |
| 35 | + local src = deps .. "/tree-sitter-yaml" |
| 36 | + if not exists(src) then |
| 37 | + if |
| 38 | + not run({ |
| 39 | + "git", |
| 40 | + "clone", |
| 41 | + "--depth", |
| 42 | + "1", |
| 43 | + "https://github.com/tree-sitter-grammars/tree-sitter-yaml", |
| 44 | + src, |
| 45 | + }) |
| 46 | + then |
| 47 | + io.stderr:write("FATAL: failed to clone tree-sitter-yaml\n") |
| 48 | + vim.cmd("cquit 1") |
| 49 | + end |
| 50 | + end |
| 51 | + |
| 52 | + -- tree-sitter-yaml ships a C parser and a C scanner (the scanner pulls in the |
| 53 | + -- default `schema.core.c` itself via an #include), so everything is plain C. |
| 54 | + local cc = os.getenv("CC") or "cc" |
| 55 | + local srcdir = src .. "/src" |
34 | 56 |
|
35 | | --- Install the yaml parser if missing. |
36 | | -if pcall(require, "nvim-treesitter.configs") then |
37 | | - pcall(vim.cmd, "TSInstallSync! yaml") |
| 57 | + local ok = run({ cc, "-c", "-fPIC", "-I", srcdir, srcdir .. "/scanner.c", "-o", deps .. "/scanner.o" }) |
| 58 | + ok = ok and run({ cc, "-c", "-fPIC", "-I", srcdir, srcdir .. "/parser.c", "-o", deps .. "/parser.o" }) |
| 59 | + ok = ok |
| 60 | + and run({ |
| 61 | + cc, |
| 62 | + "-shared", |
| 63 | + "-fPIC", |
| 64 | + deps .. "/parser.o", |
| 65 | + deps .. "/scanner.o", |
| 66 | + "-o", |
| 67 | + parser_so, |
| 68 | + }) |
| 69 | + |
| 70 | + if not ok or not exists(parser_so) then |
| 71 | + io.stderr:write("FATAL: failed to build the yaml treesitter parser\n") |
| 72 | + vim.cmd("cquit 1") |
| 73 | + end |
38 | 74 | end |
39 | 75 |
|
40 | | --- Fail loudly if the yaml parser still isn't available, so CI surfaces the |
41 | | --- real cause instead of the smoke test silently doing nothing. |
| 76 | +-- Put the compiled parser and this plugin on the runtimepath. |
| 77 | +vim.opt.runtimepath:prepend(deps) |
| 78 | +vim.opt.runtimepath:prepend(root()) |
| 79 | + |
| 80 | +-- Sanity check: the yaml parser must load. |
42 | 81 | if not pcall(vim.treesitter.language.add, "yaml") then |
43 | 82 | io.stderr:write("FATAL: yaml treesitter parser is not available\n") |
44 | 83 | vim.cmd("cquit 1") |
|
0 commit comments