mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat: render selected range
This commit is contained in:
parent
b8d9014d83
commit
9f93c6f34e
9 changed files with 93 additions and 32 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -1511,18 +1511,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.171"
|
||||
version = "1.0.173"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
|
||||
checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.171"
|
||||
version = "1.0.173"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682"
|
||||
checksum = "a6250dde8342e0232232be9ca3db7aa40aceb5a3e5dd9bddbc00d99a007cde49"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1560,9 +1560,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.16"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b824b6e687aff278cdbf3b36f07aa52d4bd4099699324d5da86a2ebce3aa00b3"
|
||||
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
|
|
|
|||
|
|
@ -130,5 +130,5 @@ keymap = [
|
|||
|
||||
{ on = [ "d" ], exec = "delete" },
|
||||
{ on = [ "c" ], exec = "delete --insert" },
|
||||
{ on = [ "x" ], exec = [ "delete", "move 1" ] }
|
||||
{ on = [ "x" ], exec = [ "delete", "move 1 --in-operating" ] }
|
||||
]
|
||||
|
|
|
|||
|
|
@ -114,22 +114,23 @@
|
|||
|
||||
## input
|
||||
|
||||
### Normal mode
|
||||
|
||||
- close: Cancel input.
|
||||
|
||||
- `--submit`: Submit the input.
|
||||
|
||||
- escape: Cancel visual mode and enter normal mode.
|
||||
- move: Move the cursor left or right.
|
||||
|
||||
- `n`: Move the cursor n characters left or right. Negative value for left, positive value for right.
|
||||
- `--in-operating`: Move the cursor only if its currently waiting for an operation.
|
||||
|
||||
### Normal mode
|
||||
|
||||
- insert: Enter insert mode.
|
||||
|
||||
- `--append`: Insert after the cursor.
|
||||
|
||||
- visual: Enter visual mode.
|
||||
- move: Move the cursor left or right.
|
||||
|
||||
- `n`: Move the cursor n characters left or right. Negative value for left, positive value for right.
|
||||
|
||||
- backward: Move to the beginning of the previous word.
|
||||
- forward: Move to the beginning of the next word.
|
||||
|
||||
|
|
|
|||
|
|
@ -44,8 +44,9 @@ Available parameters are as follows:
|
|||
|
||||
- cmd: The program to open the selected files
|
||||
- args: Arguments to be passed
|
||||
- `$n`: The n-th selected item
|
||||
- `$*`: All selected files
|
||||
- `"$n"`: The N-th selected file
|
||||
- `"$*"`: All selected files
|
||||
- `"foo"`: Literal string to be passed
|
||||
- block: Open in a blocking manner. After setting this, Yazi will hide into a secondary screen and display the program on the main screen until it exits. During this time, it can receive I/O signals, which is useful for interactive programs.
|
||||
|
||||
## open
|
||||
|
|
|
|||
|
|
@ -11,6 +11,16 @@ pub struct Key {
|
|||
pub alt: bool,
|
||||
}
|
||||
|
||||
impl Key {
|
||||
#[inline]
|
||||
pub fn plain(&self) -> Option<char> {
|
||||
match self.code {
|
||||
KeyCode::Char(c) if !self.ctrl && !self.alt => Some(c),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Key {
|
||||
fn default() -> Self { Self { code: KeyCode::Null, shift: false, ctrl: false, alt: false } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ impl Input {
|
|||
let _ = cb.send(if submit { Ok(self.value.clone()) } else { Err(anyhow!("canceled")) });
|
||||
}
|
||||
|
||||
self.op = InputOp::None;
|
||||
self.range = None;
|
||||
|
||||
self.mode = InputMode::Insert;
|
||||
self.visible = false;
|
||||
true
|
||||
|
|
@ -131,6 +134,11 @@ impl Input {
|
|||
self.handle_op(include) || self.cursor != old
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn move_in_operating(&mut self, step: isize) -> bool {
|
||||
if self.op == InputOp::None { false } else { self.move_(step) }
|
||||
}
|
||||
|
||||
pub fn backward(&mut self) -> bool {
|
||||
if self.cursor == 0 {
|
||||
return self.handle_op(false);
|
||||
|
|
@ -282,6 +290,37 @@ impl Input {
|
|||
(area.x + width + 1, area.y + 1)
|
||||
}
|
||||
|
||||
pub fn range(&self) -> Option<Rect> {
|
||||
if let Some((start, end)) = self.range {
|
||||
let end = self
|
||||
.value
|
||||
.chars()
|
||||
.skip(start)
|
||||
.enumerate()
|
||||
.take_while(|(i, _)| *i < end)
|
||||
.map(|(_, c)| c)
|
||||
.collect::<String>()
|
||||
.width() as u16;
|
||||
|
||||
let start = self
|
||||
.value
|
||||
.chars()
|
||||
.enumerate()
|
||||
.take_while(|(i, _)| *i < start)
|
||||
.map(|(_, c)| c)
|
||||
.collect::<String>()
|
||||
.width() as u16;
|
||||
|
||||
return Some(Rect {
|
||||
x: self.position.0 + 1 + start,
|
||||
y: self.position.1 + 3,
|
||||
width: end,
|
||||
height: 1,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(&self) -> usize { self.value.chars().count() }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![feature(if_let_guard)]
|
||||
|
||||
use ui::App;
|
||||
|
||||
mod config;
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ impl Executor {
|
|||
} else if layer == 2 {
|
||||
render = Self::select(cx, e) || render;
|
||||
} else if layer == 3 {
|
||||
render = Self::input(cx, Some(e), key.code) || render;
|
||||
render = Self::input(cx, Some(e), &key) || render;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if layer == 3 && !matched {
|
||||
render = Self::input(cx, None, key.code);
|
||||
render = Self::input(cx, None, &key);
|
||||
}
|
||||
render
|
||||
}
|
||||
|
|
@ -166,27 +166,34 @@ impl Executor {
|
|||
}
|
||||
}
|
||||
|
||||
fn input(cx: &mut Ctx, exec: Option<&Exec>, code: KeyCode) -> bool {
|
||||
fn input(cx: &mut Ctx, exec: Option<&Exec>, key: &Key) -> bool {
|
||||
let exec = if let Some(e) = exec {
|
||||
e
|
||||
} else {
|
||||
if cx.input.mode() == InputMode::Insert {
|
||||
if let KeyCode::Char(c) = code {
|
||||
if let KeyCode::Char(c) = key.code {
|
||||
return cx.input.type_(c);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
match exec.cmd.as_str() {
|
||||
"close" => return cx.input.close(exec.named.contains_key("submit")),
|
||||
"escape" => return cx.input.escape(),
|
||||
if cx.input.mode() != InputMode::Insert || key.plain().is_none() {
|
||||
match exec.cmd.as_str() {
|
||||
"close" => return cx.input.close(exec.named.contains_key("submit")),
|
||||
"escape" => return cx.input.escape(),
|
||||
|
||||
"move" => {
|
||||
let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
return cx.input.move_(step);
|
||||
"move" => {
|
||||
let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
let in_operating = exec.named.contains_key("in-operating");
|
||||
return if in_operating {
|
||||
cx.input.move_in_operating(step)
|
||||
} else {
|
||||
cx.input.move_(step)
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match cx.input.mode() {
|
||||
|
|
@ -200,13 +207,10 @@ impl Executor {
|
|||
_ => false,
|
||||
},
|
||||
InputMode::Insert => match exec.cmd.as_str() {
|
||||
_ if let Some(c) = key.plain() => cx.input.type_(c),
|
||||
|
||||
"backspace" => cx.input.backspace(),
|
||||
_ => {
|
||||
if let KeyCode::Char(c) = code {
|
||||
return cx.input.type_(c);
|
||||
}
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ impl<'a> Widget for Input<'a> {
|
|||
.style(Style::default().fg(Color::White))
|
||||
.render(area, buf);
|
||||
|
||||
if let Some(range) = input.range() {
|
||||
buf.set_style(range, Style::default().bg(Color::Rgb(72, 77, 102)))
|
||||
}
|
||||
|
||||
let _ = match input.mode() {
|
||||
InputMode::Insert => Term::set_cursor_bar(),
|
||||
_ => Term::set_cursor_block(),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue