This commit is contained in:
sxyazi 2023-11-10 08:41:58 +08:00
parent f8b3ab0ce7
commit f083369183
No known key found for this signature in database
25 changed files with 596 additions and 336 deletions

View file

@ -0,0 +1,56 @@
use yazi_config::keymap::Exec;
use crate::help::Help;
pub struct Opt {
step: isize,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
}
}
impl From<isize> for Opt {
fn from(step: isize) -> Self { Self { step } }
}
impl Help {
#[inline]
pub fn arrow(&mut self, opt: impl Into<Opt>) -> bool {
let max = self.bindings.len().saturating_sub(1);
self.offset = self.offset.min(max);
self.cursor = self.cursor.min(max);
let opt = opt.into() as Opt;
if opt.step > 0 { self.next(opt.step as usize) } else { self.prev(opt.step.unsigned_abs()) }
}
fn next(&mut self, step: usize) -> bool {
let len = self.bindings.len();
if len == 0 {
return false;
}
let old = self.cursor;
self.cursor = (self.cursor + step).min(len - 1);
let limit = Self::limit();
if self.cursor >= (self.offset + limit).min(len).saturating_sub(5) {
self.offset = len.saturating_sub(limit).min(self.offset + self.cursor - old);
}
old != self.cursor
}
fn prev(&mut self, step: usize) -> bool {
let old = self.cursor;
self.cursor = self.cursor.saturating_sub(step);
if self.cursor < self.offset + 5 {
self.offset = self.offset.saturating_sub(old - self.cursor);
}
old != self.cursor
}
}

View file

@ -0,0 +1,21 @@
use yazi_config::keymap::Exec;
use crate::help::Help;
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Help {
pub fn escape(&mut self, _: impl Into<Opt>) -> bool {
if self.in_filter.is_some() {
self.in_filter = None;
self.filter_apply();
true
} else {
self.toggle(self.layer)
}
}
}

View file

@ -0,0 +1,17 @@
use yazi_config::keymap::Exec;
use crate::help::Help;
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Help {
pub fn filter(&mut self, _: impl Into<Opt>) -> bool {
self.in_filter = Some(Default::default());
self.filter_apply();
true
}
}

View file

@ -0,0 +1,3 @@
mod arrow;
mod escape;
mod filter;

View file

@ -7,16 +7,16 @@ use crate::{emit, input::Input};
#[derive(Default)] #[derive(Default)]
pub struct Help { pub struct Help {
pub visible: bool, pub visible: bool,
pub layer: KeymapLayer, pub layer: KeymapLayer,
bindings: Vec<Control>, pub(super) bindings: Vec<Control>,
// Filter // Filter
keyword: Option<String>, keyword: Option<String>,
in_filter: Option<Input>, pub(super) in_filter: Option<Input>,
offset: usize, pub(super) offset: usize,
cursor: usize, pub(super) cursor: usize,
} }
impl Help { impl Help {
@ -38,60 +38,7 @@ impl Help {
true true
} }
pub fn escape(&mut self) -> bool { pub(super) fn filter_apply(&mut self) -> bool {
if self.in_filter.is_some() {
self.in_filter = None;
self.filter_apply();
true
} else {
self.toggle(self.layer)
}
}
#[inline]
pub fn arrow(&mut self, step: isize) -> bool {
let max = self.bindings.len().saturating_sub(1);
self.offset = self.offset.min(max);
self.cursor = self.cursor.min(max);
if step > 0 { self.next(step as usize) } else { self.prev(step.unsigned_abs()) }
}
pub fn next(&mut self, step: usize) -> bool {
let len = self.bindings.len();
if len == 0 {
return false;
}
let old = self.cursor;
self.cursor = (self.cursor + step).min(len - 1);
let limit = Self::limit();
if self.cursor >= (self.offset + limit).min(len).saturating_sub(5) {
self.offset = len.saturating_sub(limit).min(self.offset + self.cursor - old);
}
old != self.cursor
}
pub fn prev(&mut self, step: usize) -> bool {
let old = self.cursor;
self.cursor = self.cursor.saturating_sub(step);
if self.cursor < self.offset + 5 {
self.offset = self.offset.saturating_sub(old - self.cursor);
}
old != self.cursor
}
pub fn filter(&mut self) -> bool {
self.in_filter = Some(Default::default());
self.filter_apply();
true
}
fn filter_apply(&mut self) -> bool {
let kw = self.in_filter.as_ref().map(|i| i.value()).filter(|v| !v.is_empty()); let kw = self.in_filter.as_ref().map(|i| i.value()).filter(|v| !v.is_empty());
if self.keyword.as_deref() == kw { if self.keyword.as_deref() == kw {
return false; return false;

View file

@ -1,3 +1,4 @@
mod commands;
mod help; mod help;
pub use help::*; pub use help::*;

View file

@ -0,0 +1,35 @@
use yazi_config::keymap::Exec;
use yazi_shared::CharKind;
use crate::input::Input;
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Input {
pub fn backward(&mut self, _: impl Into<Opt>) -> bool {
let snap = self.snap();
if snap.cursor == 0 {
return self.move_(0);
}
let idx = snap.idx(snap.cursor).unwrap_or(snap.len());
let mut it = snap.value[..idx].chars().rev().enumerate();
let mut prev = CharKind::new(it.next().unwrap().1);
for (i, c) in it {
let c = CharKind::new(c);
if prev != CharKind::Space && prev != c {
return self.move_(-(i as isize));
}
prev = c;
}
if prev != CharKind::Space {
return self.move_(-(snap.len() as isize));
}
false
}
}

View file

@ -0,0 +1,34 @@
use yazi_config::keymap::{Exec, KeymapLayer};
use yazi_shared::InputError;
use crate::{emit, input::Input};
pub struct Opt {
submit: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
}
impl From<bool> for Opt {
fn from(submit: bool) -> Self { Self { submit } }
}
impl Input {
pub fn close(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt;
if self.completion {
emit!(Call(Exec::call("close", vec![]).vec(), KeymapLayer::Completion));
}
if let Some(cb) = self.callback.take() {
let value = self.snap_mut().value.clone();
_ = cb.send(if opt.submit { Ok(value) } else { Err(InputError::Canceled(value)) });
}
self.ticket = self.ticket.wrapping_add(1);
self.visible = false;
true
}
}

View file

@ -0,0 +1,35 @@
use yazi_config::keymap::Exec;
use crate::input::{op::InputOp, Input};
pub struct Opt {
cut: bool,
insert: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { cut: e.named.contains_key("cut"), insert: e.named.contains_key("insert") }
}
}
impl Input {
pub fn delete(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt;
match self.snap().op {
InputOp::None => {
self.snap_mut().op = InputOp::Delete(opt.cut, opt.insert, self.snap().cursor);
false
}
InputOp::Select(start) => {
self.snap_mut().op = InputOp::Delete(opt.cut, opt.insert, start);
return self.handle_op(self.snap().cursor, true).then(|| self.move_(0)).is_some();
}
InputOp::Delete(..) => {
self.snap_mut().op = InputOp::Delete(opt.cut, opt.insert, 0);
return self.move_(self.snap().len() as isize);
}
_ => false,
}
}
}

View file

@ -0,0 +1,36 @@
use yazi_config::keymap::{Exec, KeymapLayer};
use crate::{emit, input::{op::InputOp, Input, InputMode}};
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl From<()> for Opt {
fn from(_: ()) -> Self { Self }
}
impl Input {
pub fn escape(&mut self, _: impl Into<Opt>) -> bool {
let snap = self.snap_mut();
match snap.mode {
InputMode::Normal if snap.op == InputOp::None => {
self.close(false);
}
InputMode::Normal => {
snap.op = InputOp::None;
}
InputMode::Insert => {
snap.mode = InputMode::Normal;
self.move_(-1);
if self.completion {
emit!(Call(Exec::call("close", vec![]).vec(), KeymapLayer::Completion));
}
}
}
self.snaps.tag();
true
}
}

View file

@ -0,0 +1,42 @@
use yazi_config::keymap::Exec;
use yazi_shared::CharKind;
use crate::input::{op::InputOp, Input};
pub struct Opt {
end_of_word: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { end_of_word: e.named.contains_key("end-of-word") } }
}
impl Input {
pub fn forward(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt;
let snap = self.snap();
if snap.value.is_empty() {
return self.move_(0);
}
let mut it = snap.value.chars().skip(snap.cursor).enumerate();
let mut prev = CharKind::new(it.next().unwrap().1);
for (i, c) in it {
let c = CharKind::new(c);
let b = if opt.end_of_word {
prev != CharKind::Space && prev != c && i != 1
} else {
c != CharKind::Space && c != prev
};
if b && !matches!(snap.op, InputOp::None | InputOp::Select(_)) {
return self.move_(i as isize);
} else if b {
return self.move_(if opt.end_of_word { i - 1 } else { i } as isize);
}
prev = c;
}
self.move_(snap.len() as isize)
}
}

View file

@ -0,0 +1,29 @@
use yazi_config::keymap::Exec;
use crate::input::Input;
pub struct Opt {
append: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { append: e.named.contains_key("append") } }
}
impl From<bool> for Opt {
fn from(append: bool) -> Self { Self { append } }
}
impl Input {
pub fn insert(&mut self, opt: impl Into<Opt>) -> bool {
if !self.snap_mut().insert() {
return false;
}
let opt = opt.into() as Opt;
if opt.append {
self.move_(1);
}
true
}
}

View file

@ -1 +1,13 @@
mod backward;
mod close;
mod complete; mod complete;
mod delete;
mod escape;
mod forward;
mod insert;
mod move_;
mod paste;
mod redo;
mod undo;
mod visual;
mod yank;

View file

@ -0,0 +1,57 @@
use unicode_width::UnicodeWidthStr;
use yazi_config::keymap::Exec;
use crate::input::{op::InputOp, snap::InputSnap, Input};
pub struct Opt {
step: isize,
in_operating: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self {
step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0),
in_operating: e.named.contains_key("in-operating"),
}
}
}
impl From<isize> for Opt {
fn from(step: isize) -> Self { Self { step, in_operating: false } }
}
impl Input {
pub fn move_(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt;
let snap = self.snap();
if opt.in_operating && snap.op == InputOp::None {
return false;
}
let b = self.handle_op(
if opt.step <= 0 {
snap.cursor.saturating_sub(opt.step.unsigned_abs())
} else {
snap.count().min(snap.cursor + opt.step as usize)
},
false,
);
let snap = self.snap_mut();
if snap.cursor < snap.offset {
snap.offset = snap.cursor;
} else if snap.value.is_empty() {
snap.offset = 0;
} else {
let delta = snap.mode.delta();
let s = snap.slice(snap.offset..snap.cursor + delta);
if s.width() >= /*TODO: hardcode*/ 50 - 2 {
let s = s.chars().rev().collect::<String>();
snap.offset = snap.cursor - InputSnap::find_window(&s, 0).end.saturating_sub(delta);
}
}
b
}
}

