Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Make repeat operator work with completion edits #1640

Merged
merged 15 commits into from
Mar 1, 2022
Merged
22 changes: 18 additions & 4 deletions helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::compositor::{Component, Context, EventResult};
use crossterm::event::{Event, KeyCode, KeyEvent};
use helix_view::editor::CompleteAction;
use tui::buffer::Buffer as Surface;

use std::borrow::Cow;
Expand Down Expand Up @@ -92,13 +93,14 @@ impl Completion {
start_offset: usize,
trigger_offset: usize,
) -> Transaction {
if let Some(edit) = &item.text_edit {
let transaction = if let Some(edit) = &item.text_edit {
let edit = match edit {
lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
lsp::CompletionTextEdit::InsertAndReplace(item) => {
unimplemented!("completion: insert_and_replace {:?}", item)
}
};

util::generate_transaction_from_edits(
doc.text(),
vec![edit],
Expand All @@ -114,7 +116,9 @@ impl Completion {
doc.text(),
vec![(trigger_offset, trigger_offset, Some(text.into()))].into_iter(),
)
}
};

transaction
}

let (view, doc) = current!(editor);
Expand All @@ -123,7 +127,9 @@ impl Completion {
doc.restore(view.id);

match event {
PromptEvent::Abort => {}
PromptEvent::Abort => {
editor.last_completion = None;
}
PromptEvent::Update => {
// always present here
let item = item.unwrap();
Expand All @@ -138,8 +144,11 @@ impl Completion {

// initialize a savepoint
doc.savepoint();

doc.apply(&transaction, view.id);
editor.last_completion = Some(CompleteAction {
trigger_pos: trigger_offset,
matszczygiel marked this conversation as resolved.
Show resolved Hide resolved
transaction,
});
}
PromptEvent::Validate => {
// always present here
Expand All @@ -152,7 +161,12 @@ impl Completion {
start_offset,
trigger_offset,
);

doc.apply(&transaction, view.id);
editor.last_completion = Some(CompleteAction {
trigger_pos: trigger_offset,
transaction,
});

// apply additional edits, mostly used to auto import unqualified types
let resolved_additional_text_edits = if item.additional_text_edits.is_some() {
Expand Down
63 changes: 55 additions & 8 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ use helix_core::{
syntax::{self, HighlightEvent},
unicode::segmentation::UnicodeSegmentation,
unicode::width::UnicodeWidthStr,
LineEnding, Position, Range, Selection,
LineEnding, Position, Range, Selection, Transaction,
};
use helix_view::{
document::{Mode, SCRATCH_BUFFER_NAME},
editor::CursorShapeConfig,
editor::{CompleteAction, CursorShapeConfig},
graphics::{CursorKind, Modifier, Rect, Style},
info::Info,
input::KeyEvent,
Expand All @@ -34,12 +34,19 @@ use tui::buffer::Buffer as Surface;
pub struct EditorView {
keymaps: Keymaps,
on_next_key: Option<Box<dyn FnOnce(&mut commands::Context, KeyEvent)>>,
last_insert: (commands::MappableCommand, Vec<KeyEvent>),
last_insert: (commands::MappableCommand, Vec<InsertEvent>),
pub(crate) completion: Option<Completion>,
spinners: ProgressSpinners,
autoinfo: Option<Info>,
}

#[derive(Debug, Clone)]
archseer marked this conversation as resolved.
Show resolved Hide resolved
pub enum InsertEvent {
Key(KeyEvent),
CompletionApply(CompleteAction),
TriggerCompleiton,
}

impl Default for EditorView {
fn default() -> Self {
Self::new(Keymaps::default())
Expand Down Expand Up @@ -735,8 +742,35 @@ impl EditorView {
// first execute whatever put us into insert mode
self.last_insert.0.execute(cxt);
// then replay the inputs
for &key in &self.last_insert.1.clone() {
self.insert_mode(cxt, key)
for key in self.last_insert.1.clone() {
match key {
InsertEvent::Key(key) => self.insert_mode(cxt, key),
InsertEvent::CompletionApply(compl) => {
let (view, doc) = current!(cxt.editor);

doc.restore(view.id);

let text = doc.text().slice(..);
let cursor = doc.selection(view.id).primary().cursor(text);

log::error!("Replaying completion: {compl:?}");

let shift_position =
|pos: usize| -> usize { pos + cursor - compl.trigger_pos };

let tx = Transaction::change(
doc.text(),
compl.transaction.changes_iter().map(|(start, end, t)| {
(shift_position(start), shift_position(end), t)
}),
archseer marked this conversation as resolved.
Show resolved Hide resolved
);
doc.apply(&tx, view.id);
}
InsertEvent::TriggerCompleiton => {
let (_, doc) = current!(cxt.editor);
doc.savepoint();
}
}
}
}
_ => {
Expand Down Expand Up @@ -777,6 +811,9 @@ impl EditorView {
// Immediately initialize a savepoint
doc_mut!(editor).savepoint();

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

// TODO : propagate required size on resize to completion too
completion.required_size((size.width, size.height));
self.completion = Some(completion);
Expand Down Expand Up @@ -981,9 +1018,6 @@ impl Component for EditorView {
} else {
match mode {
Mode::Insert => {
// record last_insert key
self.last_insert.1.push(key);

// let completion swallow the event if necessary
let mut consumed = false;
if let Some(completion) = &mut self.completion {
Expand All @@ -999,6 +1033,12 @@ impl Component for EditorView {
consumed = true;

if callback.is_some() {
if let Some(compl) = cx.editor.last_completion.take() {
self.last_insert
.1
.push(InsertEvent::CompletionApply(compl));
}
matszczygiel marked this conversation as resolved.
Show resolved Hide resolved

// assume close_fn
self.clear_completion(cx.editor);
}
Expand All @@ -1007,8 +1047,15 @@ impl Component for EditorView {

// if completion didn't take the event, we pass it onto commands
if !consumed {
if let Some(compl) = cx.editor.last_completion.take() {
self.last_insert.1.push(InsertEvent::CompletionApply(compl));
}

self.insert_mode(&mut cx, key);

// record last_insert key
self.last_insert.1.push(InsertEvent::Key(key));

// lastly we recalculate completion
if let Some(completion) = &mut self.completion {
completion.update(&mut cx);
Expand Down
11 changes: 10 additions & 1 deletion helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use anyhow::{bail, Error};

pub use helix_core::diagnostic::Severity;
pub use helix_core::register::Registers;
use helix_core::syntax;
use helix_core::{syntax, Transaction};
use helix_core::{Position, Selection};

use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize};
Expand Down Expand Up @@ -249,9 +249,17 @@ pub struct Editor {
pub idle_timer: Pin<Box<Sleep>>,
pub last_motion: Option<Motion>,

pub last_completion: Option<CompleteAction>,

pub exit_code: i32,
}

#[derive(Default, Debug, Clone)]
matszczygiel marked this conversation as resolved.
Show resolved Hide resolved
pub struct CompleteAction {
pub trigger_pos: usize,
pub transaction: Transaction,
}

#[derive(Debug, Copy, Clone)]
pub enum Action {
Load,
Expand Down Expand Up @@ -288,6 +296,7 @@ impl Editor {
status_msg: None,
idle_timer: Box::pin(sleep(config.idle_timeout)),
last_motion: None,
last_completion: None,
config,
exit_code: 0,
}
Expand Down