Skip to content
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

feat: 强制4字补全 & 强制触发补全 #7

Merged
merged 5 commits into from
Apr 4, 2023
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
46 changes: 45 additions & 1 deletion doc/nvim.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ local start_rime = function()
max_candidates = 10, -- [v0.2.0 后不再有用] 与 rime 的候选数量配置最好保持一致
trigger_characters = {}, -- 为空表示全局开启
schema_trigger_character = "&" -- [since v0.2.0] 当输入此字符串时请求补全会触发 “方案选单”
always_incomplete = false -- [since v0.2.3] true 强制补全永远刷新整个列表,而不是使用过滤
max_tokens = 0 -- [since v0.2.3] 大于 0 表示会在删除到这个字符个数的时候,重建所有候选词,而不使用删除字符操作
},
});
vim.lsp.buf_attach_client(0, client_id)
Expand Down Expand Up @@ -237,7 +239,7 @@ return M

## 空格键补全

为了取得与外部输入法更加相似的体验,可以通过配置 cmp 实现用空格键补全,参考配置如下:
为了取得与外部输入法更加相似的体验,可以通过配置 cmp 实现用空格键补全并用回车键直接输入,参考配置如下:

```lua
cmp.setup {
Expand All @@ -248,6 +250,9 @@ cmp.setup {
-- ...
['<Space>'] = cmp.mapping(function(fallback)
local entry = cmp.get_selected_entry()
if entry == nil then
entry = cmp.core.view:get_first_entry()
end
if entry and entry.source.name == "nvim_lsp"
and entry.source.source.client.name == "rime_ls" then
cmp.confirm({
Expand All @@ -258,6 +263,25 @@ cmp.setup {
fallback()
end
end, {'i', 's'}),
['<CR>'] = cmp.mapping(function(fallback)
local entry = cmp.get_selected_entry()
if entry == nil then
entry = cmp.core.view:get_first_entry()
end
if entry and entry.source.name == 'nvim_lsp'
and entry.source.source.client.name == 'rime_ls' then
cmp.abort()
else
if entry ~= nil then
cmp.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true
})
else
fallback()
end
end
end, {'i', 's'}),
-- 其他内容
-- ...
}
Expand All @@ -272,3 +296,23 @@ cmp.setup {

将运行命令修改为 `cmd = vim.lsp.rpc.connect('<ip>', <port>)`

## 五笔或者双形用户

```lua
require('lspconfig').rime_ls.setup {
init_options = {
enabled = vim.g.rime_enabled,
shared_data_dir = "/usr/share/rime-data",
user_data_dir = "~/.local/share/rime-ls",
log_dir = "~/.local/share/rime-ls",
max_candidates = 9,
trigger_characters = {},
schema_trigger_character = "&" -- [since v0.2.0] 当输入此字符串时请求补全会触发 “方案选单”
max_tokens = 4, -- 强制在删除到4字的时候重建一次候选词,避免用退格造成的空列表的问题
always_incomplete = true, -- 将 incomplete 永远设为 true,防止任何时候的过滤代替候选词重建
},
on_attach = rime_on_attach,
capabilities = capabilities,
}
```

18 changes: 18 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ pub struct Config {
/// if set, completion request with this string will trigger「方案選單」
#[serde(default = "default_schema_trigger_character")]
pub schema_trigger_character: String,
/// if set, when a delete action arrives the number of max tokens, emit a force new_typing
#[serde(default = "default_max_tokens")]
pub max_tokens: usize,
/// if CompletionItem is always incomplete
#[serde(default = "default_always_incomplete")]
pub always_incomplete: bool,
}

/// settings that can be tweaked during running
Expand Down Expand Up @@ -66,6 +72,8 @@ impl Default for Config {
max_candidates: default_max_candidates(),
trigger_characters: default_trigger_characters(),
schema_trigger_character: default_schema_trigger_character(),
max_tokens: default_max_tokens(),
always_incomplete: default_always_incomplete(),
}
}
}
Expand All @@ -74,10 +82,18 @@ fn default_enabled() -> bool {
true
}

fn default_always_incomplete() -> bool {
false
}

fn default_max_candidates() -> usize {
10
}

fn default_max_tokens() -> usize {
0
}

fn default_trigger_characters() -> Vec<String> {
Vec::default()
}
Expand Down Expand Up @@ -113,6 +129,8 @@ fn test_default_config() {
config.schema_trigger_character,
default_schema_trigger_character()
);
assert_eq!(config.always_incomplete, default_always_incomplete());
assert_eq!(config.max_tokens, default_max_tokens());
}

#[test]
Expand Down
22 changes: 21 additions & 1 deletion src/input.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt::Display;

use ouroboros::self_referencing;
use regex::Regex;

Expand All @@ -15,6 +17,16 @@ pub struct Input {
pub select: &'this str,
}

impl Display for Input {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"pinyin: {}, select: {}",
self.borrow_pinyin(),
self.borrow_select()
))
}
}

impl Input {
/// if matches, take ownership of &str, and self-reference it.
pub fn from_str(re: &Regex, text: &str) -> Option<Self> {
Expand Down Expand Up @@ -101,6 +113,7 @@ impl InputState {
new_offset: usize,
new_input: &Input,
schema_trigger: &str,
max_tokens: usize,
) -> InputResult {
let rime = Rime::global();
let session_id = rime.find_session(self.session_id);
Expand All @@ -118,7 +131,14 @@ impl InputState {
let diff_pinyin = diff(self.input.borrow_pinyin(), new_input.borrow_pinyin());
match diff_pinyin {
DiffResult::Add(suffix) => rime.process_str(session_id, suffix),
DiffResult::Delete(suffix) => rime.delete_keys(session_id, suffix.len()),
DiffResult::Delete(suffix) => {
// if current pinyin len == max_tokens, force new typing
if max_tokens > 0 && max_tokens == new_input.borrow_pinyin().len() {
rime.clear_composition(session_id);
return Self::handle_new_typing(session_id, new_input);
}
rime.delete_keys(session_id, suffix.len())
}
DiffResult::New => {
rime.clear_composition(session_id);
if !schema_trigger.is_empty() && new_input.borrow_pinyin() == &schema_trigger {
Expand Down
9 changes: 7 additions & 2 deletions src/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,12 @@ impl Backend {
} = match (*last_state).as_ref() {
Some(state) => {
let schema_trigger = &self.config.read().await.schema_trigger_character;
state.handle_new_input(new_offset, &new_input, schema_trigger)
state.handle_new_input(
new_offset,
&new_input,
schema_trigger,
self.config.read().await.max_tokens,
)
}
None => InputState::handle_first_state(&new_input),
};
Expand Down Expand Up @@ -235,7 +240,7 @@ impl Backend {
.enumerate()
.map(|(i, c)| candidate_to_completion_item(i, c));
Some(CompletionList {
is_incomplete,
is_incomplete: (self.config.read().await.always_incomplete || is_incomplete),
items: item_iter.collect(),
})
}
Expand Down