-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
用数字选词以后还需要一次空格才能上屏幕 #20
Comments
这个是bug吗还是本来就是这么设计的,有没有可能按数字直接就可以继续输入呀 |
目前暂时只能做到这样,LSP 只提供候选项,应该不清楚用户最终具体是怎么选择的?如果是针对特定的编辑器,或许可以通过写插件之类的做到按数字直接输入。 也有可能是我调研不清楚,我有空的时候再研究一下 LSP 协议 |
有没有可能可以用keymap解决呢,数字k映射成让第k个选项上屏。这个做法有一个问题就是如果打的字比较长但是后面的选项比较短的话选了短的选项会吃掉所有打的字。所以能不能判断是否在按完数字键以后已经给所有的拼音选好了字呢?这个应该是LSP可以做的吧,我看了打印出来的entries,有一点点复杂,想问问里面有没有能判断是否已经给所有拼音选好字的选项,谢谢! |
RPReplay_Final1708590317.mp4我目前只能实现到这一步 |
感觉现在是可以判断的,已经可以上屏的字前面就没有数字序号了。 只考虑 nvim 场景的话,应该是可以通过给 cmp 写一些 lua 逻辑来做到,比如按数字键之后判断候选项只有一个并且不是数字开头,就自动补全之类的。我初步判断有希望实现,但我对 lua 和 cmp 的接口都不太熟悉,你可以试试。LSP server 这边应该是不用做什么东西 |
好的,如果实现了我就把代码贴出来 |
RPReplay_Final1708746438.mp4初步解决,但是这个方法性能比较差,快速输入的时候有时候不跟手。现在的原理是在数字输入后检查不全项目,相当慢。 |
LSP 本身是存在一些限制的,我用 LSP 的初衷是一套代码尽可能支持更多编辑器。如果确定用 vim 或者 nvim,也可以试试一些直接应用 rime + 补全插件 的方案,比如之前的 rime-ls 用户实现的 https://github.com/yao-weijie/cmp-rime 。等我有时间我也会看看有没有更好的解决方案。 |
我试了一下,直接用 cmp 的 confirm 确实非常慢,但是手动调用 这是我的实现,就是在配置 cmp 那里通过 cmp 提供的 callback 接口,判断 entry 的情况手动补全
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 中查看。 |
你如果补全也在用 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 |
感谢 @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时就直接结束循环,这样可以在补全列表的元素数量很多的时候提升性能,从而解决卡顿的问题。 |
最近在尝试 blink.cmp,作者 最新的一个 commit 有希望实现这个功能 试了一下感觉还行?我现在感觉 blink.cmp 比 nvim-cmp 舒服多了 我现在的配置是这样: 还是有点问题,这样没法连续选择了 config = function()
local rime_complete = function(cmp, index)
local list = require('blink.cmp.completion.list')
if not list then return end
local item = list.items[index or list.selected_item_idx]
if not item then return end
local client = vim.lsp.get_client_by_id(item.client_id)
if (not client) or client.name ~= "rime_ls" then return end
cmp.accept({ index = index })
end
require('blink.cmp').setup {
-- 'default', 'super-tab', 'enter'
keymap = {
preset = 'enter',
['<Tab>'] = { 'snippet_forward', 'select_next', 'fallback' },
['<S-Tab>'] = { 'snippet_backward', 'select_prev', 'fallback' },
['1'] = { function(cmp) rime_complete(cmp, 1) end, 'fallback' },
['2'] = { function(cmp) rime_complete(cmp, 2) end, 'fallback' },
['3'] = { function(cmp) rime_complete(cmp, 3) end, 'fallback' },
['4'] = { function(cmp) rime_complete(cmp, 4) end, 'fallback' },
['5'] = { function(cmp) rime_complete(cmp, 5) end, 'fallback' },
['6'] = { function(cmp) rime_complete(cmp, 6) end, 'fallback' },
['7'] = { function(cmp) rime_complete(cmp, 7) end, 'fallback' },
['8'] = { function(cmp) rime_complete(cmp, 8) end, 'fallback' },
['9'] = { function(cmp) rime_complete(cmp, 9) end, 'fallback' },
},
......
}
end 更新:直接像之前那样加个事件判断,这样与 rime-ls 最初的设计比较贴合 require('blink.cmp.completion.list').show_emitter:on(function(event)
-- if last char is number, and the only completion item is provided by rime-ls, accept it
local items = event.items
local line = event.context.line
local col = vim.fn.col('.') - 1
if #items ~= 1 then return end
if line:sub(col - 1, col):match("%a%d") == nil then return end
local item = items[1]
local client = vim.lsp.get_client_by_id(item.client_id)
if (not client) or client.name ~= "rime_ls" then return end
require('blink.cmp').accept({ index = 1 })
end) |
Uploading RPReplay_Final1708562563.mp4…
The text was updated successfully, but these errors were encountered: