## 事象 [[nvim-cmp]]にて[[LuaSnip]]の `expand_or_jump` コマンドを登録している。 ```lua config = function() local cmp = require("cmp") local luasnip = require("luasnip") require("luasnip.loaders.from_snipmate").lazy_load() cmp.setup({ -- 中略 mapping = cmp.mapping.preset.insert({ ["<Tab>"] = cmp.mapping(function(fallback) if luasnip.expand_or_jumpable() then luasnip.expand_or_jump() else fallback() end end, { "i", "s" }), ``` `markdown.snippets` で登録された以下のスニペットに対し ```lua snippet _ - [ ] ${1} ``` 以下のように、スニペット挿入し、移動して、[[挿入モード]]に入り、`<Tab>` を押すと、`${1}` の場所に飛んでしまう。 ![[2024-12-30-15-57-40.webm]] ## 原因 ### `expand_or_jumpable` を使って かつ `${1}` にしているから `expand_or_jumpable` は、今もプレイスホルダーを順に移動するべきかを確認するコマンド。`${1}` は `<Tab>` 移動時の位置を示すindexであり、`${0}` に到達するまでの間は上記は `true` と見なされる。 `${0}` が明示的に指定されていない場合は、スニペットの最後が `${0}` とみなされるので、一度は `<Tab>` を押さなければ `expand_or_jumpable` は `false` にならない。 ## 解決方法 `expand_or_locally_jumpable` を使う。このコマンドは **カーソル位置がスニペットの外に出ている場合は `false` を返す** ので、関係ないところで `<Tab>` を押したときに予期せぬ移動が発生するリスクは軽減される。 ```diff mapping = cmp.mapping.preset.insert({ ["<Tab>"] = cmp.mapping(function(fallback) - if luasnip.expand_or_jumpable() then + if luasnip.expand_or_locally_jumpable() then luasnip.expand_or_jump() else fallback() end end, { "i", "s" }), ``` あわせて、`<Tab>` による移動が不要な場合は `${1}` ではなく `${0}` を指定するようにしたほうがよい。 ```lua snippet _ - [ ] ${0} ``` プレースホルダーが複数存在する場合も、最後に `${0}` を入れておいたほうが安全。 ```lua snippet _ - [ ] [${1}](${0:URL}) ``` ## 参考 - [LuaSnip/DOC\.md at master · L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip/blob/master/DOC.md#api-2)