mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
a4a869464a
commit
4f40977f1f
19 changed files with 183 additions and 163 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -3483,7 +3483,6 @@ dependencies = [
|
|||
"ratatui",
|
||||
"scopeguard",
|
||||
"signal-hook-tokio",
|
||||
"syntect",
|
||||
"textwrap",
|
||||
"tikv-jemallocator",
|
||||
"tokio",
|
||||
|
|
@ -3637,6 +3636,7 @@ name = "yazi-widgets"
|
|||
version = "25.3.7"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"ratatui",
|
||||
"unicode-width 0.2.0",
|
||||
"yazi-codegen",
|
||||
"yazi-config",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ regex = "1.11.1"
|
|||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.219", features = [ "derive" ] }
|
||||
serde_json = "1.0.140"
|
||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
tokio = { version = "1.44.1", features = [ "full" ] }
|
||||
tokio-stream = "0.1.17"
|
||||
tokio-util = "0.7.14"
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
use yazi_config::popup::{Offset, Origin, Position};
|
||||
use yazi_macro::render;
|
||||
use yazi_shared::event::CmdCow;
|
||||
|
||||
use crate::{help::Help, input::Input};
|
||||
use crate::help::Help;
|
||||
|
||||
impl Help {
|
||||
pub fn filter(&mut self, _: CmdCow) {
|
||||
let mut input = Input::default();
|
||||
input.position = Position::new(Origin::BottomLeft, Offset::line());
|
||||
|
||||
self.in_filter = Some(input);
|
||||
self.in_filter = Some(Default::default());
|
||||
self.filter_apply();
|
||||
render!();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use crossterm::event::KeyCode;
|
||||
use crossterm::{cursor::SetCursorStyle, event::KeyCode};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use yazi_adapter::Dimension;
|
||||
use yazi_config::{KEYMAP, keymap::{Chord, Key}};
|
||||
use yazi_config::{INPUT, KEYMAP, keymap::{Chord, Key}};
|
||||
use yazi_macro::{render, render_and};
|
||||
use yazi_shared::Layer;
|
||||
|
||||
use super::HELP_MARGIN;
|
||||
use crate::input::Input;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Help {
|
||||
|
|
@ -16,7 +15,7 @@ pub struct Help {
|
|||
|
||||
// Filter
|
||||
pub(super) keyword: String,
|
||||
pub(super) in_filter: Option<Input>,
|
||||
pub(super) in_filter: Option<yazi_widgets::input::Input>,
|
||||
|
||||
pub(super) offset: usize,
|
||||
pub(super) cursor: usize,
|
||||
|
|
@ -89,7 +88,7 @@ impl Help {
|
|||
.as_ref()
|
||||
.map(|i| i.value())
|
||||
.or(Some(self.keyword.as_str()).filter(|&s| !s.is_empty()))
|
||||
.map(|s| format!("Filter: {}", s))
|
||||
.map(|s| format!("Filter: {s}"))
|
||||
}
|
||||
|
||||
// --- Bindings
|
||||
|
|
@ -113,4 +112,9 @@ impl Help {
|
|||
|
||||
#[inline]
|
||||
pub fn rel_cursor(&self) -> usize { self.cursor - self.offset }
|
||||
|
||||
#[inline]
|
||||
pub fn cursor_shape(&self) -> SetCursorStyle {
|
||||
if INPUT.cursor_blink { SetCursorStyle::BlinkingBlock } else { SetCursorStyle::SteadyBlock }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ indexmap = { workspace = true }
|
|||
mlua = { workspace = true }
|
||||
ratatui = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use std::sync::atomic::Ordering;
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use crossterm::{execute, queue, terminal::{BeginSynchronizedUpdate, EndSynchronizedUpdate}};
|
||||
use ratatui::{CompletedFrame, backend::{Backend, CrosstermBackend}, buffer::Buffer};
|
||||
use scopeguard::defer;
|
||||
use crossterm::{cursor::{MoveTo, SetCursorStyle, Show}, execute, queue, terminal::{BeginSynchronizedUpdate, EndSynchronizedUpdate}};
|
||||
use ratatui::{CompletedFrame, backend::{Backend, CrosstermBackend}, buffer::Buffer, layout::Position};
|
||||
use yazi_plugin::elements::COLLISION;
|
||||
use yazi_shared::{event::NEED_RENDER, tty::TTY};
|
||||
|
||||
|
|
@ -13,22 +12,18 @@ impl App {
|
|||
NEED_RENDER.store(false, Ordering::Relaxed);
|
||||
let Some(term) = &mut self.term else { return };
|
||||
|
||||
queue!(TTY.writer(), BeginSynchronizedUpdate).ok();
|
||||
defer! { execute!(TTY.writer(), EndSynchronizedUpdate).ok(); }
|
||||
Self::routine(true, None);
|
||||
let _guard = scopeguard::guard(self.cx.cursor(), |c| Self::routine(false, c));
|
||||
|
||||
let collision = COLLISION.swap(false, Ordering::Relaxed);
|
||||
let frame = term
|
||||
.draw(|f| {
|
||||
_ = Lives::scope(&self.cx, || Ok(f.render_widget(Root::new(&self.cx), f.area())));
|
||||
|
||||
if let Some(pos) = self.cx.cursor() {
|
||||
f.set_cursor_position(pos);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
if COLLISION.load(Ordering::Relaxed) {
|
||||
Self::patch(frame, self.cx.cursor());
|
||||
Self::patch(frame);
|
||||
}
|
||||
if !self.cx.notify.messages.is_empty() {
|
||||
self.render_partially();
|
||||
|
|
@ -46,6 +41,9 @@ impl App {
|
|||
return self.render();
|
||||
}
|
||||
|
||||
Self::routine(true, None);
|
||||
let _guard = scopeguard::guard(self.cx.cursor(), |c| Self::routine(false, c));
|
||||
|
||||
let frame = term
|
||||
.draw_partial(|f| {
|
||||
_ = Lives::scope(&self.cx, || {
|
||||
|
|
@ -53,20 +51,16 @@ impl App {
|
|||
f.render_widget(crate::notify::Notify::new(&self.cx), f.area());
|
||||
Ok(())
|
||||
});
|
||||
|
||||
if let Some(pos) = self.cx.cursor() {
|
||||
f.set_cursor_position(pos);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
if COLLISION.load(Ordering::Relaxed) {
|
||||
Self::patch(frame, self.cx.cursor());
|
||||
Self::patch(frame);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn patch(frame: CompletedFrame, cursor: Option<(u16, u16)>) {
|
||||
fn patch(frame: CompletedFrame) {
|
||||
let mut new = Buffer::empty(frame.area);
|
||||
for y in new.area.top()..new.area.bottom() {
|
||||
for x in new.area.left()..new.area.right() {
|
||||
|
|
@ -79,14 +73,23 @@ impl App {
|
|||
}
|
||||
|
||||
let patches = frame.buffer.diff(&new);
|
||||
let stdout = &mut *TTY.lockout();
|
||||
CrosstermBackend::new(&mut *TTY.lockout()).draw(patches.into_iter()).ok();
|
||||
}
|
||||
|
||||
let mut backend = CrosstermBackend::new(stdout);
|
||||
backend.draw(patches.into_iter()).ok();
|
||||
if let Some(pos) = cursor {
|
||||
backend.show_cursor().ok();
|
||||
backend.set_cursor_position(pos).ok();
|
||||
fn routine(push: bool, cursor: Option<(Position, SetCursorStyle)>) {
|
||||
static COUNT: AtomicU8 = AtomicU8::new(0);
|
||||
if push && COUNT.fetch_add(1, Ordering::Relaxed) != 0 {
|
||||
return;
|
||||
} else if !push && COUNT.fetch_sub(1, Ordering::Relaxed) != 1 {
|
||||
return;
|
||||
}
|
||||
backend.flush().ok();
|
||||
|
||||
_ = if push {
|
||||
queue!(TTY.writer(), BeginSynchronizedUpdate)
|
||||
} else if let Some((Position { x, y }, shape)) = cursor {
|
||||
execute!(TTY.writer(), shape, MoveTo(x, y), Show, EndSynchronizedUpdate)
|
||||
} else {
|
||||
execute!(TTY.writer(), EndSynchronizedUpdate)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use ratatui::layout::Rect;
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
use ratatui::layout::{Position, Rect};
|
||||
use yazi_core::{cmp::Cmp, confirm::Confirm, help::Help, input::Input, mgr::Mgr, notify::Notify, pick::Pick, tab::{Folder, Tab}, tasks::Tasks, which::Which};
|
||||
use yazi_shared::Layer;
|
||||
|
||||
|
|
@ -30,13 +31,16 @@ impl Ctx {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cursor(&self) -> Option<(u16, u16)> {
|
||||
pub fn cursor(&self) -> Option<(Position, SetCursorStyle)> {
|
||||
if self.input.visible {
|
||||
let Rect { x, y, .. } = self.mgr.area(self.input.position);
|
||||
return Some((x + 1 + self.input.cursor(), y + 1));
|
||||
return Some((
|
||||
Position { x: x + 1 + self.input.cursor(), y: y + 1 },
|
||||
self.input.cursor_shape(),
|
||||
));
|
||||
}
|
||||
if let Some((x, y)) = self.help.cursor() {
|
||||
return Some((x, y));
|
||||
return Some((Position { x, y }, self.help.cursor_shape()));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,57 +233,30 @@ impl<'a> Executor<'a> {
|
|||
return self.app.cx.input.$name(cmd);
|
||||
}
|
||||
};
|
||||
($name:ident, $alias:literal) => {
|
||||
if cmd.name == $alias {
|
||||
return self.app.cx.input.$name(cmd);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
on!(escape);
|
||||
on!(show);
|
||||
on!(close);
|
||||
on!(escape);
|
||||
on!(move_, "move");
|
||||
on!(backward);
|
||||
on!(forward);
|
||||
|
||||
if cmd.name.as_str() == "complete" {
|
||||
return if cmd.bool("trigger") {
|
||||
self.app.cx.cmp.trigger(cmd)
|
||||
} else {
|
||||
self.app.cx.input.complete(cmd)
|
||||
};
|
||||
}
|
||||
|
||||
match self.app.cx.input.mode() {
|
||||
InputMode::Normal => {
|
||||
on!(insert);
|
||||
on!(visual);
|
||||
on!(replace);
|
||||
|
||||
on!(delete);
|
||||
on!(yank);
|
||||
on!(paste);
|
||||
|
||||
on!(undo);
|
||||
on!(redo);
|
||||
|
||||
match cmd.name.as_str() {
|
||||
// Help
|
||||
"help" => self.app.cx.help.toggle(Layer::Input),
|
||||
"help" => return self.app.cx.help.toggle(Layer::Input),
|
||||
// Plugin
|
||||
"plugin" => self.app.plugin(cmd),
|
||||
"plugin" => return self.app.plugin(cmd),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
InputMode::Insert => {
|
||||
on!(visual);
|
||||
|
||||
on!(backspace);
|
||||
on!(kill);
|
||||
}
|
||||
InputMode::Insert => match cmd.name.as_str() {
|
||||
"complete" if cmd.bool("trigger") => return self.app.cx.cmp.trigger(cmd),
|
||||
_ => {}
|
||||
},
|
||||
InputMode::Replace => {}
|
||||
}
|
||||
};
|
||||
|
||||
self.app.cx.input.execute(cmd)
|
||||
}
|
||||
|
||||
fn confirm(&mut self, cmd: CmdCow) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
use std::ops::Range;
|
||||
use ratatui::{buffer::Buffer, layout::{Margin, Rect}, text::Line, widgets::{Block, BorderType, Widget}};
|
||||
use yazi_config::THEME;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use ratatui::{buffer::Buffer, layout::Rect, text::Line, widgets::{Block, BorderType, Paragraph, Widget}};
|
||||
use syntect::easy::HighlightLines;
|
||||
use yazi_config::{PREVIEW, THEME};
|
||||
use yazi_plugin::external::Highlighter;
|
||||
use yazi_widgets::input::InputMode;
|
||||
|
||||
use crate::{Ctx, Term};
|
||||
use crate::Ctx;
|
||||
|
||||
pub(crate) struct Input<'a> {
|
||||
cx: &'a Ctx,
|
||||
|
|
@ -15,52 +9,21 @@ pub(crate) struct Input<'a> {
|
|||
|
||||
impl<'a> Input<'a> {
|
||||
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
|
||||
|
||||
fn highlighted_value(&self) -> Result<Line<'static>> {
|
||||
if !self.cx.input.highlight {
|
||||
bail!("Highlighting is disabled");
|
||||
}
|
||||
|
||||
let (theme, syntaxes) = Highlighter::init();
|
||||
if let Some(syntax) = syntaxes.find_syntax_by_name("Bourne Again Shell (bash)") {
|
||||
let mut h = HighlightLines::new(syntax, theme);
|
||||
let regions = h.highlight_line(self.cx.input.value(), syntaxes)?;
|
||||
return Ok(Highlighter::to_line_widget(regions, &PREVIEW.indent()));
|
||||
}
|
||||
bail!("Failed to find syntax")
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Input<'_> {
|
||||
fn render(self, win: Rect, buf: &mut Buffer) {
|
||||
fn render(self, _: Rect, buf: &mut Buffer) {
|
||||
let input = &self.cx.input;
|
||||
let area = self.cx.mgr.area(input.position);
|
||||
|
||||
yazi_plugin::elements::Clear::default().render(area, buf);
|
||||
Paragraph::new(self.highlighted_value().unwrap_or_else(|_| Line::from(input.value())))
|
||||
.block(
|
||||
Block::bordered()
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(THEME.input.border)
|
||||
.title(Line::styled(&input.title, THEME.input.title)),
|
||||
)
|
||||
.style(THEME.input.value)
|
||||
|
||||
Block::bordered()
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(THEME.input.border)
|
||||
.title(Line::styled(&input.title, THEME.input.title))
|
||||
.render(area, buf);
|
||||
|
||||
if let Some(Range { start, end }) = input.selected() {
|
||||
let x = win.width.min(area.x + 1 + start);
|
||||
let y = win.height.min(area.y + 1);
|
||||
|
||||
buf.set_style(
|
||||
Rect { x, y, width: (end - start).min(win.width - x), height: 1.min(win.height - y) },
|
||||
THEME.input.selected,
|
||||
)
|
||||
}
|
||||
|
||||
_ = match input.mode() {
|
||||
InputMode::Insert => Term::set_cursor_bar(),
|
||||
InputMode::Replace => Term::set_cursor_underscore(),
|
||||
_ => Term::set_cursor_block(),
|
||||
};
|
||||
input.render(area.inner(Margin::new(1, 1)), buf);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use std::{io, ops::{Deref, DerefMut}, sync::atomic::{AtomicBool, AtomicU8, Ordering}};
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::{Command, event::{DisableBracketedPaste, EnableBracketedPaste, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, queue, style::Print, terminal::{LeaveAlternateScreen, SetTitle, disable_raw_mode, enable_raw_mode}};
|
||||
use crossterm::{Command, event::{DisableBracketedPaste, EnableBracketedPaste, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, style::Print, terminal::{LeaveAlternateScreen, SetTitle, disable_raw_mode, enable_raw_mode}};
|
||||
use cursor::RestoreCursor;
|
||||
use ratatui::{CompletedFrame, Frame, Terminal, backend::CrosstermBackend, buffer::Buffer, layout::Rect};
|
||||
use yazi_adapter::{Emulator, Mux};
|
||||
use yazi_config::{INPUT, MGR};
|
||||
use yazi_config::MGR;
|
||||
use yazi_shared::{SyncCell, tty::{TTY, TtyWriter}};
|
||||
|
||||
static CSI_U: AtomicBool = AtomicBool::new(false);
|
||||
|
|
@ -141,36 +141,6 @@ impl Term {
|
|||
pub(super) fn can_partial(&mut self) -> bool {
|
||||
self.inner.autoresize().is_ok() && self.last_area == self.inner.get_frame().area()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn set_cursor_block() -> Result<()> {
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
Ok(if INPUT.cursor_blink {
|
||||
queue!(TTY.writer(), SetCursorStyle::BlinkingBlock)?
|
||||
} else {
|
||||
queue!(TTY.writer(), SetCursorStyle::SteadyBlock)?
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn set_cursor_bar() -> Result<()> {
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
Ok(if INPUT.cursor_blink {
|
||||
queue!(TTY.writer(), SetCursorStyle::BlinkingBar)?
|
||||
} else {
|
||||
queue!(TTY.writer(), SetCursorStyle::SteadyBar)?
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn set_cursor_underscore() -> Result<()> {
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
Ok(if INPUT.cursor_blink {
|
||||
queue!(TTY.writer(), SetCursorStyle::BlinkingUnderScore)?
|
||||
} else {
|
||||
queue!(TTY.writer(), SetCursorStyle::SteadyUnderScore)?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Term {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ mlua = { workspace = true }
|
|||
parking_lot = { workspace = true }
|
||||
ratatui = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
syntect = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
tokio-util = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -18,4 +18,5 @@ yazi-shared = { path = "../yazi-shared", version = "25.3.7" }
|
|||
|
||||
# External dependencies
|
||||
futures = { workspace = true }
|
||||
ratatui = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
|
|
|
|||
48
yazi-widgets/src/input/commands/commands.rs
Normal file
48
yazi-widgets/src/input/commands/commands.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
use yazi_shared::event::CmdCow;
|
||||
|
||||
use crate::input::{Input, InputMode};
|
||||
|
||||
impl Input {
|
||||
pub fn execute(&mut self, cmd: CmdCow) {
|
||||
macro_rules! on {
|
||||
($name:ident) => {
|
||||
if cmd.name == stringify!($name) {
|
||||
return self.$name(cmd);
|
||||
}
|
||||
};
|
||||
($name:ident, $alias:literal) => {
|
||||
if cmd.name == $alias {
|
||||
return self.$name(cmd);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
on!(move_, "move");
|
||||
on!(backward);
|
||||
on!(forward);
|
||||
|
||||
match self.mode() {
|
||||
InputMode::Normal => {
|
||||
on!(insert);
|
||||
on!(visual);
|
||||
on!(replace);
|
||||
|
||||
on!(delete);
|
||||
on!(yank);
|
||||
on!(paste);
|
||||
|
||||
on!(undo);
|
||||
on!(redo);
|
||||
}
|
||||
InputMode::Insert => {
|
||||
on!(visual);
|
||||
|
||||
on!(backspace);
|
||||
on!(kill);
|
||||
|
||||
on!(complete);
|
||||
}
|
||||
InputMode::Replace => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ const SEPARATOR: char = std::path::MAIN_SEPARATOR;
|
|||
|
||||
struct Opt {
|
||||
word: Cow<'static, str>,
|
||||
_ticket: usize, // FIXME
|
||||
_ticket: usize, // FIXME: not used
|
||||
}
|
||||
|
||||
impl From<CmdCow> for Opt {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(backspace backward complete delete escape forward insert kill move_ paste redo replace type_ undo visual yank);
|
||||
yazi_macro::mod_flat!(backspace backward commands complete delete escape forward insert kill move_ paste redo replace type_ undo visual yank);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use ratatui::crossterm::cursor::SetCursorStyle;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use yazi_config::INPUT;
|
||||
use yazi_plugin::CLIPBOARD;
|
||||
|
||||
use super::{InputSnap, InputSnaps, mode::InputMode, op::InputOp};
|
||||
|
|
@ -70,7 +72,10 @@ impl Input {
|
|||
|
||||
impl Input {
|
||||
#[inline]
|
||||
pub fn value(&self) -> &str { self.snap().slice(self.snap().window(self.limit)) }
|
||||
pub fn value(&self) -> &str { &self.snap().value }
|
||||
|
||||
#[inline]
|
||||
pub fn visible_value(&self) -> &str { self.snap().slice(self.snap().window(self.limit)) }
|
||||
|
||||
#[inline]
|
||||
pub fn mode(&self) -> InputMode { self.snap().mode }
|
||||
|
|
@ -81,6 +86,20 @@ impl Input {
|
|||
snap.slice(snap.offset..snap.cursor).width() as u16
|
||||
}
|
||||
|
||||
pub fn cursor_shape(&self) -> SetCursorStyle {
|
||||
use InputMode as M;
|
||||
|
||||
match self.mode() {
|
||||
M::Normal if INPUT.cursor_blink => SetCursorStyle::BlinkingBlock,
|
||||
M::Normal if !INPUT.cursor_blink => SetCursorStyle::SteadyBlock,
|
||||
M::Insert if INPUT.cursor_blink => SetCursorStyle::BlinkingBar,
|
||||
M::Insert if !INPUT.cursor_blink => SetCursorStyle::SteadyBar,
|
||||
M::Replace if INPUT.cursor_blink => SetCursorStyle::BlinkingUnderScore,
|
||||
M::Replace if !INPUT.cursor_blink => SetCursorStyle::SteadyUnderScore,
|
||||
M::Normal | M::Insert | M::Replace => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn selected(&self) -> Option<Range<u16>> {
|
||||
let snap = self.snap();
|
||||
let start = snap.op.start()?;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
yazi_macro::mod_pub!(commands);
|
||||
|
||||
yazi_macro::mod_flat!(input mode op snap snaps);
|
||||
yazi_macro::mod_flat!(input mode op snap snaps widget);
|
||||
|
|
|
|||
|
|
@ -2,13 +2,23 @@ use std::mem;
|
|||
|
||||
use super::InputSnap;
|
||||
|
||||
#[derive(Default, PartialEq, Eq)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct InputSnaps {
|
||||
idx: usize,
|
||||
versions: Vec<InputSnap>,
|
||||
current: InputSnap,
|
||||
}
|
||||
|
||||
impl Default for InputSnaps {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
idx: 0,
|
||||
versions: vec![InputSnap::new(String::new(), 0)],
|
||||
current: InputSnap::new(String::new(), 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputSnaps {
|
||||
pub fn new(value: String, limit: usize) -> Self {
|
||||
let current = InputSnap::new(value, limit);
|
||||
|
|
|
|||
29
yazi-widgets/src/input/widget.rs
Normal file
29
yazi-widgets/src/input/widget.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use ratatui::{layout::Rect, text::Line, widgets::Widget};
|
||||
use yazi_config::THEME;
|
||||
|
||||
use super::Input;
|
||||
|
||||
impl Widget for &Input {
|
||||
fn render(self, area: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
yazi_plugin::elements::Clear::default().render(area, buf);
|
||||
|
||||
Line::styled(self.visible_value(), THEME.input.value).render(area, buf);
|
||||
|
||||
if let Some(Range { start, end }) = self.selected() {
|
||||
buf.set_style(
|
||||
Rect {
|
||||
x: area.x,
|
||||
y: area.y,
|
||||
width: area.width.min(end - start),
|
||||
height: area.height.min(1),
|
||||
},
|
||||
THEME.input.selected,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue