#[cfg(feature = "keybindings")]
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
#[cfg(all(feature = "keybindings", feature = "commandline"))]
use crate::commandline::CommandLineEventOutcome;
#[cfg(feature = "keybindings")]
use crate::{
canvas::modes::AppMode,
editor::{
behavior::KeybindingParadigm,
product::{KeybindingProduct, handle_product_key_event},
},
keybindings::{CanvasKeyAction, KeyEventOutcome},
textarea::{TextAreaDataProvider, TextAreaState},
};
#[cfg(feature = "keybindings")]
impl<P: TextAreaDataProvider> TextAreaState<P> {
pub fn handle_key_event(&mut self, evt: KeyEvent) -> KeyEventOutcome {
if self.core.keybinding_paradigm().is_helix() {
if let Some(pending) = self.helix_pending {
if evt.kind != KeyEventKind::Press {
return KeyEventOutcome::Consumed(None);
}
self.helix_pending = None;
if let KeyCode::Char(ch) = evt.code {
if !evt.modifiers.contains(KeyModifiers::CONTROL)
&& !evt.modifiers.contains(KeyModifiers::ALT)
{
self.resolve_helix_pending(pending, ch);
}
}
return KeyEventOutcome::Consumed(None);
}
}
if self.core.keybinding_paradigm() == KeybindingParadigm::Vim {
if let Some(pending) = self.vim_pending {
if evt.kind != KeyEventKind::Press {
return KeyEventOutcome::Consumed(None);
}
self.vim_pending = None;
let mut resolved = false;
if let KeyCode::Char(ch) = evt.code {
if !evt.modifiers.contains(KeyModifiers::CONTROL)
&& !evt.modifiers.contains(KeyModifiers::ALT)
{
self.resolve_vim_pending(pending, ch);
resolved = true;
}
}
if let Some(op) = self.core.behavior_state.vim().pending_operator() {
self.core.behavior_state.vim_mut().clear_pending_operator();
if resolved {
if let crate::textarea::actions::selection::vim::VimPending::Find {
forward,
..
} = pending
{
self.finish_operator_charwise_vim(op.operator, op.anchor, forward);
}
}
}
return KeyEventOutcome::Consumed(None);
}
}
#[cfg(feature = "commandline")]
{
let should_route_commandline = self
.commandline
.as_ref()
.map(|commandline| {
commandline.state().is_active()
|| matches!(self.mode(), AppMode::Nor | AppMode::Sel)
})
.unwrap_or(false);
if should_route_commandline {
let outcome = self
.commandline
.as_mut()
.expect("checked commandline presence")
.state_mut()
.input_key(evt);
match outcome {
CommandLineEventOutcome::Ignored => {}
CommandLineEventOutcome::Handled | CommandLineEventOutcome::Cancelled => {
return KeyEventOutcome::Consumed(None);
}
CommandLineEventOutcome::Submitted(submit) => {
self.apply_default_commandline_submit(submit);
return KeyEventOutcome::Consumed(None);
}
}
}
}
handle_product_key_event(self, evt)
}
pub fn is_sequence_pending(&self) -> bool {
self.core.is_sequence_pending()
|| self.vim_pending.is_some()
|| self.helix_pending.is_some()
}
fn dispatch_textarea_key_action(
&mut self,
action: &CanvasKeyAction,
count: usize,
) -> KeyEventOutcome {
match self.core.keybinding_paradigm() {
KeybindingParadigm::Helix => self.dispatch_textarea_key_action_helix(action, count),
KeybindingParadigm::Emacs => self.dispatch_textarea_key_action_emacs(action, count),
KeybindingParadigm::Vscode => self.dispatch_textarea_key_action_vscode(action, count),
KeybindingParadigm::Vim => self.dispatch_textarea_key_action_vim(action, count),
}
}
}
#[cfg(feature = "keybindings")]
impl<P: TextAreaDataProvider> KeybindingProduct for TextAreaState<P> {
type Provider = P;
fn core(&self) -> &crate::editor::EditorCore<Self::Provider> {
&self.core
}
fn core_mut(&mut self) -> &mut crate::editor::EditorCore<Self::Provider> {
&mut self.core
}
fn handle_insert_enter(&mut self) -> KeyEventOutcome {
if self.core.keybinding_paradigm() == KeybindingParadigm::Vscode
&& self.vscode_selection_active()
{
self.vscode_delete_selection();
}
self.insert_newline();
KeyEventOutcome::Consumed(None)
}
fn handle_insert_tab(&mut self) -> KeyEventOutcome {
self.insert_tab_spaces();
KeyEventOutcome::Consumed(None)
}
fn handle_plain_insert_char(&mut self, ch: char) -> KeyEventOutcome {
if self.core.keybinding_paradigm() == KeybindingParadigm::Vscode
&& self.vscode_selection_active()
{
self.vscode_delete_selection();
}
self.enter_edit_mode();
#[cfg(feature = "gui")]
{
self.edited_this_frame = true;
}
if self.insert_char(ch).is_ok() {
KeyEventOutcome::Consumed(None)
} else {
KeyEventOutcome::NotMatched
}
}
fn dispatch_product_key_action(
&mut self,
action: &CanvasKeyAction,
count: usize,
) -> KeyEventOutcome {
self.dispatch_textarea_key_action(action, count)
}
}