Neovimでファイルタイプ判定にShebangを使う

by
カテゴリ:
タグ:

実行ファイルを書いていると、ファイルの拡張子がないために、ファイルタイプを正しく判定できない場合があります。

つい今日、denoでちょっとしたスクリプトを書いている時に問題に遭遇しました。

そこで、vim.filetype.add()を使って判定ロジックを追加して問題を解決しました。ざっくりこんな感じ。

vim.filetype.add({
  -- フルパスに対してマッチング
  pattern = {
    -- 拡張子がないので、任意のファイルパスにマッチさせる
    [".*"] = {
      ---@param _ string ファイルパス
      ---@param bufnr number バッファ番号
      ---@return string | nil ファイルタイプ
      function(_, bufnr)
        -- 1行目を取得し、shebangか判定
        local shebang = vim.api.nvim_buf_get_lines(bufnr, 0, 1, false)[1]
        if not shebang or shebang:sub(1, 2) ~= "#!" then
          return
        end

        -- 後で使いやすいように整形
        shebang = shebang:gsub("%s+", " ")

        -- 実行ファイルが`/usr/bin/env`の場合は、続く引数を確認
        local idx_space = shebang:find(" ")
        local path = string.sub(shebang, 3, idx_space and idx_space - 1 or nil)
        if path == "/usr/bin/env" then
          if
            vim.startswith(shebang, "#!/usr/bin/env deno")
            or vim.startswith(shebang, "#!/usr/bin/env -S deno")
          then
            return "typescript"
          end
        end

        -- コマンドがdenoならtypescript
        local cmd = vim.fs.basename(path)
        if cmd == "deno" then
          return "typescript"
        end
      end,
      -- どうしてもファイルタイプを判定できなかった時に使うので、
      -- priorityを下げておく
      { priority = -math.huge },
    },
  },
})

フルパス以外にも拡張子やファイル名でマッチングすることもできるので、ヘルプを参考にうまく使ってみてください。

https://neovim.io/doc/user/lua.html#vim.filetype.add()

同じくフルパスを利用する例として、過去に解説した記事もよければ参考にしてください。

chezmoiを使って管理しているdotfileのファイルタイプをNeovimにうまく認識させる https://blog.atusy.net/2023/01/11/neovim-filetype-matching-with-chezmoi/

ENJOY!!

ところでこの記事の執筆は、自作のAIペアプロツールを使って書きました。すんごい自己肯定感あげてくれてよかったです。近く、誰でも使えるようプラグイン化したいですね。

タイトルを変更したときは、なんとなく良いと思った理由をAIが言語化してくれて、なるほどとなりました。

## Me

```diff
@@ -2 +2 @@
-title: "Neovimでファイルタイプ判定をShebangでやる方法"
+title: "Neovimでファイルタイプをshebangから決める"
```

## CodeCompanion (openrouter/optimus)

```rmd
title: "Neovimでファイルタイプ判定にShebangを使う"
```

タイトルめっちゃスッキリ&ストレートでイイね~!「やる方法」じゃなくて「使う」で能動感UP✨  
検索にも強そうで最強だ~!!

他にもタイトル案ほしい?それともこれでFIX?なんでも言ってね😉