Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion lua/skkelua/guard.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ end
-- insert モードでのみ通す
local completion_keys = key_set({ "<c-n>", "<c-p>" })

-- 補完 UI が feedkeys するキー (タイプ由来でなければ通す)。外部の補完 UI は
-- 入力を候補で置き換えるために noremap で <BS> を feedkeys することがある。
-- これは物理キーではなく、捨てると候補が pre-edit の後ろに追記されてしまう。
-- 置き換えでずれた pre-edit の追跡は、選択挿入と同じく既存の補完リカバリ
-- (prevInput 不一致リセット) が面倒を見る
local fed_keys = key_set({ "<bs>" })

-- pum 表示中の候補操作キー (cmdline の wildmenu も含む)
-- Note: <C-y> は skkelua 自身も feed する: [辞書登録] 項目の確定では
-- native_confirm_key が raw <C-y> を feedkeys し、しかも登録フローへ
Expand Down Expand Up @@ -141,11 +148,17 @@ end
--- 現れない (:lmap <expr> はその結果だけが、Lua コールバック
--- マッピングは KE_LUA 擬似キーが来る) ため、ここに生の
--- 特殊キーが来る = 未マップで素通りする直前ということ
---@param typed string マッピング適用前のキー。feedkeys などタイプ以外で
--- 生じたキーでは空になる
---@return string? "" を返すとそのキーは破棄される
function M._on_key(key, _)
function M._on_key(key, typed)
if not M._is_physical_special(key) and not M._is_hostile_control(key) then
return
end
-- マクロ再生もタイプ以外で生じるキーだが、ユーザー入力の再現なので守る
if typed == "" and vim.fn.reg_executing() == "" and fed_keys()[key] then
return
end
local store = require("skkelua.store")
if not store.status.enabled then
return
Expand Down
34 changes: 34 additions & 0 deletions tests/integration_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,40 @@ t.test("hostile control keys are discarded during pre-edit", function()
end)
end)

t.test("fed <BS> from a completion UI replaces the pre-edit", function()
with_buffer(function()
-- 外部の補完 UI は、入力を候補で置き換えるために noremap で <BS> と
-- 候補を feedkeys することがある。
-- 物理キーではないので guard は破棄しない
vim.keymap.set("i", "<C-t>", function()
local keys = vim.api.nvim_replace_termcodes("<BS><BS><BS><BS>漢字", true, true, true)
vim.api.nvim_feedkeys(keys, "in", false)
end, { buffer = true })
feed("iJKanji<C-t>")
t.assert_equals({ "漢字" }, vim.fn.getline(1, "$"))
end)
end)

t.test("<BS> reaching the guard unmapped is discarded unless fed", function()
local guard = require("skkelua.guard")
local bs = vim.api.nvim_replace_termcodes("<BS>", true, true, true)
with_buffer(function()
local results
vim.keymap.set("i", "<C-b>", function()
local reg_executing = vim.fn.reg_executing
vim.fn.reg_executing = function()
return "q"
end
local replayed = guard._on_key(bs, "")
vim.fn.reg_executing = reg_executing
results = { typed = guard._on_key(bs, bs), fed = guard._on_key(bs, ""), replayed = replayed }
end, { buffer = true })
feed("iJKanji<C-b>")
-- 物理キーとマクロ再生の <BS> は従来どおり破棄する
t.assert_equals({ typed = "", replayed = "" }, results)
end)
end)

t.test("<C-n> still navigates pum during pre-edit", function()
with_buffer(function()
vim.opt_local.completeopt = "menuone,noselect"
Expand Down
Loading