This commit is contained in:
sxyazi 2023-11-16 08:27:24 +08:00
parent c95b613ed5
commit 75dc1ec8a3
No known key found for this signature in database
15 changed files with 224 additions and 244 deletions

View file

@ -76,56 +76,56 @@ preload = []
[input]
# cd
cd_title = "Change directory:"
cd_position = "top-center"
cd_origin = "top-center"
cd_offset = [ 0, 2, 50, 3 ]
cd_completion = 1
# create
create_title = "Create:"
create_position = "top-center"
create_offset = [ 0, 2, 50, 3 ]
create_title = "Create:"
create_origin = "top-center"
create_offset = [ 0, 2, 50, 3 ]
# rename
rename_title = "Rename:"
rename_position = "hovered"
rename_offset = [ 0, 1, 50, 3 ]
rename_title = "Rename:"
rename_origin = "hovered"
rename_offset = [ 0, 1, 50, 3 ]
# trash
trash_title = "Move {n} selected file{s} to trash? (y/N)"
trash_position = "top-center"
trash_offset = [ 0, 2, 50, 3 ]
trash_title = "Move {n} selected file{s} to trash? (y/N)"
trash_origin = "top-center"
trash_offset = [ 0, 2, 50, 3 ]
# delete
delete_title = "Delete {n} selected file{s} permanently? (y/N)"
delete_position = "top-center"
delete_offset = [ 0, 2, 50, 3 ]
delete_title = "Delete {n} selected file{s} permanently? (y/N)"
delete_origin = "top-center"
delete_offset = [ 0, 2, 50, 3 ]
# find
find_title = [ "Find previous:", "Find next:" ]
find_position = "top-center"
find_origin = "top-center"
find_offset = [ 0, 2, 50, 3 ]
find_realtime = true
# search
search_title = "Search:"
search_position = "top-center"
search_offset = [ 0, 2, 50, 3 ]
search_title = "Search:"
search_origin = "top-center"
search_offset = [ 0, 2, 50, 3 ]
# shell
shell_title = [ "Shell:", "Shell (block):" ]
shell_position = "top-center"
shell_origin = "top-center"
shell_offset = [ 0, 2, 50, 3 ]
shell_highlight = true
# overwrite
overwrite_title = "Overwrite an existing file? (y/N)"
overwrite_position = "top-center"
overwrite_offset = [ 0, 2, 50, 3 ]
overwrite_title = "Overwrite an existing file? (y/N)"
overwrite_origin = "top-center"
overwrite_offset = [ 0, 2, 50, 3 ]
[select]
open_title = "Open with:"
open_position = "hovered"
open_offset = [ 0, 1, 50, 3 ]
open_title = "Open with:"
open_origin = "hovered"
open_offset = [ 0, 1, 50, 3 ]
[log]
enabled = false

View file

