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

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