From 4f40977f1faf74332d8ee5c831623009b65e5a42 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Thu, 20 Mar 2025 01:31:41 +0800 Subject: [PATCH] .. --- Cargo.lock | 2 +- Cargo.toml | 1 + yazi-core/src/help/commands/filter.rs | 8 +-- yazi-core/src/help/help.rs | 14 +++-- yazi-fm/Cargo.toml | 1 - yazi-fm/src/app/commands/render.rs | 51 +++++++++--------- yazi-fm/src/context.rs | 12 +++-- yazi-fm/src/executor.rs | 47 ++++------------- yazi-fm/src/input/input.rs | 57 ++++----------------- yazi-fm/src/term.rs | 34 +----------- yazi-plugin/Cargo.toml | 2 +- yazi-widgets/Cargo.toml | 1 + yazi-widgets/src/input/commands/commands.rs | 48 +++++++++++++++++ yazi-widgets/src/input/commands/complete.rs | 2 +- yazi-widgets/src/input/commands/mod.rs | 2 +- yazi-widgets/src/input/input.rs | 21 +++++++- yazi-widgets/src/input/mod.rs | 2 +- yazi-widgets/src/input/snaps.rs | 12 ++++- yazi-widgets/src/input/widget.rs | 29 +++++++++++ 19 files changed, 183 insertions(+), 163 deletions(-) create mode 100644 yazi-widgets/src/input/commands/commands.rs create mode 100644 yazi-widgets/src/input/widget.rs diff --git a/Cargo.lock b/Cargo.lock index 05f69a22..aae35be6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 5d82d069..80ebeda0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/yazi-core/src/help/commands/filter.rs b/yazi-core/src/help/commands/filter.rs index 29fcc540..0bfb54af 100644 --- a/yazi-core/src/help/commands/filter.rs +++ b/yazi-core/src/help/commands/filter.rs @@ -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!(); } diff --git a/yazi-core/src/help/help.rs b/yazi-core/src/help/help.rs index 00670f8a..a9c12fc6 100644 --- a/yazi-core/src/help/help.rs +++ b/yazi-core/src/help/help.rs @@ -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, + pub(super) in_filter: Option, 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 } + } } diff --git a/yazi-fm/Cargo.toml b/yazi-fm/Cargo.toml index 7d9a93c3..360e1e7b 100644 --- a/yazi-fm/Cargo.toml +++ b/yazi-fm/Cargo.toml @@ -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 } diff --git a/yazi-fm/src/app/commands/render.rs b/yazi-fm/src/app/commands/render.rs index 97a80c69..a7e2fadd 100644 --- a/yazi-fm/src/app/commands/render.rs +++ b/yazi-fm/src/app/commands/render.rs @@ -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) + }; } } diff --git a/yazi-fm/src/context.rs b/yazi-fm/src/context.rs index f8d5b1b7..cc1f012b 100644 --- a/yazi-fm/src/context.rs +++ b/yazi-fm/src/context.rs @@ -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 } diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 357713b5..282c1ad6 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -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) { diff --git a/yazi-fm/src/input/input.rs b/yazi-fm/src/input/input.rs index decb2466..4c85dcb4 100644 --- a/yazi-fm/src/input/input.rs +++ b/yazi-fm/src/input/input.rs @@ -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> { - 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); } } diff --git a/yazi-fm/src/term.rs b/yazi-fm/src/term.rs index 182ee1af..e0d22bf2 100644 --- a/yazi-fm/src/term.rs +++ b/yazi-fm/src/term.rs @@ -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 { diff --git a/yazi-plugin/Cargo.toml b/yazi-plugin/Cargo.toml index 135d97f2..25eee456 100644 --- a/yazi-plugin/Cargo.toml +++ b/yazi-plugin/Cargo.toml @@ -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 } diff --git a/yazi-widgets/Cargo.toml b/yazi-widgets/Cargo.toml index b14276ab..806ad867 100644 --- a/yazi-widgets/Cargo.toml +++ b/yazi-widgets/Cargo.toml @@ -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 } diff --git a/yazi-widgets/src/input/commands/commands.rs b/yazi-widgets/src/input/commands/commands.rs new file mode 100644 index 00000000..7ab08e12 --- /dev/null +++ b/yazi-widgets/src/input/commands/commands.rs @@ -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 => {} + } + } +} diff --git a/yazi-widgets/src/input/commands/complete.rs b/yazi-widgets/src/input/commands/complete.rs index 286de979..241a3e03 100644 --- a/yazi-widgets/src/input/commands/complete.rs +++ b/yazi-widgets/src/input/commands/complete.rs @@ -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 for Opt { diff --git a/yazi-widgets/src/input/commands/mod.rs b/yazi-widgets/src/input/commands/mod.rs index 49bff105..3fb65236 100644 --- a/yazi-widgets/src/input/commands/mod.rs +++ b/yazi-widgets/src/input/commands/mod.rs @@ -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); diff --git a/yazi-widgets/src/input/input.rs b/yazi-widgets/src/input/input.rs index 77a5943b..0fb0834b 100644 --- a/yazi-widgets/src/input/input.rs +++ b/yazi-widgets/src/input/input.rs @@ -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> { let snap = self.snap(); let start = snap.op.start()?; diff --git a/yazi-widgets/src/input/mod.rs b/yazi-widgets/src/input/mod.rs index bc6b58ab..1e6e60b0 100644 --- a/yazi-widgets/src/input/mod.rs +++ b/yazi-widgets/src/input/mod.rs @@ -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); diff --git a/yazi-widgets/src/input/snaps.rs b/yazi-widgets/src/input/snaps.rs index bc3f9e7a..c0d6b1de 100644 --- a/yazi-widgets/src/input/snaps.rs +++ b/yazi-widgets/src/input/snaps.rs @@ -2,13 +2,23 @@ use std::mem; use super::InputSnap; -#[derive(Default, PartialEq, Eq)] +#[derive(PartialEq, Eq)] pub struct InputSnaps { idx: usize, versions: Vec, 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); diff --git a/yazi-widgets/src/input/widget.rs b/yazi-widgets/src/input/widget.rs new file mode 100644 index 00000000..08e265b5 --- /dev/null +++ b/yazi-widgets/src/input/widget.rs @@ -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, + ) + } + } +}