mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
f8b3ab0ce7
commit
f083369183
25 changed files with 596 additions and 336 deletions
56
yazi-core/src/help/commands/arrow.rs
Normal file
56
yazi-core/src/help/commands/arrow.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
21
yazi-core/src/help/commands/escape.rs
Normal file
21
yazi-core/src/help/commands/escape.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
yazi-core/src/help/commands/filter.rs
Normal file
17
yazi-core/src/help/commands/filter.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
3
yazi-core/src/help/commands/mod.rs
Normal file
3
yazi-core/src/help/commands/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
mod arrow;
|
||||||
|
mod escape;
|
||||||
|
mod filter;
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod commands;
|
||||||
mod help;
|
mod help;
|
||||||
|
|
||||||
pub use help::*;
|
pub use help::*;
|
||||||
|
|
|
||||||
35
yazi-core/src/input/commands/backward.rs
Normal file
35
yazi-core/src/input/commands/backward.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
34
yazi-core/src/input/commands/close.rs
Normal file
34
yazi-core/src/input/commands/close.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
35
yazi-core/src/input/commands/delete.rs
Normal file
35
yazi-core/src/input/commands/delete.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
yazi-core/src/input/commands/escape.rs
Normal file
36
yazi-core/src/input/commands/escape.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
42
yazi-core/src/input/commands/forward.rs
Normal file
42
yazi-core/src/input/commands/forward.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
29
yazi-core/src/input/commands/insert.rs
Normal file
29
yazi-core/src/input/commands/insert.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
57
yazi-core/src/input/commands/move_.rs
Normal file
57
yazi-core/src/input/commands/move_.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
31
yazi-core/src/input/commands/paste.rs
Normal file
31
yazi-core/src/input/commands/paste.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
13
yazi-core/src/input/commands/redo.rs
Normal file
13
yazi-core/src/input/commands/redo.rs
Normal 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() }
|
||||||
|
}
|
||||||
21
yazi-core/src/input/commands/undo.rs
Normal file
21
yazi-core/src/input/commands/undo.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
14
yazi-core/src/input/commands/visual.rs
Normal file
14
yazi-core/src/input/commands/visual.rs
Normal 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() }
|
||||||
|
}
|
||||||
30
yazi-core/src/input/commands/yank.rs
Normal file
30
yazi-core/src/input/commands/yank.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
mod arrow;
|
mod arrow;
|
||||||
mod cancel;
|
mod cancel;
|
||||||
mod inspect;
|
mod inspect;
|
||||||
|
mod toggle;
|
||||||
|
|
|
||||||
20
yazi-core/src/tasks/commands/toggle.rs
Normal file
20
yazi-core/src/tasks/commands/toggle.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue