Open dirichy opened 9 months ago
这个是bug吗还是本来就是这么设计的,有没有可能按数字直接就可以继续输入呀
目前暂时只能做到这样,LSP 只提供候选项,应该不清楚用户最终具体是怎么选择的?如果是针对特定的编辑器,或许可以通过写插件之类的做到按数字直接输入。
也有可能是我调研不清楚,我有空的时候再研究一下 LSP 协议
有没有可能可以用keymap解决呢,数字k映射成让第k个选项上屏。这个做法有一个问题就是如果打的字比较长但是后面的选项比较短的话选了短的选项会吃掉所有打的字。所以能不能判断是否在按完数字键以后已经给所有的拼音选好了字呢?这个应该是LSP可以做的吧,我看了打印出来的entries,有一点点复杂,想问问里面有没有能判断是否已经给所有拼音选好字的选项,谢谢!
https://github.com/wlh320/rime-ls/assets/144102919/0769aa34-31ab-4dbf-a5df-9b1040a5bb2a
我目前只能实现到这一步 不知道有没有办法检测是否已经完成一次输入。
感觉现在是可以判断的,已经可以上屏的字前面就没有数字序号了。
只考虑 nvim 场景的话,应该是可以通过给 cmp 写一些 lua 逻辑来做到,比如按数字键之后判断候选项只有一个并且不是数字开头,就自动补全之类的。我初步判断有希望实现,但我对 lua 和 cmp 的接口都不太熟悉,你可以试试。LSP server 这边应该是不用做什么东西
好的,如果实现了我就把代码贴出来
https://github.com/wlh320/rime-ls/assets/144102919/f50bf67a-167f-4a75-af17-248b8d8dabab
初步解决,但是这个方法性能比较差,快速输入的时候有时候不跟手。现在的原理是在数字输入后检查不全项目,相当慢。 想问问您这个lsp里面有没有接口能判断每个项目匹配到的输入的部分是什么,比如我输入nihao的时候第二个项目是“你”,我有没有可能通过api知道这个项目匹配到的是“ni”。 如果可以的话我就可以不在数字输入后在做判断而是在数字输入时直接判断数字对应的项目是否应该直接上屏了。
LSP 本身是存在一些限制的,我用 LSP 的初衷是一套代码尽可能支持更多编辑器。如果确定用 vim 或者 nvim,也可以试试一些直接应用 rime + 补全插件 的方案,比如之前的 rime-ls 用户实现的 https://github.com/yao-weijie/cmp-rime 。等我有时间我也会看看有没有更好的解决方案。
我试了一下,直接用 cmp 的 confirm 确实非常慢,但是手动调用 vim.lsp.util.apply_text_edits
就很快
这是我的实现,就是在配置 cmp 那里通过 cmp 提供的 callback 接口,判断 entry 的情况手动补全
但是实现还很初步,标点符号也会直接上屏 可以修改判断用的正则表达式,只自动上屏汉字,避免影响正常编程
Edit: 增加了简单的标点判断
cmp.event:on('menu_opened', function()
entry = cmp.core.view:get_first_entry()
if entry and entry.source.name == "nvim_lsp"
and entry.source.source.client.name == "rime_ls" then
local item = entry:get_completion_item()
local label = item.label
local pos1, _ = string.find(label, "^%d%.")
local pos2, _ = string.find(label, "^[,。《》?;:“”、!()【】「」〖〗]")
if pos1 == nil and pos2 == nil then
vim.lsp.util.apply_text_edits({ item.textEdit }, 0, 'utf-16')
end
end
end)
我采用的思路是重新定义数字 1-9 这几个快捷键,当 rime_ls 通过数字键返回唯一的的候选项时,模拟按数字 0 的操作,数字 0 在这时候会上屏汉字。实际使用下来,效果和普通输入法类似,应该算非常跟手了。
M.keymaps["0"] = cmp.mapping(function(fallback)
if not cmp.visible() or not utils.buf_rime_enabled() then
return fallback()
end
local first_entry = cmp.core.view:get_first_entry()
if not M.input_method_take_effect(first_entry) then
return fallback()
end
M.rimels_auto_upload(cmp.core.view:get_entries())
end, { "i" })
for numkey = 1, 9 do
local numkey_str = tostring(numkey)
M.keymaps[numkey_str] = cmp.mapping(function(fallback)
if not cmp.visible() or not utils.buf_rime_enabled() then
return fallback()
else
local first_entry = cmp.core.view:get_first_entry()
if
not M.input_method_take_effect(
first_entry,
{ "probe_punctuation_after_half_symbol" }
)
then
return fallback()
end
end
cmp.mapping.close()
feedkey(numkey_str, "n")
cmp.complete()
feedkey("0", "m")
end, { "i" })
end
这中间调用了一些辅助函数,如果有兴趣,可以在 liubianshi/cmp-lsp-rimels 中查看。
你如果补全也在用 nvim-cmp
的话,可以尝试下我这个方案。
local just_inserted = false
local rime_ls_auto_confirm = vim.schedule_wrap(function()
local cmp = require("cmp")
if not cmp.visible() then
return
end
local entries = cmp.core.view:get_entries()
if entries == nil or #entries == 0 then
return
end
local rime_ls_entries_cnt = 0
for _, entry in ipairs(entries) do
if is_rime_entry(entry) then
rime_ls_entries_cnt = rime_ls_entries_cnt + 1
end
end
local first_entry = cmp.get_selected_entry()
if first_entry == nil then
first_entry = cmp.core.view:get_first_entry()
end
if
first_entry ~= nil
and rime_ls_entries_cnt == 1
and is_rime_entry(first_entry)
and text_edit_range_length(first_entry) == 4
then
cmp.confirm {
behavior = cmp.ConfirmBehavior.Insert,
select = true,
}
end
end)
vim.api.nvim_create_autocmd("InsertCharPre", {
buffer = bufnr,
callback = function()
just_inserted = true
end,
})
vim.api.nvim_create_autocmd({ "TextChangedI", "TextChangedP" }, {
buffer = bufnr,
callback = function()
if just_inserted then
-- check completion
rime_ls_auto_confirm()
just_inserted = false
end
end,
})
感觉数字选词这一块交给 cmp 之类的步骤比较好,毕竟大多数人开了不止一个 lsp,插件的优势就是混合输入。
nvim-cmp 的 index 功能还没merge https://github.com/hrsh7th/nvim-cmp/pull/1491/files
你如果补全也在用
nvim-cmp
的话,可以尝试下我这个方案。 这部分:https://github.com/TwIStOy/dotvim/blob/df9e00b6376c62a285b8c8fe37e61c4ffed251e8/lua/dotvim/pkgs/extra/misc/rime.lua#L46-L87
感谢 @TwIStOy 提供的方案,给了我很大的启发,但是提供的方案在快速输入的时候会有明显的卡顿,因此我对其做了如下的改动(没有绑定空格上屏,如果需要,只需要增加一个绑定即可):
local rime_ls_filetypes = { 'markdown', 'vimwiki' }
local function is_rime_entry(entry)
return vim.tbl_get(entry, "source", "name") == "nvim_lsp"
and vim.tbl_get(entry, "source", "source", "client", "name")
== "rime_ls"
end
local cmp = require("cmp")
local function auto_upload_rime()
if not cmp.visible() then
return
end
local entries = cmp.core.view:get_entries()
if entries == nil or #entries == 0 then
return
end
local first_entry = cmp.get_selected_entry()
if first_entry == nil then
first_entry = cmp.core.view:get_first_entry()
end
if first_entry ~= nil and is_rime_entry(first_entry) then
local rime_ls_entries_cnt = 0
for _, entry in ipairs(entries) do
if is_rime_entry(entry) then
rime_ls_entries_cnt = rime_ls_entries_cnt + 1
if rime_ls_entries_cnt == 2 then
break
end
end
end
if rime_ls_entries_cnt == 1 then
cmp.confirm {
behavior = cmp.ConfirmBehavior.Insert,
select = true,
}
end
end
end
vim.api.nvim_create_autocmd('FileType', {
pattern = rime_ls_filetypes,
callback = function ()
for numkey = 1, 9 do
local numkey_str = tostring(numkey)
vim.api.nvim_buf_set_keymap(0, 'i', numkey_str, '', {
noremap = true,
silent = false,
callback = function()
vim.fn.feedkeys(numkey_str, 'n')
vim.schedule(auto_upload_rime)
end
})
vim.api.nvim_buf_set_keymap(0, 's', numkey_str, '', {
noremap = true,
silent = false,
callback = function()
vim.fn.feedkeys(numkey_str, 'n')
vim.schedule(auto_upload_rime)
end
})
end
end
})
思路就是只对数字进行绑定,而不是在每次插入后都触发检查,这样只有在按下数字按键的时候才会触发自动上屏的检查,同时在检查的时候在可选数量为2时就直接结束循环,这样可以在补全列表的元素数量很多的时候提升性能,从而解决卡顿的问题。
Uploading RPReplay_Final1708562563.mp4…