@ -1,49 +1,49 @@
use serde::Deserialize;
use super::position::{Offset, Position};
use super::{Offset, Origin};
use crate::MERGED_YAZI;
#[derive(Debug, Deserialize)]
#[derive(Deserialize)]
pub struct Input {
// cd
pub cd_title: String,
pub cd_position: Position,
pub cd_offset: Offset,
pub cd_title: String,
pub cd_origin: Origin,
pub cd_offset: Offset,
// create
pub create_title: String,
pub create_position: Position,
pub create_offset: Offset,
pub create_title: String,
pub create_origin: Origin,
pub create_offset: Offset,
// rename
pub rename_title: String,
pub rename_position: Position,
pub rename_offset: Offset,
pub rename_title: String,
pub rename_origin: Origin,
pub rename_offset: Offset,
// trash
pub trash_title: String,
pub trash_position: Position,
pub trash_offset: Offset,
pub trash_title: String,
pub trash_origin: Origin,
pub trash_offset: Offset,
// delete
pub delete_title: String,
pub delete_position: Position,
pub delete_offset: Offset,
pub delete_title: String,
pub delete_origin: Origin,
pub delete_offset: Offset,
// find
pub find_title: [String; 2],
pub find_position: Position,
pub find_offset: Offset,
pub find_title: [String; 2],
pub find_origin: Origin,
pub find_offset: Offset,
// search
pub search_title: String,
pub search_position: Position,
pub search_offset: Offset,
pub search_title: String,
pub search_origin: Origin,
pub search_offset: Offset,
// shell
pub shell_title: [String; 2],
pub shell_position: Position,
pub shell_offset: Offset,
pub shell_title: [String; 2],
pub shell_origin: Origin,
pub shell_offset: Offset,
}
impl Default for Input {

View file

@ -1,9 +1,13 @@
mod input;
mod offset;
mod options;
mod origin;
mod position;
mod select;
pub use input::*;
pub use offset::*;
pub use options::*;
pub use origin::*;
pub use position::*;
pub use select::*;

View file

@ -0,0 +1,31 @@
use anyhow::bail;
use serde::Deserialize;
#[derive(Clone, Copy, Default, Deserialize)]
#[serde(try_from = "Vec<i16>")]
pub struct Offset {
pub x: i16,
pub y: i16,
pub width: u16,
pub height: u16,
}
impl TryFrom<Vec<i16>> for Offset {
type Error = anyhow::Error;
fn try_from(values: Vec<i16>) -> Result<Self, Self::Error> {
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,
})
}
}

View file

@ -0,0 +1,24 @@
use serde::Deserialize;
#[derive(Clone, Copy, Default, Deserialize)]
pub enum Origin {
#[default]
#[serde(rename = "top-left")]
TopLeft,
#[serde(rename = "top-center")]
TopCenter,
#[serde(rename = "top-right")]
TopRight,
#[serde(rename = "bottom-left")]
BottomLeft,
#[serde(rename = "bottom-center")]
BottomCenter,
#[serde(rename = "bottom-right")]
BottomRight,
#[serde(rename = "center")]
Center,
#[serde(rename = "hovered")]
Hovered,
}

View file