View file

@ -0,0 +1,31 @@
use yazi_config::keymap::Exec;
use crate::{external, input::{op::InputOp, Input}};
pub struct Opt {
before: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { before: e.named.contains_key("before") } }
}
impl Input {
pub fn paste(&mut self, opt: impl Into<Opt>) -> bool {
if let Some(start) = self.snap().op.start() {
self.snap_mut().op = InputOp::Delete(false, false, start);
self.handle_op(self.snap().cursor, true);
}
let s = futures::executor::block_on(external::clipboard_get()).unwrap_or_default();
if s.is_empty() {
return false;
}
let opt = opt.into() as Opt;
self.insert(!opt.before);
self.type_str(&s.to_string_lossy());
self.escape(());
true
}
}

View file

@ -0,0 +1,13 @@
use yazi_config::keymap::Exec;
use crate::input::Input;
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Input {
pub fn redo(&mut self, _: impl Into<Opt>) -> bool { self.snaps.redo() }
}

View file

@ -0,0 +1,21 @@
use yazi_config::keymap::Exec;
use crate::input::{Input, InputMode};
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Input {
pub fn undo(&mut self, _: impl Into<Opt>) -> bool {
if !self.snaps.undo() {
return false;
}
if self.snap().mode == InputMode::Insert {
self.escape(());
}
true
}
}

