Skip to content

Commit

Permalink
completion fix
Browse files Browse the repository at this point in the history
  • Loading branch information
cossonleo committed May 1, 2022
1 parent ede01b5 commit 334c92b
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 62 deletions.
126 changes: 82 additions & 44 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2651,13 +2651,11 @@ pub mod insert {
super::completion(cx);
}

fn language_server_completion(cx: &mut Context, ch: char) {
pub fn is_server_trigger_char(doc: &Document, ch: char) -> bool {
use helix_lsp::lsp;
// if ch matches completion char, trigger completion
let doc = doc_mut!(cx.editor);
let language_server = match doc.language_server() {
Some(language_server) => language_server,
None => return,
None => return false,
};

let capabilities = language_server.capabilities();
Expand All @@ -2667,12 +2665,25 @@ pub mod insert {
..
}) = &capabilities.completion_provider
{
// TODO: what if trigger is multiple chars long
if triggers.iter().any(|trigger| trigger.contains(ch)) {
cx.editor.clear_idle_timer();
super::completion(cx);
return true;
}
}
false
}

fn language_server_completion(cx: &mut Context, ch: char) {
use helix_core::chars::char_is_word;

// if ch matches completion char, trigger completion
let doc = doc_mut!(cx.editor);
if char_is_word(ch) && doc.savepoint.is_none() {
cx.editor.reset_idle_timer();
return;
}
if is_server_trigger_char(doc, ch) {
cx.editor.reset_idle_timer_zero();
}
}

