BigQuery の LSP でスキーマ補完を効かせる nvim-lspconfig


@dr666m1 さんが公開されている BigQuery(標準 SQL)の LSPnvim-lsp に設定して使わせていただいている(↓記事参照)のですが、なんと BigQuery からデータセットの情報を取得して補完に活用してくれる機能があります。今日は、これを試してみることにします。

https://zenn.dev/a24k/articles/a8b882019da106
https://zenn.dev/a24k/articles/20220325-nvim-lsp-bqls-only

以下、↑記事と同様の設定が済んでいる前提となります。

はじめに

最初の記事でも少し触れたのですが、当初私の環境ではこの機能が上手く動かず困っておりました。キャッシュファイルのタイムスタンプは更新されるのに、期待した中身が入ってこない。なんとなく見ているうちに、US リージョンのデータセットは取得できているが、東京リージョンのデータセットが取得できていないことに気付きました。

そこで、拙い英語で issue 立てて相談差し上げたところ、サクッと直していただけました。大変ありがとうございます。0.0.17 にマージされているので、それ以降であれば上手く動きそうです。

https://github.com/dr666m1/bq-extension-vscode/issues/38

nvim-lsp-installer にカスタムサーバーとして追加してあれば、:LspInstallInfou を押すだけでサクッと最新版にアップデートできますね。

bq/updateCache について

LSP に対して bq/updateCache と言うメソッドをリクエストをすると、LSP 側で bq コマンドや INFORMATION_SCHEMA へのクエリを実行して、プロジェクトやデータセットの情報を取得してくれます。INFORMATION_SCHEMA へのクエリは最小でも 10MB かかる決まりですが、編集中のクエリ内で使用しているデータセットに対してのみ情報取得が走る様なので安心です。

取得された情報は、~/.bq_extension_vscode/cache.sqlite と言うファイル(前述した 0.0.17 の修正により cache_00_00_17.sqlite と言うファイル名に変更になっています)に保存され、この情報を元に補完機能が動作する様です。便利。

bq/updateCache を実行するキーバインドの設定

もちろんコマンドで vim.lsp を直接たたけば実行できるのですが、まぁ面倒なのでキーバインドしておきましょう。データセットの状況にもよるとは思いますが、実行に多少時間がかかるので非同期で動く様にしておきます。こんなイメージ。

local lspInstaller = require("nvim-lsp-installer")

serverOnAttach['bqls'] = function (_, bufnr)
    local function nnoremap_silent_buffer(lhs, rhs)
        vim.api.nvim_buf_set_keymap(bufnr, 'n', lhs, rhs, { noremap=true, silent=true })
    end

    nnoremap_silent_buffer('gu', '<Cmd>lua print("LSP[bqls][Request] bq/updateCache") vim.lsp.buf_request(bufnr, "bq/updateCache", {}, function(_, res, _, _) print("LSP[bqls][Response]", res) end)<CR>')
    nnoremap_silent_buffer('gc', '<Cmd>lua print("LSP[bqls][Request] bq/clearCache") vim.lsp.buf_request(bufnr, "bq/clearCache", {}, function(_, res, _, _) print("LSP[bqls][Response]", res) end)<CR>')
end

lspInstaller.on_server_ready(function(server)
    local opts = {
        on_attach = on_attach,  -- e.g.
    }

    if serverOpts[server.name] then
        for k, v in pairs(serverOpts[server.name]) do opts[k] = v end
    end

    if serverOnAttach[server.name] then
        opts.on_attach = function (client, bufnr)
            on_attach(client, bufnr)
            serverOnAttach[server.name](client, bufnr)
        end
    end

    server:setup(opts)
    vim.cmd [[ do User LspAttachBuffers ]]
end)

保存したキャッシュをクリアする bq/clearCache と言うメソッドもあるので、一緒に設定しておきます。キーバインドは、お好みで。

おわりに

無事に補完も動く様になって、ますますクエリがはかどりそうです。BigQuery のコンソール開く時間が減りました。@dr666m1 さんに感謝です。