Skip to content

Commit

Permalink
completion fix
Browse files Browse the repository at this point in the history
  • Loading branch information
cossonleo committed Sep 10, 2022
1 parent a15420e commit aec001a
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 39 deletions.
83 changes: 62 additions & 21 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2887,13 +2887,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 @@ -2903,11 +2901,35 @@ 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);
triggers.iter().any(|trigger| trigger.contains(ch))
} else {
false
}
}

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

let config = cx.editor.config();
if !config.auto_completion {
return;
}
let (view, doc) = current_ref!(cx.editor);
if char_is_word(ch) && doc.savepoint.is_none() {
let text = doc.text().slice(..);
let cursor = doc.selection(view.id).primary().cursor(text);
let mut iter = text.chars_at(cursor);
iter.reverse();
for _ in 0..config.completion_trigger_len {
if iter.next().map_or(true, |c| !char_is_word(c)) {
return;
}
}
cx.editor.reset_idle_timer();
return;
}
if is_server_trigger_char(doc, ch) {
cx.editor.reset_idle_timer_zero();
}
}

Expand Down Expand Up @@ -3819,6 +3841,13 @@ 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(helix_lsp::Error::Timeout) => Ok(serde_json::Value::Null),
Err(e) => Err(e),
}
};

let trigger_offset = cursor;

Expand All @@ -3832,11 +3861,21 @@ 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_mut!(editor);
let savepoint = match doc.savepoint.take() {
Some(s) => s,
None => return,
};
if editor.mode != Mode::Insert {
// we're not in insert mode anymore
return;
}
if savepoint.0 != trigger_version {
doc.savepoint = Some(savepoint);
return;
}

Expand All @@ -3847,25 +3886,27 @@ pub fn completion(cx: &mut Context) {
is_incomplete: _is_incomplete,
items,
})) => items,
None => Vec::new(),
None => {
editor.set_status(
"The completion response is none and will request server again",
);
editor.reset_idle_timer();
return;
}
};

if !prefix.is_empty() {
items = items
.into_iter()
.filter(|item| {
item.filter_text
.as_ref()
.unwrap_or(&item.label)
.starts_with(&prefix)
})
.collect();
}
items.retain(|item| match &item.filter_text {
Some(t) => t.starts_with(&prefix),
None => item.label.starts_with(&prefix),
});
};

if items.is_empty() {
// editor.set_error("No completion available");
// editor.set_error("No completion available".to_string());
return;
}
doc.savepoint = Some(savepoint);
let size = compositor.size();
let ui = compositor.find::<ui::EditorView>().unwrap();
ui.set_completion(
Expand Down
10 changes: 10 additions & 0 deletions helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,16 @@ impl Component for Completion {
height = rel_height.min(height);
}
Rect::new(x, y, width, height)
} else if popup_x > 30 {
let mut height = area.height.saturating_sub(popup_y);
let mut width = popup_x;
if let Some((rel_width, rel_height)) = markdown_doc.required_size((width, height)) {
width = rel_width.min(width);
height = rel_height.min(height);
}
let x = popup_x - width;
let y = popup_y;
Rect::new(x, y, width, height)
} else {
let half = area.height / 2;
let height = 15.min(half);
Expand Down
23 changes: 9 additions & 14 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ impl EditorView {
}
(Mode::Insert, Mode::Normal) => {
// if exiting insert mode, remove completion
self.completion = None;
self.clear_completion(cxt.editor);

// TODO: Use an on_mode_change hook to remove signature help
cxt.jobs.callback(async {
Expand Down Expand Up @@ -985,9 +985,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 @@ -1006,23 +1003,20 @@ impl EditorView {
}

pub fn handle_idle_timeout(&mut self, cx: &mut crate::compositor::Context) -> EventResult {
if self.completion.is_some()
|| cx.editor.mode != Mode::Insert
|| !cx.editor.config().auto_completion
{
let config = cx.editor.config();
if cx.editor.mode != Mode::Insert || !config.auto_completion {
return EventResult::Ignored(None);
}

let mut cx = commands::Context {
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 @@ -1246,7 +1240,7 @@ impl Component for EditorView {
EventResult::Consumed(None)
}
Event::Key(mut key) => {
cx.editor.reset_idle_timer();
cx.editor.clear_idle_timer();
canonicalize_key(&mut key);

// clear status
Expand Down Expand Up @@ -1298,7 +1292,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
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 @@ -768,7 +768,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 @@ -856,11 +857,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 @@ -763,6 +763,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 aec001a

Please sign in to comment.