The Issue

如果不是用到了一个叫 peek 的录屏软件,我可能没听过这个叫 vala 的语言,GNOME 搞出来的东西。

老灯日常用的 geary 邮件客户端和 peek 都是这个语言编写的。

老灯发现neovim 官方的 vala lang server 配置无法适用于 peek 这个项目。已经提交了 PR ( https://github.com/neovim/nvim-lspconfig/pull/789), 不过这个合并效率真是低,都两周了,还没动静,没给close 也没给merge.

neovim 官方的 vala lang server 配置甚至无法用于正常浏览 vala-language-server 的源码。

git clone https://github.com/benwaffle/vala-language-server
cd vala-language-server
nvim

然后我们在 neovim 中打开 src/server.vala,然后 neovim lsp 会在src目录下找到一个“假”的meson.build文件 (真正的 meson.build 文件在项目根目录下),根据 vala lang server 的逻辑,它会在这个“project root"(假的) 下面执行 meson build, 很明显这个命令会失败,因为这个不是真正的 meson.build 文件,而只是一个被根目录下的 meson.build 文件 包含进来的 include 文件 (姑且这么说吧,你 get 到意思就行)。然后 vala lang server 就报错了(实际上它输出的是 meson 的 stderr 错误信息):

ERROR: First statement must be a call to project

The Solution

根据 meson 的报错信息,我们知道,meson.build 文件的第一行有效指令一定是 a call to project.

这里老灯用的有效指令,其实主要是指排除comment. a call to project 即调用 project()

在官方没合并老灯的 PR 前,只能手动在配置那里hack了:

-- https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#vala_ls
local meson_matcher = function (path)
  local pattern = "meson.build"
  local f = vim.fn.glob(util.path.join(path, pattern))
  if f == '' then
    return nil
  end
  for line in io.lines(f) do
    -- skip meson comments
    if not line:match('^%s*#.*') then
      local str = line:gsub('%s+', '')
      if str ~= '' then
        if str:match('^project%(') then
          return path
        else
          break
        end
      end
    end
  end
end

lsp.vala_ls.setup({
  on_attach = mix_attach,
  capabilities = lsp_status.capabilities,
  cmd = {'vala-language-server'},
  root_dir = function (fname)
    local root = util.search_ancestors(fname, meson_matcher)
    return root or util.find_git_ancestor(fname)
  end,
})

ps: 关于上面配置里的 mix_attach 和 lsp_status 请参考老灯之前写的《 Neovim C Cpp Lsp Integration Tips

这里主要是告诉 neovim lsp, 要怎么确定这个 project root, 所谓的 project root, neovim lsp config 的逻辑是,

先找到项目的 meson.build 文件, 该文件所在目录,即project root,否则,就尝试找 git 仓库.

这里我们简单地给查找 meson.build 文件的方法 hack 了一下,跳过评论并且去除行两端的空格后,我们简单地判断此行是否以project(开头,即可过滤掉那些假的 meson.build 文件

其实 neovim lsp config 这个判断方法也只是针对大部分情况。但是老灯觉得,对于大部分情况已经 OK 了,毕竟,作为一个公共配置,它无法兼顾所有情况。

根据 GNOME 官方说明:meson 是 Vala 主要的构建系统。

Meson - a front end to the Ninja build system with Vala support (The main build system for Vala)

因此,只判断meson.build 文件,对于大部分 Vala 项目来说应该是 OK 的

Refs

https://github.com/benwaffle/vala-language-server

https://wiki.gnome.org/Projects/Vala/Tools

https://mesonbuild.com/Syntax.html#comments

https://github.com/phw/peek

https://gitlab.gnome.org/GNOME/geary

https://github.com/benwaffle/vala-language-server