Skip to content

Commit

Permalink
fix: continuous input in some editors
Browse files Browse the repository at this point in the history
- add option `long_filter_text` for some editors (zed, helix)
- add option `show_filter_text_in_label` for some editor (zed)
- update helix doc
  • Loading branch information
wlh320 committed May 6, 2024
1 parent 6170d9b commit f9fbe3c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 6 deletions.
8 changes: 5 additions & 3 deletions doc/helix.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ config.trigger_characters = []
config.schema_trigger_character = "&"
config.max_tokens = 4
config.always_incomplete = true
config.long_filter_text = true
```

### Since 23.10
Expand All @@ -38,6 +39,7 @@ config.trigger_characters = []
config.schema_trigger_character = "&"
config.max_tokens = 4
config.always_incomplete = true
config.long_filter_text = true

[[language]]
name = "markdown"
Expand All @@ -52,7 +54,7 @@ rime-ls 的配置项参考其他编辑器,都是一样的,改成 toml 的格

## 存在问题

- [ ] 补全触发条件有问题
- [ ] 在汉字后面输入不会自动触发补全,需通过配置的触发字符手动触发
- [ ] 最小补全长度为 2,手动设置最小补全长度为 1 会导致当前输入长度为 2 时补全消失
- [x] 补全触发条件有问题(**已解决**)
- [x] 在汉字后面输入不会自动触发补全,需通过配置的触发字符手动触发(since v0.2.5 配置 `config.long_filter_text = true`)
- [x] 最小补全长度为 2,手动设置最小补全长度为 1 会导致当前输入长度为 2 时补全消失(helix 最新版已无问题)

24 changes: 24 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ pub struct Config {
/// if preselect first CompletionItem
#[serde(default = "default_preselect_first")]
pub preselect_first: bool,
/// if including word prefix in filter_text
#[serde(default = "default_long_filter_text")]
pub long_filter_text: bool,
/// if showing filter_text in label
#[serde(default = "default_show_filter_text_in_label")]
pub show_filter_text_in_label: bool,
}

/// settings that can be tweaked during running
Expand All @@ -59,6 +65,10 @@ pub struct Settings {
pub always_incomplete: Option<bool>,
/// if preselect first CompletionItem
pub preselect_first: Option<bool>,
/// if including word prefix in filter_text
pub long_filter_text: Option<bool>,
/// if showing filter_text in label
pub show_filter_text_in_label: Option<bool>,
}

macro_rules! apply_setting {
Expand Down Expand Up @@ -90,6 +100,8 @@ impl Default for Config {
max_tokens: default_max_tokens(),
always_incomplete: default_always_incomplete(),
preselect_first: default_preselect_first(),
long_filter_text: default_long_filter_text(),
show_filter_text_in_label: default_show_filter_text_in_label()
}
}
}
Expand Down Expand Up @@ -140,6 +152,14 @@ fn default_preselect_first() -> bool {
false
}

fn default_long_filter_text() -> bool {
false
}

fn default_show_filter_text_in_label() -> bool {
false
}

#[test]
fn test_default_config() {
let config: Config = Default::default();
Expand Down Expand Up @@ -169,6 +189,8 @@ fn test_apply_settings() {
max_tokens: None,
always_incomplete: None,
preselect_first: None,
long_filter_text: None,
show_filter_text_in_label: Some(true),
};
// apply settings with macro
let mut test_val = vec!["baz".to_string()];
Expand All @@ -179,6 +201,7 @@ fn test_apply_settings() {
test_val = v.clone();
});
apply_setting!(config <- settings.schema_trigger_character);
apply_setting!(config <- settings.show_filter_text_in_label);
// verify
assert_eq!(config.enabled, false);
assert_eq!(config.max_candidates, 100);
Expand All @@ -188,5 +211,6 @@ fn test_apply_settings() {
);
assert_eq!(config.trigger_characters, vec!["foo".to_string()]);
assert_eq!(config.schema_trigger_character, String::from("bar"));
assert_eq!(config.show_filter_text_in_label, true);
assert_eq!(test_val, vec!["foo".to_string()]);
}
18 changes: 15 additions & 3 deletions src/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ impl Backend {
apply_setting!(config <- settings.max_tokens);
apply_setting!(config <- settings.always_incomplete);
apply_setting!(config <- settings.preselect_first);
apply_setting!(config <- settings.long_filter_text);
apply_setting!(config <- settings.show_filter_text_in_label);
}

async fn create_work_done_progress(&self, token: NumberOrString) -> Result<NumberOrString> {
Expand Down Expand Up @@ -201,22 +203,31 @@ impl Backend {

// candidates to completions
let range = Range::new(utils::offset_to_position(&rope, real_offset)?, position);
let filter_text = new_input.borrow_raw_text().to_string();
let filter_text = if self.config.read().await.long_filter_text {
let prefix = utils::surrounding_word(&Cow::from(rope.slice(line_begin..real_offset)));
prefix + new_input.borrow_raw_text()
} else {
new_input.borrow_raw_text().to_string()
};
let order_to_sort_text = {
let max_candidates = self.config.read().await.max_candidates;
utils::build_order_to_sort_text(max_candidates)
};
let show_filter_text_in_label = { self.config.read().await.show_filter_text_in_label };
let is_selecting = new_input.is_selecting();
let preselect_enabled = self.config.read().await.preselect_first;
let preselect_enabled = { self.config.read().await.preselect_first };
let candidate_to_completion_item = |(i, c): (usize, Candidate)| -> CompletionItem {
let text = match is_selecting {
true => submitted.clone() + &c.text,
false => c.text,
};
let label = match c.order {
let mut label = match c.order {
0 => text.to_string(),
_ => format!("{}. {}", c.order, &text),
};
if show_filter_text_in_label {
label += &format!(" ({})", filter_text);
}
let label_details = (!c.comment.is_empty()).then_some(CompletionItemLabelDetails {
detail: Some(c.comment.clone()),
description: None,
Expand All @@ -241,6 +252,7 @@ impl Backend {
new_offset,
is_incomplete,
));

// return completions
let item_iter = candidates
.into_iter()
Expand Down
29 changes: 29 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,32 @@ pub fn expand_tilde(path: impl AsRef<Path>) -> PathBuf {
let home_dir = base_dirs.home_dir();
home_dir.join(path.as_ref().strip_prefix("~").unwrap())
}

#[inline]
fn char_is_word(ch: char) -> bool {
ch.is_alphanumeric() || ch == '_'
}

pub fn surrounding_word(s: &str) -> String {
let end = s.len();
let mut start = end;
for ch in s.chars().rev() {
if char_is_word(ch) {
start -= ch.len_utf8();
} else {
break;
}
}
s[start..end].to_string()
}

#[test]
fn test_surrounding_word() {
assert_eq!(surrounding_word(""), "".to_string());
assert_eq!(surrounding_word(" "), "".to_string());
assert_eq!(surrounding_word("hello_world"), "hello_world".to_string());
assert_eq!(surrounding_word("hello world"), "world".to_string());
assert_eq!(surrounding_word("汉字nihao"), "汉字nihao".to_string());
assert_eq!(surrounding_word("汉,字nihao"), "字nihao".to_string());
assert_eq!(surrounding_word("汉。字nihao"), "字nihao".to_string());
}

0 comments on commit f9fbe3c

Please sign in to comment.