From 564af8827e323312d05465f416943830e81b5257 Mon Sep 17 00:00:00 2001 From: Hanaasagi Date: Sun, 12 Nov 2023 19:53:13 +0900 Subject: [PATCH] feat: custom input box position Close: #351 --- yazi-config/preset/yazi.toml | 19 ++++ yazi-config/src/lib.rs | 3 + yazi-config/src/popup/input.rs | 38 ++++++++ yazi-config/src/popup/mod.rs | 7 ++ yazi-config/src/popup/position.rs | 51 ++++++++++ yazi-config/src/popup/select.rs | 1 + yazi-core/src/context.rs | 117 +++++++++++++++++++---- yazi-core/src/input/option.rs | 59 ++++++++---- yazi-core/src/manager/commands/create.rs | 7 +- yazi-core/src/manager/commands/quit.rs | 6 +- yazi-core/src/manager/commands/rename.rs | 11 ++- yazi-core/src/position.rs | 41 ++++++-- yazi-core/src/select/option.rs | 11 ++- yazi-core/src/tab/commands/cd.rs | 4 +- yazi-core/src/tab/commands/find.rs | 5 +- yazi-core/src/tab/commands/search.rs | 4 +- yazi-core/src/tab/commands/shell.rs | 5 +- yazi-core/src/tasks/tasks.rs | 5 +- yazi-fm/src/completion/completion.rs | 13 +-- 19 files changed, 339 insertions(+), 68 deletions(-) create mode 100644 yazi-config/src/popup/input.rs create mode 100644 yazi-config/src/popup/mod.rs create mode 100644 yazi-config/src/popup/position.rs create mode 100644 yazi-config/src/popup/select.rs diff --git a/yazi-config/preset/yazi.toml b/yazi-config/preset/yazi.toml index c234909b..d9e6911a 100644 --- a/yazi-config/preset/yazi.toml +++ b/yazi-config/preset/yazi.toml @@ -16,6 +16,25 @@ cache_dir = "" ueberzug_scale = 1 ueberzug_offset = [ 0, 0, 0, 0 ] +[input] +cd_position = "top" +cd_offset = [0, 2, 50, 3] + +search_position = "top" +search_offset = [0, 2, 50, 3] + +find_position = "top" +find_offset = [0, 2, 50, 3] + +shell_position = "top" +shell_offset = [0, 2, 50, 3] + +create_position = "top" +create_offset = [0, 2, 50, 3] + +rename_position = "hovered" +rename_offset = [0, 1, 50, 3] + [opener] edit = [ { exec = '$EDITOR "$@"', block = true, for = "unix" }, diff --git a/yazi-config/src/lib.rs b/yazi-config/src/lib.rs index 7baec519..df556b9e 100644 --- a/yazi-config/src/lib.rs +++ b/yazi-config/src/lib.rs @@ -9,6 +9,7 @@ pub mod manager; pub mod open; mod pattern; pub mod plugins; +pub mod popup; mod preset; pub mod preview; mod tasks; @@ -32,6 +33,7 @@ pub static PLUGINS: RoCell = RoCell::new(); pub static PREVIEW: RoCell = RoCell::new(); pub static TASKS: RoCell = RoCell::new(); pub static THEME: RoCell = RoCell::new(); +pub static INPUTBOX: RoCell = RoCell::new(); pub static BOOT: RoCell = RoCell::new(); @@ -48,6 +50,7 @@ pub fn init() { PREVIEW.with(Default::default); TASKS.with(Default::default); THEME.with(Default::default); + INPUTBOX.with(Default::default); BOOT.with(Default::default); } diff --git a/yazi-config/src/popup/input.rs b/yazi-config/src/popup/input.rs new file mode 100644 index 00000000..0223f8f9 --- /dev/null +++ b/yazi-config/src/popup/input.rs @@ -0,0 +1,38 @@ +use serde::Deserialize; + +use super::position::{Offset, Position}; +use crate::MERGED_YAZI; + +#[derive(Debug, Deserialize)] +pub struct Input { + // cd + pub cd_position: Position, + pub cd_offset: Offset, + // search + pub search_position: Position, + pub search_offset: Offset, + // find + pub find_position: Position, + pub find_offset: Offset, + // shell + pub shell_position: Position, + pub shell_offset: Offset, + // create + pub create_position: Position, + pub create_offset: Offset, + // rename + pub rename_position: Position, + pub rename_offset: Offset, +} + +impl Default for Input { + fn default() -> Self { + #[derive(Deserialize)] + struct Outer { + input: Input, + } + + // TODO: + toml::from_str::(&MERGED_YAZI).unwrap().input + } +} diff --git a/yazi-config/src/popup/mod.rs b/yazi-config/src/popup/mod.rs new file mode 100644 index 00000000..dc47ddd4 --- /dev/null +++ b/yazi-config/src/popup/mod.rs @@ -0,0 +1,7 @@ +mod input; +mod position; +mod select; + +pub use input::*; +pub use position::*; +pub use select::*; diff --git a/yazi-config/src/popup/position.rs b/yazi-config/src/popup/position.rs new file mode 100644 index 00000000..d2764a43 --- /dev/null +++ b/yazi-config/src/popup/position.rs @@ -0,0 +1,51 @@ +use anyhow::bail; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize)] +pub enum Position { + #[serde(rename = "top-left")] + TopLeft, + #[serde(rename = "top-right")] + TopRight, + #[serde(rename = "top")] + Top, + #[serde(rename = "center")] + Center, + #[serde(rename = "bottom")] + Bottom, + #[serde(rename = "bottom-left")] + BottomLeft, + #[serde(rename = "bottom-right")] + BottomRight, + #[serde(rename = "hovered")] + Hovered, +} + +#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] +#[serde(try_from = "Vec")] +pub struct Offset { + pub x: i16, + pub y: i16, + pub width: u16, + pub height: u16, +} + +impl TryFrom> for Offset { + type Error = anyhow::Error; + + fn try_from(values: Vec) -> Result { + if values.len() != 4 { + bail!("invalid offset: {:?}", values); + } + if values[2] < 0 || values[3] < 0 { + bail!("invalid offset: {:?}", values); + } + + Ok(Self { + x: values[0], + y: values[1], + width: values[2] as u16, + height: values[3] as u16, + }) + } +} diff --git a/yazi-config/src/popup/select.rs b/yazi-config/src/popup/select.rs new file mode 100644 index 00000000..6c8ea4d0 --- /dev/null +++ b/yazi-config/src/popup/select.rs @@ -0,0 +1 @@ +// TODO: diff --git a/yazi-core/src/context.rs b/yazi-core/src/context.rs index 31546bb3..a8f496ee 100644 --- a/yazi-core/src/context.rs +++ b/yazi-core/src/context.rs @@ -2,7 +2,7 @@ use crossterm::terminal::WindowSize; use ratatui::prelude::Rect; use yazi_shared::Term; -use crate::{completion::Completion, help::Help, input::Input, manager::Manager, select::Select, tasks::Tasks, which::Which, Position}; +use crate::{completion::Completion, help::Help, input::Input, manager::Manager, select::Select, tasks::Tasks, which::Which, Position, RectShim}; pub struct Ctx { pub manager: Manager, @@ -30,29 +30,114 @@ impl Ctx { pub fn area(&self, pos: &Position) -> Rect { let WindowSize { columns, rows, .. } = Term::size(); - let (x, y) = match pos { - Position::Top(Rect { mut x, mut y, width, height }) => { - x = x.min(columns.saturating_sub(*width)); - y = y.min(rows.saturating_sub(*height)); - ((columns / 2).saturating_sub(width / 2) + x, y) + let (x, y) = match *pos { + Position::TopLeft(RectShim { x_offset, y_offset, width, height }) => { + let right_max = columns.saturating_sub(width); + let bottom_max = rows.saturating_sub(height); + + let base_x = 0_u16; + let base_y = 0_u16; + + let x = base_x.saturating_add_signed(x_offset).max(0).min(right_max); + let y = base_y.saturating_add_signed(y_offset).max(0).min(bottom_max); + + (x, y) } - Position::Sticky(Rect { mut x, y, width, height }, r) => { - x = x.min(columns.saturating_sub(*width)); - if y + height + r.y + r.height > rows { - (x + r.x, r.y.saturating_sub(height.saturating_sub(*y))) - } else { - (x + r.x, y + r.y + r.height) - } + Position::TopRight(RectShim { x_offset, y_offset, width, height }) => { + let right_max = columns.saturating_sub(width); + let bottom_max = rows.saturating_sub(height); + + let base_x = right_max; + let base_y = 0_u16; + + let x = base_x.saturating_add_signed(x_offset).max(0).min(right_max); + let y = base_y.saturating_add_signed(y_offset).max(0).min(bottom_max); + + (x, y) } - Position::Hovered(rect) => { + Position::Top(RectShim { x_offset, y_offset, width, height }) => { + let right_max = columns.saturating_sub(width); + let bottom_max = rows.saturating_sub(height); + + let base_x = (columns / 2).saturating_sub(width / 2); + let base_y = 0_u16; + + let x = base_x.saturating_add_signed(x_offset).max(0).min(right_max); + let y = base_y.saturating_add_signed(y_offset).max(0).min(bottom_max); + + (x, y) + } + Position::Center(RectShim { x_offset, y_offset, width, height }) => { + let right_max = columns.saturating_sub(width); + let bottom_max = rows.saturating_sub(height); + + let base_x = (columns / 2).saturating_sub(width / 2); + let base_y = (bottom_max / 2).saturating_sub(height / 2); + + let x = base_x.saturating_add_signed(x_offset).max(0).min(right_max); + let y = base_y.saturating_add_signed(y_offset).max(0).min(bottom_max); + + (x, y) + } + Position::Bottom(RectShim { x_offset, y_offset, width, height }) => { + let right_max = columns.saturating_sub(width); + let bottom_max = rows.saturating_sub(height); + + let base_x = (columns / 2).saturating_sub(width / 2); + let base_y = bottom_max; + + let x = base_x.saturating_add_signed(x_offset).max(0).min(right_max); + let y = base_y.saturating_add_signed(y_offset).max(0).min(bottom_max); + + (x, y) + } + Position::BottomLeft(RectShim { x_offset, y_offset, width, height }) => { + let right_max = columns.saturating_sub(width); + let bottom_max = rows.saturating_sub(height); + + let base_x = 0_u16; + let base_y = bottom_max; + + let x = base_x.saturating_add_signed(x_offset).max(0).min(right_max); + let y = base_y.saturating_add_signed(y_offset).max(0).min(bottom_max); + + (x, y) + } + Position::BottomRight(RectShim { x_offset, y_offset, width, height }) => { + let right_max = columns.saturating_sub(width); + let bottom_max = rows.saturating_sub(height); + + let base_x = right_max; + let base_y = bottom_max; + + let x = base_x.saturating_add_signed(x_offset).max(0).min(right_max); + let y = base_y.saturating_add_signed(y_offset).max(0).min(bottom_max); + + (x, y) + } + Position::Hovered(rect_shim) => { return self.area(&if let Some(r) = self.manager.hovered().and_then(|h| self.manager.current().rect_current(&h.url)) { - Position::Sticky(*rect, r) + Position::Sticky(rect_shim, r) } else { - Position::Top(*rect) + Position::Top(rect_shim) }); } + Position::Sticky(RectShim { x_offset, y_offset, width, height }, r) => { + // TODO: + unimplemented!("Position::Sticky is not implemented"); + // let mut x = columns.saturating_sub(width); + // x = x.saturating_add_signed(x_offset); + // let mut y = r.y; + // y = y.saturating_add_signed(y_offset); + + // if y + height + r.height > rows { + // (x + r.x, r.y.saturating_sub(height.saturating_sub(y))) + // } else { + // (x + r.x, y + r.height) + // } + } }; let (w, h) = pos.dimension(); diff --git a/yazi-core/src/input/option.rs b/yazi-core/src/input/option.rs index f8bb6e64..8b5278ad 100644 --- a/yazi-core/src/input/option.rs +++ b/yazi-core/src/input/option.rs @@ -1,6 +1,6 @@ -use ratatui::prelude::Rect; +use yazi_config::popup::{Offset as CfgOffset, Position as CfgPosition}; -use crate::Position; +use crate::{Position, RectShim}; #[derive(Default)] pub struct InputOpt { @@ -12,23 +12,48 @@ pub struct InputOpt { pub highlight: bool, } -impl InputOpt { - pub fn top(title: impl AsRef) -> Self { - Self { - title: title.as_ref().to_owned(), - position: Position::Top(/* TODO: hardcode */ Rect { x: 0, y: 2, width: 50, height: 3 }), - ..Default::default() +macro_rules! gen_method { + ($func_name:ident, $position:ident) => { + pub fn $func_name(title: impl AsRef, rect: RectShim) -> InputOpt { + InputOpt { + title: title.as_ref().to_owned(), + position: Position::$position(rect), + ..Default::default() + } } - } + }; +} - pub fn hovered(title: impl AsRef) -> Self { - Self { - title: title.as_ref().to_owned(), - position: Position::Hovered( - // TODO: hardcode - Rect { x: 0, y: 1, width: 50, height: 3 }, - ), - ..Default::default() +impl InputOpt { + gen_method!(top_left, TopLeft); + + gen_method!(top_right, TopRight); + + gen_method!(top, Top); + + gen_method!(center, Center); + + gen_method!(bottom, Bottom); + + gen_method!(bottom_left, BottomLeft); + + gen_method!(bottom_right, BottomRight); + + gen_method!(hovered, Hovered); + + pub fn from_cfg(title: impl AsRef, pos: &CfgPosition, rect: &CfgOffset) -> Self { + let rect = + RectShim { x_offset: rect.x, y_offset: rect.y, width: rect.width, height: rect.height }; + + match pos { + CfgPosition::TopLeft => Self::top_left(title, rect), + CfgPosition::TopRight => Self::top_right(title, rect), + CfgPosition::Top => Self::top(title, rect), + CfgPosition::Center => Self::center(title, rect), + CfgPosition::Bottom => Self::bottom(title, rect), + CfgPosition::BottomLeft => Self::bottom_left(title, rect), + CfgPosition::BottomRight => Self::bottom_right(title, rect), + CfgPosition::Hovered => Self::hovered(title, rect), } } diff --git a/yazi-core/src/manager/commands/create.rs b/yazi-core/src/manager/commands/create.rs index e97af987..331dc093 100644 --- a/yazi-core/src/manager/commands/create.rs +++ b/yazi-core/src/manager/commands/create.rs @@ -19,14 +19,17 @@ impl Manager { let opt = opt.into() as Opt; let cwd = self.cwd().to_owned(); tokio::spawn(async move { - let mut result = emit!(Input(InputOpt::top("Create:"))); + let mut result = emit!(Input(InputOpt::top("Create:", Default::default()))); let Some(Ok(name)) = result.recv().await else { return Ok(()); }; let path = cwd.join(&name); if !opt.force && fs::symlink_metadata(&path).await.is_ok() { - match emit!(Input(InputOpt::top("Overwrite an existing file? (y/N)"))).recv().await { + match emit!(Input(InputOpt::top("Overwrite an existing file? (y/N)", Default::default()))) + .recv() + .await + { Some(Ok(c)) if c == "y" || c == "Y" => (), _ => return Ok(()), } diff --git a/yazi-core/src/manager/commands/quit.rs b/yazi-core/src/manager/commands/quit.rs index d1eb0fcd..14c0efa7 100644 --- a/yazi-core/src/manager/commands/quit.rs +++ b/yazi-core/src/manager/commands/quit.rs @@ -24,8 +24,10 @@ impl Manager { } tokio::spawn(async move { - let mut result = - emit!(Input(InputOpt::top(format!("{tasks} tasks running, sure to quit? (y/N)")))); + let mut result = emit!(Input(InputOpt::top( + format!("{tasks} tasks running, sure to quit? (y/N)",), + Default::default() + ))); if let Some(Ok(choice)) = result.recv().await { if choice == "y" || choice == "Y" { diff --git a/yazi-core/src/manager/commands/rename.rs b/yazi-core/src/manager/commands/rename.rs index 35a4f7aa..15dea8ae 100644 --- a/yazi-core/src/manager/commands/rename.rs +++ b/yazi-core/src/manager/commands/rename.rs @@ -2,7 +2,7 @@ use std::{collections::BTreeSet, ffi::OsStr, io::{stdout, BufWriter, Write}, pat use anyhow::{anyhow, bail, Result}; use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}}; -use yazi_config::{keymap::Exec, OPEN, PREVIEW}; +use yazi_config::{keymap::Exec, INPUTBOX, OPEN, PREVIEW}; use yazi_shared::{max_common_root, Defer, Term, Url}; use crate::{emit, external::{self, ShellOpt}, files::{File, FilesOp}, input::InputOpt, manager::Manager, Event, BLOCKER}; @@ -43,7 +43,8 @@ impl Manager { let opt = opt.into() as Opt; tokio::spawn(async move { let mut result = emit!(Input( - InputOpt::hovered("Rename:").with_value(hovered.file_name().unwrap().to_string_lossy()) + InputOpt::from_cfg("Rename:", &INPUTBOX.rename_position, &INPUTBOX.rename_offset) + .with_value(hovered.file_name().unwrap().to_string_lossy()) )); let Some(Ok(name)) = result.recv().await else { @@ -56,7 +57,11 @@ impl Manager { return; } - let mut result = emit!(Input(InputOpt::hovered("Overwrite an existing file? (y/N)"))); + let mut result = emit!(Input(InputOpt::from_cfg( + "Overwrite an existing file? (y/N)", + &INPUTBOX.rename_position, + &INPUTBOX.rename_offset + ))); if let Some(Ok(choice)) = result.recv().await { if choice == "y" || choice == "Y" { Self::rename_and_hover(hovered, Url::from(new)).await.ok(); diff --git a/yazi-core/src/position.rs b/yazi-core/src/position.rs index 37bd0911..e2534471 100644 --- a/yazi-core/src/position.rs +++ b/yazi-core/src/position.rs @@ -1,22 +1,47 @@ use ratatui::prelude::Rect; +#[derive(Debug, Clone, Copy)] +pub struct RectShim { + pub x_offset: i16, + pub y_offset: i16, + pub width: u16, + pub height: u16, +} + +impl Default for RectShim { + fn default() -> Self { Self { x_offset: 0, y_offset: 2, width: 50, height: 3 } } +} + +#[derive(Debug, Clone)] pub enum Position { - Top(Rect), - Sticky(Rect, Rect), - Hovered(Rect), + TopLeft(RectShim), + TopRight(RectShim), + Top(RectShim), + Center(RectShim), + Bottom(RectShim), + BottomLeft(RectShim), + BottomRight(RectShim), + Hovered(RectShim), + Sticky(RectShim, Rect), } impl Default for Position { - fn default() -> Self { Self::Top(Rect::default()) } + fn default() -> Self { Self::Top(RectShim::default()) } } impl Position { #[inline] - pub fn rect(&self) -> Rect { + pub fn rect(&self) -> &RectShim { match self { - Position::Top(rect) => *rect, - Position::Sticky(rect, _) => *rect, - Position::Hovered(rect) => *rect, + Position::TopLeft(rect) => rect, + Position::TopRight(rect) => rect, + Position::Top(rect) => rect, + Position::Center(rect) => rect, + Position::Bottom(rect) => rect, + Position::BottomLeft(rect) => rect, + Position::BottomRight(rect) => rect, + Position::Hovered(rect) => rect, + Position::Sticky(rect, _) => rect, } } diff --git a/yazi-core/src/select/option.rs b/yazi-core/src/select/option.rs index eaf41037..1491057c 100644 --- a/yazi-core/src/select/option.rs +++ b/yazi-core/src/select/option.rs @@ -1,6 +1,6 @@ use ratatui::prelude::Rect; -use crate::Position; +use crate::{Position, RectShim}; pub struct SelectOpt { pub title: String, @@ -14,7 +14,10 @@ impl SelectOpt { Self { title: title.to_owned(), items, - position: Position::Top(/* TODO: hardcode */ Rect { x: 0, y: 2, width: 50, height }), + position: Position::Top( + // TODO: + RectShim { x_offset: 0, y_offset: 2, width: 50, height }, + ), } } @@ -24,8 +27,8 @@ impl SelectOpt { title: title.to_owned(), items, position: Position::Hovered( - // TODO: hardcode - Rect { x: 0, y: 1, width: 50, height }, + // TODO: + RectShim { x_offset: 0, y_offset: 1, width: 50, height }, ), } } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index 74935103..3b6c3d5b 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -2,7 +2,7 @@ use std::{mem, time::Duration}; use tokio::{fs, pin}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; -use yazi_config::keymap::{Exec, KeymapLayer}; +use yazi_config::{keymap::{Exec, KeymapLayer}, INPUTBOX}; use yazi_shared::{expand_path, Debounce, InputError, Url}; use crate::{emit, input::InputOpt, tab::Tab}; @@ -66,7 +66,7 @@ impl Tab { tokio::spawn(async move { let rx = emit!(Input( - InputOpt::top("Change directory:") + InputOpt::from_cfg("Change directory:", &INPUTBOX.cd_position, &INPUTBOX.cd_offset) .with_value(opt.target.to_string_lossy()) .with_completion() )); diff --git a/yazi-core/src/tab/commands/find.rs b/yazi-core/src/tab/commands/find.rs index 6aa54e1f..9960bd4c 100644 --- a/yazi-core/src/tab/commands/find.rs +++ b/yazi-core/src/tab/commands/find.rs @@ -2,7 +2,7 @@ use std::time::Duration; use tokio::pin; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; -use yazi_config::keymap::{Exec, KeymapLayer}; +use yazi_config::{keymap::{Exec, KeymapLayer}, INPUTBOX}; use yazi_shared::{Debounce, InputError}; use crate::{emit, input::InputOpt, tab::{Finder, FinderCase, Tab}}; @@ -39,8 +39,9 @@ impl Tab { pub fn find<'a>(&mut self, opt: impl Into>) -> bool { let opt = opt.into() as Opt; tokio::spawn(async move { + let title = if opt.prev { "Find previous:" } else { "Find next:" }; let rx = emit!(Input( - InputOpt::top(if opt.prev { "Find previous:" } else { "Find next:" }).with_realtime() + InputOpt::from_cfg(title, &INPUTBOX.find_position, &INPUTBOX.find_offset).with_realtime() )); let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50)); diff --git a/yazi-core/src/tab/commands/search.rs b/yazi-core/src/tab/commands/search.rs index 93acade8..eaf98968 100644 --- a/yazi-core/src/tab/commands/search.rs +++ b/yazi-core/src/tab/commands/search.rs @@ -3,7 +3,7 @@ use std::{mem, time::Duration}; use anyhow::bail; use tokio::pin; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; -use yazi_config::keymap::{Exec, KeymapLayer}; +use yazi_config::{keymap::{Exec, KeymapLayer}, INPUTBOX}; use crate::{emit, external, files::FilesOp, input::InputOpt, tab::Tab}; @@ -45,7 +45,7 @@ impl Tab { let hidden = self.conf.show_hidden; self.search = Some(tokio::spawn(async move { - let Some(Ok(subject)) = emit!(Input(InputOpt::top("Search:"))).recv().await else { + let Some(Ok(subject)) = emit!(Input(InputOpt::from_cfg("Search:", &INPUTBOX.cd_position, &INPUTBOX.cd_offset))).recv().await else { bail!("") }; diff --git a/yazi-core/src/tab/commands/shell.rs b/yazi-core/src/tab/commands/shell.rs index 2fd1ba37..926d4faa 100644 --- a/yazi-core/src/tab/commands/shell.rs +++ b/yazi-core/src/tab/commands/shell.rs @@ -1,4 +1,4 @@ -use yazi_config::{keymap::Exec, open::Opener}; +use yazi_config::{keymap::Exec, open::Opener, INPUTBOX}; use crate::{emit, input::InputOpt, tab::Tab}; @@ -29,8 +29,9 @@ impl Tab { let mut opt = opt.into() as Opt; tokio::spawn(async move { if !opt.confirm || opt.cmd.is_empty() { + let title = if opt.block { "Shell (block):" } else { "Shell:" }; let mut result = emit!(Input( - InputOpt::top(if opt.block { "Shell (block):" } else { "Shell:" }) + InputOpt::from_cfg(title, &INPUTBOX.shell_position, &INPUTBOX.shell_offset) .with_value(opt.cmd) .with_highlight() )); diff --git a/yazi-core/src/tasks/tasks.rs b/yazi-core/src/tasks/tasks.rs index a7e90f25..dbf21407 100644 --- a/yazi-core/src/tasks/tasks.rs +++ b/yazi-core/src/tasks/tasks.rs @@ -111,11 +111,12 @@ impl Tasks { let scheduler = self.scheduler.clone(); tokio::spawn(async move { let s = if targets.len() > 1 { "s" } else { "" }; - let mut result = emit!(Input(InputOpt::hovered(if permanently { + let prompt = if permanently { format!("Delete {} selected file{s} permanently? (y/N)", targets.len()) } else { format!("Move {} selected file{s} to trash? (y/N)", targets.len()) - }))); + }; + let mut result = emit!(Input(InputOpt::hovered(prompt, Default::default()))); if let Some(Ok(choice)) = result.recv().await { if choice != "y" && choice != "Y" { diff --git a/yazi-fm/src/completion/completion.rs b/yazi-fm/src/completion/completion.rs index 5243159f..aa29d471 100644 --- a/yazi-fm/src/completion/completion.rs +++ b/yazi-fm/src/completion/completion.rs @@ -2,7 +2,7 @@ use std::path::MAIN_SEPARATOR; use ratatui::{buffer::Buffer, layout::Rect, widgets::{Block, BorderType, Borders, Clear, List, ListItem, Widget}}; use yazi_config::THEME; -use yazi_core::{Ctx, Position}; +use yazi_core::{Ctx, Position, RectShim}; pub(crate) struct Completion<'a> { cx: &'a Ctx, @@ -40,11 +40,12 @@ impl<'a> Widget for Completion<'a> { let input_area = self.cx.area(&self.cx.input.position); let mut area = self.cx.area(&Position::Sticky( - Rect { - x: 1, - y: 0, - width: input_area.width.saturating_sub(2), - height: items.len() as u16 + 2, + // TODO: + RectShim { + x_offset: 1, + y_offset: 0, + width: input_area.width.saturating_sub(2), + height: items.len() as u16 + 2, }, input_area, ));