fn signature_help(cx: &mut Context, ch: char) {
Expand Down Expand Up @@ -3545,6 +3556,12 @@ pub fn completion(cx: &mut Context) {
let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding);

let future = language_server.completion(doc.identifier(), pos, None);
let future = async move {
match future.await {
Ok(v) => Ok(v),
Err(_) => Ok(serde_json::Value::Null),
}
};

let trigger_offset = cursor;

Expand All @@ -3558,51 +3575,72 @@ pub fn completion(cx: &mut Context) {
let start_offset = cursor.saturating_sub(offset);
let prefix = text.slice(start_offset..cursor).to_string();

doc.savepoint();
let trigger_version = doc.version();
cx.callback(
future,
move |editor, compositor, response: Option<lsp::CompletionResponse>| {
let doc = doc!(editor);
if doc.mode() != Mode::Insert {
// we're not in insert mode anymore
return;
}
let get_items = || {
let doc = doc!(editor);
if doc.mode() != Mode::Insert {
// we're not in insert mode anymore
return None;
}
match &doc.savepoint {
Some((current, _)) if *current == trigger_version => {}
_ => return None,
};
if response.is_none() {
if doc.version() != trigger_version {
editor.reset_idle_timer_zero();
}
return None;
}

let mut items = match response {
Some(lsp::CompletionResponse::Array(items)) => items,
// TODO: do something with is_incomplete
Some(lsp::CompletionResponse::List(lsp::CompletionList {
is_incomplete: _is_incomplete,
items,
})) => items,
None => Vec::new(),
};
let mut items = match response {
Some(lsp::CompletionResponse::Array(items)) => items,
// TODO: do something with is_incomplete
Some(lsp::CompletionResponse::List(lsp::CompletionList {
is_incomplete: _is_incomplete,
items,
})) => items,
None => return None,
};

if !prefix.is_empty() {
items = items
.into_iter()
.filter(|item| {
item.filter_text
.as_ref()
.unwrap_or(&item.label)
.starts_with(&prefix)
})
.collect();
}
if !prefix.is_empty() {
items = items
.into_iter()
.filter(|item| {
item.filter_text
.as_ref()
.unwrap_or(&item.label)
.starts_with(&prefix)
})
.collect();
};

if items.is_empty() {
// editor.set_error("No completion available");
return;
}
if items.is_empty() {
// editor.set_error("No completion available".to_string());
return None;
}
Some(items)
};
let size = compositor.size();
let ui = compositor.find::<ui::EditorView>().unwrap();
ui.set_completion(
editor,
items,
offset_encoding,
start_offset,
trigger_offset,
size,
);
match get_items() {
Some(items) => ui.set_completion(
editor,
items,
offset_encoding,
start_offset,
trigger_offset,
size,
),
None => {
ui.completion = None;
doc_mut!(editor).savepoint = None;
}
}
},
);
}
Expand Down
56 changes: 42 additions & 14 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -907,9 +907,6 @@ impl EditorView {
return;
}

// Immediately initialize a savepoint
doc_mut!(editor).savepoint();

editor.last_completion = None;
self.last_insert.1.push(InsertEvent::TriggerCompletion);

Expand All @@ -928,23 +925,53 @@ impl EditorView {
}

pub fn handle_idle_timeout(&mut self, cx: &mut crate::compositor::Context) -> EventResult {
if self.completion.is_some()
|| !cx.editor.config().auto_completion
|| doc!(cx.editor).mode != Mode::Insert
{
use commands::insert::is_server_trigger_char;
use helix_core::chars::char_is_word;

let config = cx.editor.config();
let (view, doc) = current!(cx.editor);
if doc.mode != Mode::Insert || !config.auto_completion {
return EventResult::Ignored(None);
}

let mut cx = commands::Context {
let is_trigger = || -> bool {
let text = doc.text().slice(..);
let cursor = doc.selection(view.id).primary().cursor(text);

let mut iter = text.chars_at(cursor);
iter.reverse();
let last_char = match iter.next() {
Some(c) => c,
None => return false,
};
if is_server_trigger_char(doc, last_char) {
return true;
}
if !char_is_word(last_char) {
return false;
}
for _ in 1..config.completion_trigger_len {
match iter.next() {
Some(c) if char_is_word(c) || is_server_trigger_char(doc, c) => {}
_ => return false,
}
}
true
};

if !is_trigger() {
return EventResult::Ignored(None);
}

self.clear_completion(cx.editor);
commands::completion(&mut commands::Context {
register: None,
editor: cx.editor,
jobs: cx.jobs,
count: None,
callback: None,
on_next_key_callback: None,
};
crate::commands::insert::idle_completion(&mut cx);

});
EventResult::Consumed(None)
}
}
Expand Down Expand Up @@ -1178,7 +1205,7 @@ impl Component for EditorView {
EventResult::Consumed(None)
}
Event::Key(key) => {
cx.editor.reset_idle_timer();
cx.editor.clear_idle_timer();
let mut key = KeyEvent::from(key);
canonicalize_key(&mut key);

Expand Down Expand Up @@ -1230,7 +1257,8 @@ impl Component for EditorView {
if let Some(completion) = &mut self.completion {
completion.update(&mut cx);
if completion.is_empty() {
self.clear_completion(cx.editor);
self.completion = None;
doc_mut!(cx.editor).savepoint = None;
}
}
}
Expand Down Expand Up @@ -1276,7 +1304,7 @@ impl Component for EditorView {
}
(Mode::Insert, Mode::Normal) => {
// if exiting insert mode, remove completion
self.completion = None;
self.clear_completion(cx.editor);
}
_ => (),
}
Expand Down
9 changes: 5 additions & 4 deletions helix-view/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub struct Document {
// be more troublesome.
pub history: Cell<History>,

pub savepoint: Option<Transaction>,
pub savepoint: Option<(i32, Transaction)>,

last_saved_revision: usize,
version: i32, // should be usize?
Expand Down Expand Up @@ -670,7 +670,8 @@ impl Document {
if self.savepoint.is_some() {
take_with(&mut self.savepoint, |prev_revert| {
let revert = transaction.invert(&old_doc);
Some(revert.compose(prev_revert.unwrap()))
let (version, prev_revert) = prev_revert.unwrap();
Some((version, revert.compose(prev_revert)))
});
}

Expand Down Expand Up @@ -758,11 +759,11 @@ impl Document {
}

pub fn savepoint(&mut self) {
self.savepoint = Some(Transaction::new(self.text()));
self.savepoint = Some((self.version, Transaction::new(self.text())));
}

pub fn restore(&mut self, view_id: ViewId) {
if let Some(revert) = self.savepoint.take() {
if let Some((_, revert)) = self.savepoint.take() {
self.apply(&revert, view_id);
}
}
Expand Down
4 changes: 4 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ impl Editor {
.reset(Instant::now() + config.idle_timeout);
}

pub fn reset_idle_timer_zero(&mut self) {
self.idle_timer.as_mut().reset(Instant::now());
}

pub fn clear_status(&mut self) {
self.status_msg = None;
}
Expand Down

0 comments on commit 334c92b

Please sign in to comment.