View file

@ -0,0 +1,14 @@
use yazi_config::keymap::Exec;
use crate::input::Input;
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Input {
#[inline]
pub fn visual(&mut self, _: impl Into<Opt>) -> bool { self.snap_mut().visual() }
}

View file

@ -0,0 +1,30 @@
use yazi_config::keymap::Exec;
use crate::input::{op::InputOp, Input};
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Input {
pub fn yank(&mut self, _: impl Into<Opt>) -> bool {
match self.snap().op {
InputOp::None => {
self.snap_mut().op = InputOp::Yank(self.snap().cursor);
false
}
InputOp::Select(start) => {
self.snap_mut().op = InputOp::Yank(start);
return self.handle_op(self.snap().cursor, true).then(|| self.move_(0)).is_some();
}
InputOp::Yank(_) => {
self.snap_mut().op = InputOp::Yank(0);
self.move_(self.snap().len() as isize);
false
}
_ => false,
}
}
}

View file

@ -3,11 +3,11 @@ use std::ops::Range;
use crossterm::event::KeyCode; use crossterm::event::KeyCode;
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use yazi_config::keymap::{Exec, Key, KeymapLayer}; use yazi_config::keymap::Key;
use yazi_shared::{CharKind, InputError}; use yazi_shared::InputError;
use super::{mode::InputMode, op::InputOp, InputOpt, InputSnap, InputSnaps}; use super::{mode::InputMode, op::InputOp, InputOpt, InputSnap, InputSnaps};
use crate::{emit, external, Position}; use crate::{external, Position};
#[derive(Default)] #[derive(Default)]
pub struct Input { pub struct Input {
@ -19,9 +19,9 @@ pub struct Input {
pub position: Position, pub position: Position,
// Typing // Typing
callback: Option<UnboundedSender<Result<String, InputError>>>, pub(super) callback: Option<UnboundedSender<Result<String, InputError>>>,
realtime: bool, realtime: bool,
completion: bool, pub(super) completion: bool,
// Shell // Shell
pub(super) highlight: bool, pub(super) highlight: bool,
@ -45,157 +45,6 @@ impl Input {
self.highlight = opt.highlight; self.highlight = opt.highlight;
} }
pub fn close(&mut self, submit: bool) -> bool {
if self.completion {
emit!(Call(Exec::call("close", vec![]).vec(), KeymapLayer::Completion));
}
if let Some(cb) = self.callback.take() {
let value = self.snap_mut().value.clone();
_ = cb.send(if submit { Ok(value) } else { Err(InputError::Canceled(value)) });
}
self.ticket = self.ticket.wrapping_add(1);
self.visible = false;
true
}
pub fn escape(&mut self) -> bool {
let snap = self.snap_mut();
match snap.mode {
InputMode::Normal if snap.op == InputOp::None => {
self.close(false);
}
InputMode::Normal => {
snap.op = InputOp::None;
}
InputMode::Insert => {
snap.mode = InputMode::Normal;
self.move_(-1);
if self.completion {
emit!(Call(Exec::call("close", vec![]).vec(), KeymapLayer::Completion));
}
}
}
self.snaps.tag();
true
}
pub fn insert(&mut self, append: bool) -> bool {
if !self.snap_mut().insert() {
return false;
}
if append {
self.move_(1);
}
true
}
#[inline]
pub fn visual(&mut self) -> bool { self.snap_mut().visual() }
#[inline]
pub fn undo(&mut self) -> bool {
if !self.snaps.undo() {
return false;
}
if self.snap().mode == InputMode::Insert {
self.escape();
}
true
}
#[inline]
pub fn redo(&mut self) -> bool {
if !self.snaps.redo() {
return false;
}
true
}
pub fn move_(&mut self, step: isize) -> bool {
let snap = self.snap();
let b = self.handle_op(
if step <= 0 {
snap.cursor.saturating_sub(step.unsigned_abs())
} else {
snap.count().min(snap.cursor + step as usize)
},
false,
);
let snap = self.snap_mut();
if snap.cursor < snap.offset {
snap.offset = snap.cursor;
} else if snap.value.is_empty() {
snap.offset = 0;
} else {
let delta = snap.mode.delta();
let s = snap.slice(snap.offset..snap.cursor + delta);
if s.width() >= /*TODO: hardcode*/ 50 - 2 {
let s = s.chars().rev().collect::<String>();
snap.offset = snap.cursor - InputSnap::find_window(&s, 0).end.saturating_sub(delta);
}
}
b
}
#[inline]
pub fn move_in_operating(&mut self, step: isize) -> bool {
if self.snap_mut().op == InputOp::None { false } else { self.move_(step) }
}
pub fn backward(&mut self) -> bool {
let snap = self.snap();
if snap.cursor == 0 {
return self.move_(0);
}
let idx = snap.idx(snap.cursor).unwrap_or(snap.len());
let mut it = snap.value[..idx].chars().rev().enumerate();
let mut prev = CharKind::new(it.next().unwrap().1);
for (i, c) in it {
let c = CharKind::new(c);
if prev != CharKind::Space && prev != c {
return self.move_(-(i as isize));
}
prev = c;
}
if prev != CharKind::Space {
return self.move_(-(snap.len() as isize));
}
false
}
pub fn forward(&mut self, end: bool) -> bool {
let snap = self.snap();
if snap.value.is_empty() {
return self.move_(0);
}
let mut it = snap.value.chars().skip(snap.cursor).enumerate();
let mut prev = CharKind::new(it.next().unwrap().1);
for (i, c) in it {
let c = CharKind::new(c);
let b = if end {
prev != CharKind::Space && prev != c && i != 1
} else {
c != CharKind::Space && c != prev
};
if b && !matches!(snap.op, InputOp::None | InputOp::Select(_)) {
return self.move_(i as isize);
} else if b {
return self.move_(if end { i - 1 } else { i } as isize);
}
prev = c;
}
self.move_(snap.len() as isize)
}
pub fn type_(&mut self, key: &Key) -> bool { pub fn type_(&mut self, key: &Key) -> bool {
if self.mode() != InputMode::Insert { if self.mode() != InputMode::Insert {
return false; return false;
@ -238,61 +87,7 @@ impl Input {
true true
} }
pub fn delete(&mut self, cut: bool, insert: bool) -> bool { pub(super) fn handle_op(&mut self, cursor: usize, include: bool) -> bool {
match self.snap().op {
InputOp::None => {
self.snap_mut().op = InputOp::Delete(cut, insert, self.snap().cursor);
false
}
InputOp::Select(start) => {
self.snap_mut().op = InputOp::Delete(cut, insert, start);
return self.handle_op(self.snap().cursor, true).then(|| self.move_(0)).is_some();
}
InputOp::Delete(..) => {
self.snap_mut().op = InputOp::Delete(cut, insert, 0);
return self.move_(self.snap().len() as isize);
}
_ => false,
}
}
pub fn yank(&mut self) -> bool {
match self.snap().op {
InputOp::None => {
self.snap_mut().op = InputOp::Yank(self.snap().cursor);
false
}
InputOp::Select(start) => {
self.snap_mut().op = InputOp::Yank(start);
return self.handle_op(self.snap().cursor, true).then(|| self.move_(0)).is_some();
}
InputOp::Yank(_) => {
self.snap_mut().op = InputOp::Yank(0);
self.move_(self.snap().len() as isize);
false
}
_ => false,
}
}
pub fn paste(&mut self, before: bool) -> bool {
if let Some(start) = self.snap().op.start() {
self.snap_mut().op = InputOp::Delete(false, false, start);
self.handle_op(self.snap().cursor, true);
}
let s = futures::executor::block_on(external::clipboard_get()).unwrap_or_default();
if s.is_empty() {
return false;
}
self.insert(!before);
self.type_str(&s.to_string_lossy());
self.escape();
true
}
fn handle_op(&mut self, cursor: usize, include: bool) -> bool {
let old = self.snap().clone(); let old = self.snap().clone();
let snap = self.snaps.current_mut(); let snap = self.snaps.current_mut();
@ -384,8 +179,8 @@ impl Input {
} }
#[inline] #[inline]
fn snap(&self) -> &InputSnap { self.snaps.current() } pub(super) fn snap(&self) -> &InputSnap { self.snaps.current() }
#[inline] #[inline]
fn snap_mut(&mut self) -> &mut InputSnap { self.snaps.current_mut() } pub(super) fn snap_mut(&mut self) -> &mut InputSnap { self.snaps.current_mut() }
} }

View file

@ -61,7 +61,7 @@ impl Tab {
true true
} }
pub fn cd_interactive(&mut self, opt: impl Into<Opt>) -> bool { fn cd_interactive(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
tokio::spawn(async move { tokio::spawn(async move {

View file

@ -1,3 +1,4 @@
mod arrow; mod arrow;
mod cancel; mod cancel;
mod inspect; mod inspect;
mod toggle;

View file

@ -0,0 +1,20 @@
use yazi_config::keymap::Exec;
use crate::{emit, tasks::Tasks};
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl From<()> for Opt {
fn from(_: ()) -> Self { Self }
}
impl Tasks {
pub fn toggle(&mut self, _: impl Into<Opt>) -> bool {
self.visible = !self.visible;
emit!(Peek); // Show/hide preview for images
true
}
}

View file

@ -31,12 +31,6 @@ impl Tasks {
(Term::size().rows * TASKS_PERCENT / 100).saturating_sub(TASKS_PADDING) as usize (Term::size().rows * TASKS_PERCENT / 100).saturating_sub(TASKS_PADDING) as usize
} }
pub fn toggle(&mut self) -> bool {
self.visible = !self.visible;
emit!(Peek); // Show/hide preview for images
true
}
pub fn paginate(&self) -> Vec<TaskSummary> { pub fn paginate(&self) -> Vec<TaskSummary> {
let running = self.scheduler.running.read(); let running = self.scheduler.running.read();
running.values().take(Self::limit()).map(Into::into).collect() running.values().take(Self::limit()).map(Into::into).collect()

View file

@ -138,7 +138,7 @@ impl<'a> Executor<'a> {
match exec.cmd.as_bytes() { match exec.cmd.as_bytes() {
// Tasks // Tasks
b"tasks_show" => self.cx.tasks.toggle(), b"tasks_show" => self.cx.tasks.toggle(()),
// Help // Help
b"help" => self.cx.help.toggle(KeymapLayer::Manager), b"help" => self.cx.help.toggle(KeymapLayer::Manager),
_ => false, _ => false,
@ -152,14 +152,19 @@ impl<'a> Executor<'a> {
return self.cx.tasks.$name(exec); return self.cx.tasks.$name(exec);
} }
}; };
($name:ident, $alias:literal) => {
if exec.cmd == $alias {
return self.cx.tasks.$name(exec);
}
};
} }
on!(toggle, "close");
on!(arrow); on!(arrow);
on!(inspect); on!(inspect);
on!(cancel); on!(cancel);
match exec.cmd.as_str() { match exec.cmd.as_str() {
"close" => self.cx.tasks.toggle(),
"help" => self.cx.help.toggle(KeymapLayer::Tasks), "help" => self.cx.help.toggle(KeymapLayer::Tasks),
_ => false, _ => false,
} }
@ -184,78 +189,89 @@ impl<'a> Executor<'a> {
} }
fn input(&mut self, exec: &Exec) -> bool { fn input(&mut self, exec: &Exec) -> bool {
match exec.cmd.as_str() { macro_rules! on {
"close" => return self.cx.input.close(exec.named.contains_key("submit")), ($name:ident) => {
"escape" => return self.cx.input.escape(), if exec.cmd == stringify!($name) {
return self.cx.input.$name(exec);
}
};
($name:ident, $alias:literal) => {
if exec.cmd == $alias {
return self.cx.input.$name(exec);
}
};
}
"move" => { on!(close);
let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); on!(escape);
let in_operating = exec.named.contains_key("in-operating"); on!(move_, "move");
return if in_operating {
self.cx.input.move_in_operating(step)
} else {
self.cx.input.move_(step)
};
}
"complete" => { if exec.cmd.as_str() == "complete" {
return if exec.args.is_empty() { return if exec.args.is_empty() {
self.cx.completion.trigger(exec) self.cx.completion.trigger(exec)
} else { } else {
self.cx.input.complete(exec) self.cx.input.complete(exec)
}; };
}
_ => {}
} }
match self.cx.input.mode() { match self.cx.input.mode() {
InputMode::Normal => match exec.cmd.as_str() { InputMode::Normal => {
"insert" => self.cx.input.insert(exec.named.contains_key("append")), on!(insert);
"visual" => self.cx.input.visual(), on!(visual);
"backward" => self.cx.input.backward(), on!(backward);
"forward" => self.cx.input.forward(exec.named.contains_key("end-of-word")), on!(forward);
"delete" => { on!(delete);
self.cx.input.delete(exec.named.contains_key("cut"), exec.named.contains_key("insert"))
on!(yank);
on!(paste);
on!(undo);
on!(redo);
match exec.cmd.as_str() {
"help" => self.cx.help.toggle(KeymapLayer::Input),
_ => false,
} }
}
"yank" => self.cx.input.yank(),
"paste" => self.cx.input.paste(exec.named.contains_key("before")),
"undo" => self.cx.input.undo(),
"redo" => self.cx.input.redo(),
"help" => self.cx.help.toggle(KeymapLayer::Input),
_ => false,
},
InputMode::Insert => false, InputMode::Insert => false,
} }
} }
fn help(&mut self, exec: &Exec) -> bool { fn help(&mut self, exec: &Exec) -> bool {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
return self.cx.help.$name(exec);
}
};
}
on!(escape);
on!(arrow);
on!(filter);
match exec.cmd.as_str() { match exec.cmd.as_str() {
"close" => self.cx.help.toggle(KeymapLayer::Help), "close" => self.cx.help.toggle(KeymapLayer::Help),
"escape" => self.cx.help.escape(),
"arrow" => {
let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0);
self.cx.help.arrow(step)
}
"filter" => self.cx.help.filter(),
_ => false, _ => false,
} }
} }
fn completion(&mut self, exec: &Exec) -> bool { fn completion(&mut self, exec: &Exec) -> bool {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
return self.cx.completion.$name(exec);
}
};
}
on!(trigger);
on!(show);
on!(close);
on!(arrow);
match exec.cmd.as_str() { match exec.cmd.as_str() {
"trigger" => self.cx.completion.trigger(exec),
"show" => self.cx.completion.show(exec),
"close" => self.cx.completion.close(exec),
"arrow" => self.cx.completion.arrow(exec),
"help" => self.cx.help.toggle(KeymapLayer::Completion), "help" => self.cx.help.toggle(KeymapLayer::Completion),
_ => false, _ => false,
} }