use anyhow::Result;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use crate::action::{InsertKey, LastChange};
use crate::app::App;
use crate::app::completion::is_ident_continue;
use crate::editor::Cursor;
use crate::mode::Mode;
impl App {
pub(super) fn handle_insert_key(&mut self, key: KeyEvent) -> Result<()> {
if self.completion.is_some()
&& let Some(()) = self.handle_completion_key(key)
{
return Ok(());
}
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
if ctrl && key.code == KeyCode::Char(' ') {
self.lsp_completion();
return Ok(());
}
let no_ctrl = !key.modifiers.contains(KeyModifiers::CONTROL);
if no_ctrl && let KeyCode::Char(c) = key.code {
self.fan_out_insert_char(c);
self.record_insert_key(InsertKey::Char(c));
self.update_completion_filter();
if self.completion.is_none() && self.lsp.has_lsp() && is_ident_continue(c) {
self.lsp_completion();
}
return Ok(());
}
match key.code {
KeyCode::Esc => {
self.finalize_insert_recording();
self.enter_mode(Mode::Normal);
}
KeyCode::Enter => {
let indent = self.indent_settings();
self.buffer.insert_newline(indent);
self.record_insert_key(InsertKey::Newline);
self.cancel_completion();
}
KeyCode::Backspace => {
self.fan_out_backspace();
self.record_insert_key(InsertKey::Backspace);
self.update_completion_filter();
}
KeyCode::Tab => {
let indent = self.indent_settings();
if indent.use_tabs {
self.fan_out_insert_char('\t');
self.record_insert_key(InsertKey::Char('\t'));
} else {
let stop = indent.width.max(1);
let col = self.buffer.cursor.col;
let n = stop - (col % stop);
for _ in 0..n {
self.fan_out_insert_char(' ');
self.record_insert_key(InsertKey::Char(' '));
}
}
self.update_completion_filter();
}
KeyCode::Left => {
self.recording = None;
self.buffer.move_left();
self.cancel_completion();
}
KeyCode::Right => {
self.recording = None;
self.buffer.move_right(true);
self.cancel_completion();
}
KeyCode::Up => {
self.recording = None;
self.buffer.move_up();
self.cancel_completion();
}
KeyCode::Down => {
self.recording = None;
self.buffer.move_down();
self.cancel_completion();
}
_ => {}
}
Ok(())
}
fn handle_completion_key(&mut self, key: KeyEvent) -> Option<()> {
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
match key.code {
KeyCode::Esc => {
self.cancel_completion();
Some(())
}
KeyCode::Up => {
if let Some(s) = self.completion.as_mut() {
s.move_selection(-1);
}
Some(())
}
KeyCode::Down => {
if let Some(s) = self.completion.as_mut() {
s.move_selection(1);
}
Some(())
}
KeyCode::Char('p') if ctrl => {
if let Some(s) = self.completion.as_mut() {
s.move_selection(-1);
}
Some(())
}
KeyCode::Char('n') if ctrl => {
if let Some(s) = self.completion.as_mut() {
s.move_selection(1);
}
Some(())
}
KeyCode::Tab => {
if let Some(s) = self.completion.as_mut() {
s.move_selection(1);
}
Some(())
}
KeyCode::BackTab => {
if let Some(s) = self.completion.as_mut() {
s.move_selection(-1);
}
Some(())
}
KeyCode::Enter => {
self.accept_completion();
Some(())
}
_ => None,
}
}
fn fan_out_insert_char(&mut self, ch: char) {
if self.buffer.extra_cursors.is_empty() {
let indent = self.indent_settings();
self.buffer.insert_char_smart(ch, indent);
return;
}
let mut all = collect_cursors(self);
all.sort_by_key(|(_, c)| std::cmp::Reverse((c.row, c.col)));
let mut new_positions = vec![Cursor::default(); all.len()];
for i in 0..all.len() {
let (orig_idx, pos) = all[i];
self.buffer.cursor = pos;
self.buffer.insert_char(ch);
new_positions[orig_idx] = self.buffer.cursor;
for (other_orig_idx, _) in all.iter().take(i) {
if new_positions[*other_orig_idx].row == pos.row {
new_positions[*other_orig_idx].col += 1;
}
}
}
scatter_cursors(self, new_positions);
}
fn fan_out_backspace(&mut self) {
if self.buffer.extra_cursors.is_empty() {
let indent = self.indent_settings();
self.buffer.delete_char_before_smart(indent);
return;
}
let mut all = collect_cursors(self);
all.sort_by_key(|(_, c)| std::cmp::Reverse((c.row, c.col)));
let mut new_positions = vec![Cursor::default(); all.len()];
for i in 0..all.len() {
let (orig_idx, pos) = all[i];
if pos.col == 0 {
if orig_idx == 0 {
self.buffer.cursor = pos;
self.buffer.delete_char_before();
new_positions[orig_idx] = self.buffer.cursor;
} else {
new_positions[orig_idx] = pos;
}
continue;
}
self.buffer.cursor = pos;
self.buffer.delete_char_before();
new_positions[orig_idx] = self.buffer.cursor;
for (other_orig_idx, _) in all.iter().take(i) {
if new_positions[*other_orig_idx].row == pos.row
&& new_positions[*other_orig_idx].col > 0
{
new_positions[*other_orig_idx].col -= 1;
}
}
}
scatter_cursors(self, new_positions);
}
fn record_insert_key(&mut self, k: InsertKey) {
if let Some(r) = self.recording.as_mut() {
r.keys.push(k);
}
}
fn finalize_insert_recording(&mut self) {
if let Some(r) = self.recording.take() {
self.last_change = Some(LastChange::Insert {
trigger: r.trigger,
keys: r.keys,
});
}
}
}
fn collect_cursors(app: &App) -> Vec<(usize, Cursor)> {
std::iter::once((0usize, app.buffer.cursor))
.chain(
app.buffer
.extra_cursors
.iter()
.enumerate()
.map(|(i, c)| (i + 1, *c)),
)
.collect()
}
fn scatter_cursors(app: &mut App, positions: Vec<Cursor>) {
app.buffer.cursor = positions[0];
let primary = positions[0];
let mut extras: Vec<Cursor> = Vec::with_capacity(positions.len() - 1);
for c in positions.into_iter().skip(1) {
if c == primary || extras.contains(&c) {
continue;
}
extras.push(c);
}
app.buffer.extra_cursors = extras;
}