開発中、プログラム中の文字列をこまめに切り替えたい(トグルしたい)ことがあります。たとえば

falsetrue にする、あるいはその逆を行うケースが考えられます。 特定のフラグや設定値を変えてビルドし直して、再度値を変えてビルドし直して…というステップは開発においてよくあることです。 特定の文字列を1手で切り替えたいとき、dial.nvim というプラグインが役に立ちます。

https://github.com/monaqa/dial.nvim

dial.nvim は Neovim の / を様々な用途に利用できるよう拡張するプラグインです。 ノーマルモードにおけるデフォルトの / は数値やアルファベットの増減のみ行いますが、 dial.nvim を入れると日付や真偽値 (true / false) の切り替えも行えるようになります。

キーマップの設定方法などの説明は README に譲りますが、たとえば上の例であれば

local augend = require("dial.augend")

require("dial.config").augends:register_group {
    default = {
        augend.constant.new {
            elements = { "true", "false" },
        },
        
    },
}

という設定をいれることで true / false のトグルが可能となります。

さて、ここからが本題です。次のようなケースではどうでしょうか。

local completion_plugin = "cmp" 
local os = "windows" 

completion_plugin"cmp" または "blink" のいずれかであると分かっている、os"windows", "macos", "linux" のいずれかであると分かっているようなケースです。

もちろん予め設定ファイルにてそれらの文字列を切り替えるようなルールを書いておくこともできますが、こういった specific な文字列をいちいち定義するのは手間です。バッファ上に記された switch: cmp, blink のような形式のヒントを読み取り、cmpblink / で切り替えられるようにできないでしょうか。

dial.nvim でこれを直接的に(=簡潔な設定のみで)サポートする方法は現状ありませんが、ユーザ側で頑張って設定を書くことでやりたいことが実現できます。

local augend = require("dial.augend")


elements = {}


local function inline_constant_find(line, cursor)
    
    local pattern = "switch: (.+)$"
    local match = line:match(pattern)
    if not match then
        return
    end
    elements = {}
    for option in match:gmatch "([^,]+)" do
        table.insert(elements, option:match "^%s*(.-)%s*$")
    end

    
    local vim_regex_ptn = ([[V(%s)]]):format(table.concat(elements, [[|]]))
    return require("dial.augend.common").find_pattern_regex(vim_regex_ptn, false)(line, cursor)
end






local function inline_constant_add(text, addend, cursor)
    local n_patterns = #elements
    local n = 1
    for i, elem in ipairs(elements) do
        if text == elem then
            n = i
        end
    end
    n = (n + addend - 1) % n_patterns + 1
    text = elements[n]
    cursor = #text
    return { text = text, cursor = cursor }
end

require("dial.config").augends:register_group {
    default = {
        
        augend.user.new {
            find = inline_constant_find,
            add = inline_constant_add,
        },
        
    },
}

augend.user はユーザ定義された関数を用いて増減ルールを指定できる機能であり、使いこなせば複雑な増減操作が可能となります。 上で書いた例では、カーソル行が switch: xxx,yyy,zzz のような形式で終了している場合、 {"xxx", "yyy", "zzz"} をトグル文字列の候補とします。 検索パターンを工夫すれば TypeScript や Python の型ヒントなど、別の記法にも対応できます。

文字列を動的にトグルするためには、トグル可能な文字列の候補を取得する必要があります。 現在はカーソル行から正規表現によるパターンマッチで取得しているため、異なるパターンで記述したり、改行を挟んだりするだけで使えなくなります。 「その文字列リテラルに入りうるパターン」を言語サーバから取得できる言語(TypeScript など)であれば 言語サーバからその情報を取得して用いるのが最も賢い方法ですが、まだ実現はできていません。

dial.nvim は作者自身も愛用しているものの、issue などで作者自身が思いもよらなかったユースケースに気付かされることが時折あります。 以前見かけた例としては、Tailwind CSS のクラス名を増減できるようにしている人がいました (bg-red-50bg-red-100bg-red-200 → … のような感じ)。 作者の発想を超えたところで活躍しているのを見るとなんだか嬉しいものですね。

dial.nvim は工夫次第で色々なことができるので、ぜひいろいろ試してみてください。

フラッグシティパートナーズ海外不動産投資セミナー 【DMM FX】入金

Source link