在此给出一些 blink.cmp
的相关配置注意事项(以 blink.cmp v0.8.0
为例):
blink.cmp
对于候选词的过滤比较严格,需要将 rime-ls 的 long_filter_text
配置设置为 true
。
blink.cmp
将 LSP 服务器提供的 Text 类型补全也过滤掉了,为了启用 rime-ls,需要修改相关配置:
sources = {
-- ...
providers = {
lsp = {
transform_items = function(_, items)
-- the default transformer will do this
for _, item in ipairs(items) do
if item.kind == require('blink.cmp.types').CompletionItemKind.Snippet then
item.score_offset = item.score_offset - 3
end
end
-- you can define your own filter for rime item
return items
end
}
},
-- ...
},
你可以把 rime-ls 当成单纯的代码补全来用,也可以进行额外的配置让它更像普通的输入法。
这部分配置来自 Kaiser-Yang 的博客文章 使用 nvim-cmp + rime-ls 配置 nvim 中文输入法。
完整配置可以参考 Kaiser-Yang 的 dotfiles
先定义几个功能函数:
-- Check if item is acceptable, you can define rules by yourself
function rime_item_acceptable(item)
return
not contains_unacceptable_character(item.label)
or
item.label:match("%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d%")
end
-- Get the first n rime items' index in the completion list
function get_n_rime_item_index(n, items)
if items == nil then
items = require('blink.cmp.completion.list').items
end
local result = {}
if items == nil or #items == 0 then
return result
end
for i, item in ipairs(items) do
if is_rime_item(item) and rime_item_acceptable(item) then
result[#result + 1] = i
if #result == n then
break;
end
end
end
return result
end
相关 issue :用数字选词以后还需要一次空格才能上屏幕。
原理:添加回调函数,每次打开补全菜单时检查,满足特定条件直接上屏
Kaiser-Yang 提供的配置:当前输入最后一位是数字且 rime-ls 提供候选项唯一时上屏
-- if last char is number, and the only completion item is provided by rime-ls, accept it
require('blink.cmp.completion.list').show_emitter:on(function(event)
if not vim.g.rime_enabled then return end
local col = vim.fn.col('.') - 1
-- if you don't want use number to select, change the match pattern by yourself
if event.context.line:sub(col, col):match("%d") == nil then return end
local rime_item_index = get_n_rime_item_index(2, event.items)
if #rime_item_index ~= 1 then return end
require('blink.cmp').accept({ index = rime_item_index[1] })
end)
有可能导致误操作,根据实际需求修改判断条件
自定义 blink.cmp 的 keymap:
keymap = {
['<space>'] = {
function(cmp)
if not vim.g.rime_enabled then return false end
local rime_item_index = get_n_rime_item_index(1)
if #rime_item_index ~= 1 then return false end
-- If you want to select more than once,
-- just update this cmp.accept with vim.api.nvim_feedkeys('1', 'n', true)
-- The rest can be updated similarly
return cmp.accept({ index = rime_item_index[1] })
end,
'fallback' },
[';'] = {
-- FIX: can not work when binding ;<space> to other functionality
-- such inputting a Chinese punctuation
function(cmp)
if not vim.g.rime_enabled then return false end
local rime_item_index = get_n_rime_item_index(2)
if #rime_item_index ~= 2 then return false end
return cmp.accept({ index = rime_item_index[2] })
end, 'fallback' },
['\''] = {
function(cmp)
if not vim.g.rime_enabled then return false end
local rime_item_index = get_n_rime_item_index(3)
if #rime_item_index ~= 3 then return false end
return cmp.accept({ index = rime_item_index[3] })
end, 'fallback' }
}
确保 always_incomplete
为 true
,这样可以保证每次输入都会重新生成候选词。
require('lspconfig').rime_ls.setup {
init_options = {
-- ...
always_incomplete = true, -- 将 incomplete 永远设为 true,防止任何时候的过滤代替候选词重建
-- ...
},
on_attach = rime_on_attach,
capabilities = capabilities,
}
相关 issue :如何实现顶字上屏。
-- NOTE: there is no 'z' in the alphabet
local alphabet = "abcdefghijklmnopqrstuvwxy"
local max_code = 4
-- Select first entry when typing more than max_code
for i = 1, #alphabet do
local k = alphabet:sub(i, i)
vim.keymap.set({ 'i' }, k, function()
local cursor_column = vim.api.nvim_win_get_cursor(0)[2]
local confirmed = false
if vim.g.rime_enabled and cursor_column >= max_code then
local content_before_cursor = string.sub(vim.api.nvim_get_current_line(), 1, cursor_column)
local code = string.sub(content_before_cursor, cursor_column - max_code + 1, cursor_column)
if match_alphabet(code) then
-- This is for wubi users using 'z' as reverse look up
if not string.match(content_before_cursor, 'z[' .. alphabet .. ']*$') then
local first_rime_item_index = get_n_rime_item_index(1)
if #first_rime_item_index ~= 1 then
-- clear the wrong code
for _ = 1, max_code do
feedkeys('<bs>', 'n')
end
else
require('blink.cmp').accept({ index = first_rime_item_index[1] })
confirmed = true
end
end
end
end
if confirmed then
vim.schedule(function() feedkeys(k, 'n') end)
else
feedkeys(k, 'n')
end
end, opts())
end