@ -1,54 +1,91 @@
use anyhow::bail;
use serde::{Deserialize, Serialize};
use crossterm::terminal::WindowSize;
use ratatui::layout::Rect;
use yazi_shared::Term;
#[derive(Debug, Default, Deserialize)]
pub enum Position {
#[serde(rename = "top-left")]
TopLeft,
#[serde(rename = "top-center")]
TopCenter,
#[serde(rename = "top-right")]
TopRight,
use super::{Offset, Origin};
#[serde(rename = "bottom-left")]
BottomLeft,
#[serde(rename = "bottom-center")]
BottomCenter,
#[serde(rename = "bottom-right")]
BottomRight,
#[serde(rename = "center")]
#[default]
Center,
#[serde(rename = "hovered")]
Hovered,
#[derive(Clone, Copy, Default)]
pub struct Position {
pub origin: Origin,
pub offset: Offset,
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(try_from = "Vec<i16>")]
pub struct Offset {
pub x: i16,
pub y: i16,
pub width: u16,
pub height: u16,
}
impl Position {
pub fn rect(&self) -> Rect {
let Offset { x, y, width, height } = self.offset;
let WindowSize { columns, rows, .. } = Term::size();
impl TryFrom<Vec<i16>> for Offset {
type Error = anyhow::Error;
let max_x = columns.saturating_sub(width);
let max_y = rows.saturating_sub(height);
fn try_from(values: Vec<i16>) -> Result<Self, Self::Error> {
if values.len() != 4 {
bail!("invalid offset: {:?}", values);
}
if values[2] < 0 || values[3] < 0 {
bail!("invalid offset: {:?}", values);
let (x, y) = match self.origin {
// Top
Origin::TopLeft => (x.clamp(0, max_x as i16) as u16, y.clamp(0, max_y as i16) as u16),
Origin::TopCenter => (
(columns / 2).saturating_sub(width / 2).saturating_add_signed(x).clamp(0, max_x),
y.clamp(0, max_y as i16) as u16,
),
Origin::TopRight => {
(max_x.saturating_add_signed(x).clamp(0, max_x), y.clamp(0, max_y as i16) as u16)
}
// Bottom
Origin::BottomLeft => {
(x.clamp(0, max_x as i16) as u16, max_y.saturating_add_signed(y).clamp(0, max_y))
}
Origin::BottomCenter => (
(columns / 2).saturating_sub(width / 2).saturating_add_signed(x).clamp(0, max_x),
max_y.saturating_add_signed(y).clamp(0, max_y),
),
Origin::BottomRight => (
max_x.saturating_add_signed(x).clamp(0, max_x),
max_y.saturating_add_signed(y).clamp(0, max_y),
),
// Special
// Origin::Hovered => {
// return Origin::rect(&if let Some(r) =
// self.manager.hovered().and_then(|h| self.manager.current().rect_current(&h.url))
// {
// Origin::Sticky(r)
// } else {
// Origin::TopCenter(rect_shim)
// });
// }
Origin::Center => (
(columns / 2).saturating_sub(width / 2).saturating_add_signed(x).clamp(0, max_x),
(max_y / 2).saturating_sub(height / 2).saturating_add_signed(y).clamp(0, max_y),
),
Origin::Hovered => unreachable!(),
};
Rect {
x,
y,
width: width.min(columns.saturating_sub(x)),
height: height.min(rows.saturating_sub(y)),
}
}
Ok(Self {
x: values[0],
y: values[1],
width: values[2] as u16,
height: values[3] as u16,
})
pub fn sticky(base: Rect, offset: Offset) -> Rect {
let Offset { x, y, width, height } = offset;
let WindowSize { columns, rows, .. } = Term::size();
let above =
base.y.saturating_add(base.height).saturating_add(height).saturating_add_signed(y) > rows;
let x = base.x.saturating_add_signed(x).clamp(0, columns.saturating_sub(width));
let y = if above {
base.y.saturating_sub(height.saturating_sub(y.unsigned_abs()))
} else {
base.y.saturating_add(base.height).saturating_add_signed(y)
};
Rect {
x,
y,
width: width.min(columns.saturating_sub(x)),
height: height.min(rows.saturating_sub(y)),
}
}
}

View file

@ -1,14 +1,14 @@
use serde::Deserialize;
use super::position::{Offset, Position};
use super::{Offset, Origin};
use crate::MERGED_YAZI;
#[derive(Debug, Deserialize)]
#[derive(Deserialize)]
pub struct Select {
// open
pub open_title: String,
pub open_position: Position,
pub open_offset: Offset,
pub open_title: String,
pub open_origin: Origin,
pub open_offset: Offset,
}
impl Default for Select {

View file

@ -1,7 +1,5 @@
use crossterm::terminal::WindowSize;
use ratatui::prelude::Rect;
use yazi_config::popup::Position;
use yazi_shared::Term;
use yazi_config::popup::{Origin, Position};
use crate::{completion::Completion, help::Help, input::Input, manager::Manager, select::Select, tasks::Tasks, which::Which};
@ -29,123 +27,12 @@ impl Ctx {
}
pub fn area(&self, pos: &Position) -> Rect {
let WindowSize { columns, rows, .. } = Term::size();
// TODO: hovered
if let Origin::Hovered = pos.origin {
return Rect::default();
}
let (x, y) = match *pos {
Position::TopLeft(Offset { 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::TopRight(Offset { 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::TopCenter(Offset { 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(Offset { 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::BottomCenter(Offset { 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(Offset { 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(Offset { 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_shim, r)
} else {
Position::TopCenter(rect_shim)
});
}
Position::Sticky(Offset { x_offset, y_offset, width, height }, r) => {
let base_x = r.x;
let base_y = r.y;
if base_y.saturating_add(height).saturating_add(r.height).saturating_add_signed(y_offset)
> rows
{
(
base_x.saturating_add_signed(x_offset).max(0).min(columns.saturating_sub(width)),
base_y.saturating_sub(height.saturating_sub(y_offset.unsigned_abs())),
)
} else {
(
base_x.saturating_add_signed(x_offset),
base_y.saturating_add(r.height).saturating_add_signed(y_offset),
)
}
}
};
let (w, h) = pos.dimension();
Rect { x, y, width: w.min(columns.saturating_sub(x)), height: h.min(rows.saturating_sub(y)) }
pos.rect()
}
#[inline]

View file

@ -1,6 +1,6 @@
use std::ffi::OsString;
use yazi_config::{keymap::Exec, popup::SelectOpt, OPEN, SELECT};
use yazi_config::{keymap::Exec, popup::SelectOpt, OPEN};
use yazi_shared::MIME_DIR;
use crate::{emit, external, manager::Manager};

View file

@ -24,16 +24,17 @@ impl Manager {
}
tokio::spawn(async move {
let mut result = emit!(Input(InputOpt::top_center(
format!("{tasks} tasks running, sure to quit? (y/N)",),
Default::default()
)));
// TODO
// let mut result = emit!(Input(InputOpt::top_center(
// format!("{tasks} tasks running, sure to quit? (y/N)",),
// Default::default()
// )));
if let Some(Ok(choice)) = result.recv().await {
if choice == "y" || choice == "Y" {
emit!(Quit(opt.no_cwd_file));
}
}
// if let Some(Ok(choice)) = result.recv().await {
// if choice == "y" || choice == "Y" {
// emit!(Quit(opt.no_cwd_file));
// }
// }
});
false
}

View file

@ -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, popup::InputOpt, INPUT, OPEN, PREVIEW};
use yazi_config::{keymap::Exec, popup::InputOpt, OPEN, PREVIEW};
use yazi_shared::{max_common_root, Defer, Term, Url};
use crate::{emit, external::{self, ShellOpt}, files::{File, FilesOp}, manager::Manager, Event, BLOCKER};

View file

@ -2,7 +2,7 @@ use std::time::Duration;
use tokio::pin;
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::{keymap::{Exec, KeymapLayer}, popup::InputOpt, INPUT};
use yazi_config::{keymap::{Exec, KeymapLayer}, popup::InputOpt};
use yazi_shared::{Debounce, InputError};
use crate::{emit, tab::{Finder, FinderCase, Tab}};
@ -39,7 +39,6 @@ impl Tab {
pub fn find<'a>(&mut self, opt: impl Into<Opt<'a>>) -> 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::find(opt.prev)));
let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));

View file

@ -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}, popup::InputOpt, INPUT};
use yazi_config::{keymap::{Exec, KeymapLayer}, popup::InputOpt};
use crate::{emit, external, files::FilesOp, tab::Tab};

View file

@ -1,4 +1,4 @@
use yazi_config::{keymap::Exec, open::Opener, popup::InputOpt, INPUT};
use yazi_config::{keymap::Exec, open::Opener, popup::InputOpt};
use crate::{emit, tab::Tab};

View file

@ -1,8 +1,8 @@
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, Offset, Position};
use yazi_config::{popup::{Offset, Position}, THEME};
use yazi_core::Ctx;
pub(crate) struct Completion<'a> {
cx: &'a Ctx,
@ -39,15 +39,12 @@ impl<'a> Widget for Completion<'a> {
.collect::<Vec<_>>();
let input_area = self.cx.area(&self.cx.input.position);
let mut area = self.cx.area(&Position::Sticky(
Offset {
x_offset: 1,
y_offset: 0,
width: input_area.width.saturating_sub(2),
height: items.len() as u16 + 2,
},
input_area,
));
let mut area = Position::sticky(input_area, Offset {
x: 1,
y: 0,
width: input_area.width.saturating_sub(2),
height: items.len() as u16 + 2,
});
if area.y > input_area.y {
area.y = area.y.saturating_sub(1);