mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: customizing the number of columns of "which key" component (#571)
This commit is contained in:
parent
a19e263242
commit
28870ad26e
7 changed files with 84 additions and 71 deletions
|
|
@ -113,6 +113,7 @@ hovered = { underline = true }
|
||||||
# : Which {{{
|
# : Which {{{
|
||||||
|
|
||||||
[which]
|
[which]
|
||||||
|
cols = 3
|
||||||
mask = { bg = "black" }
|
mask = { bg = "black" }
|
||||||
cand = { fg = "lightcyan" }
|
cand = { fg = "lightcyan" }
|
||||||
rest = { fg = "darkgray" }
|
rest = { fg = "darkgray" }
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,10 @@ pub struct Tasks {
|
||||||
pub hovered: Style,
|
pub hovered: Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize, Validate)]
|
||||||
pub struct Which {
|
pub struct Which {
|
||||||
|
#[validate(range(min = 1, max = 3, message = "Must be between 1 and 3"))]
|
||||||
|
pub cols: u8,
|
||||||
pub mask: Style,
|
pub mask: Style,
|
||||||
pub cand: Style,
|
pub cand: Style,
|
||||||
pub rest: Style,
|
pub rest: Style,
|
||||||
|
|
@ -139,6 +141,7 @@ impl Default for Theme {
|
||||||
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
||||||
|
|
||||||
check_validation(theme.manager.validate());
|
check_validation(theme.manager.validate());
|
||||||
|
check_validation(theme.which.validate());
|
||||||
|
|
||||||
theme.manager.syntect_theme = expand_path(&theme.manager.syntect_theme);
|
theme.manager.syntect_theme = expand_path(&theme.manager.syntect_theme);
|
||||||
|
|
||||||
|
|
|
||||||
39
yazi-fm/src/which/cand.rs
Normal file
39
yazi-fm/src/which/cand.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
use ratatui::{buffer::Buffer, layout::Rect, text::{Line, Span}, widgets::{Paragraph, Widget}};
|
||||||
|
use yazi_config::{keymap::Control, THEME};
|
||||||
|
|
||||||
|
pub(super) struct Cand<'a> {
|
||||||
|
cand: &'a Control,
|
||||||
|
times: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Cand<'a> {
|
||||||
|
pub(super) fn new(cand: &'a Control, times: usize) -> Self { Self { times, cand } }
|
||||||
|
|
||||||
|
fn keys(&self) -> Vec<String> {
|
||||||
|
self.cand.on[self.times..].iter().map(ToString::to_string).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for Cand<'_> {
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
|
let keys = self.keys();
|
||||||
|
let mut spans = Vec::with_capacity(10);
|
||||||
|
|
||||||
|
// Padding
|
||||||
|
spans.push(Span::raw(" ".repeat(10usize.saturating_sub(keys.join("").len()))));
|
||||||
|
|
||||||
|
// First key
|
||||||
|
spans.push(Span::styled(keys[0].clone(), THEME.which.cand.into()));
|
||||||
|
|
||||||
|
// Rest keys
|
||||||
|
spans.extend(keys.iter().skip(1).map(|k| Span::styled(k, THEME.which.rest.into())));
|
||||||
|
|
||||||
|
// Separator
|
||||||
|
spans.push(Span::styled(&THEME.which.separator, THEME.which.separator_style.into()));
|
||||||
|
|
||||||
|
// Description
|
||||||
|
spans.push(Span::styled(self.cand.desc_or_exec(), THEME.which.desc.into()));
|
||||||
|
|
||||||
|
Paragraph::new(Line::from(spans)).render(area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
use ratatui::{buffer::Buffer, layout, layout::{Constraint, Direction, Rect}, widgets::{Block, Widget}};
|
use ratatui::{buffer::Buffer, layout, layout::{Constraint, Direction, Rect}, widgets::{Block, Widget}};
|
||||||
use yazi_config::THEME;
|
use yazi_config::THEME;
|
||||||
|
|
||||||
use super::Side;
|
use super::Cand;
|
||||||
use crate::{widgets, Ctx};
|
use crate::{widgets, Ctx};
|
||||||
|
|
||||||
|
const PADDING_X: u16 = 1;
|
||||||
|
const PADDING_Y: u16 = 1;
|
||||||
|
|
||||||
pub(crate) struct Which<'a> {
|
pub(crate) struct Which<'a> {
|
||||||
cx: &'a Ctx,
|
cx: &'a Ctx,
|
||||||
}
|
}
|
||||||
|
|
@ -15,31 +18,42 @@ impl<'a> Which<'a> {
|
||||||
impl Widget for Which<'_> {
|
impl Widget for Which<'_> {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let which = &self.cx.which;
|
let which = &self.cx.which;
|
||||||
let mut cands: (Vec<_>, Vec<_>, Vec<_>) = Default::default();
|
let cols = THEME.which.cols as usize;
|
||||||
for (i, &c) in which.cands.iter().enumerate() {
|
|
||||||
match i % 3 {
|
let height = area.height.min(which.cands.len().div_ceil(cols) as u16 + PADDING_Y * 2);
|
||||||
0 => cands.0.push(c),
|
let area = Rect {
|
||||||
1 => cands.1.push(c),
|
x: PADDING_X.min(area.width),
|
||||||
2 => cands.2.push(c),
|
y: area.height.saturating_sub(height + PADDING_Y * 2),
|
||||||
_ => unreachable!(),
|
width: area.width.saturating_sub(PADDING_X * 2),
|
||||||
}
|
height,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Don't render if there's no space
|
||||||
|
if area.height <= PADDING_Y * 2 {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let height = area.height.min(cands.0.len() as u16 + 2);
|
let chunks = {
|
||||||
let y = area.height.saturating_sub(height + 2);
|
use Constraint::*;
|
||||||
let area = Rect { x: area.width.min(1), y, width: area.width.saturating_sub(2), height };
|
layout::Layout::new(Direction::Horizontal, match cols {
|
||||||
|
1 => &[Ratio(1, 1)] as &[Constraint],
|
||||||
let chunks = layout::Layout::new(Direction::Horizontal, [
|
2 => &[Ratio(1, 2), Ratio(1, 2)],
|
||||||
Constraint::Ratio(1, 3),
|
_ => &[Ratio(1, 3), Ratio(1, 3), Ratio(1, 3)],
|
||||||
Constraint::Ratio(1, 3),
|
})
|
||||||
Constraint::Ratio(1, 3),
|
.split(area)
|
||||||
])
|
};
|
||||||
.split(area);
|
|
||||||
|
|
||||||
widgets::Clear.render(area, buf);
|
widgets::Clear.render(area, buf);
|
||||||
Block::new().style(THEME.which.mask.into()).render(area, buf);
|
Block::new().style(THEME.which.mask.into()).render(area, buf);
|
||||||
Side::new(which.times, cands.0).render(chunks[0], buf);
|
|
||||||
Side::new(which.times, cands.1).render(chunks[1], buf);
|
for y in 0..area.height {
|
||||||
Side::new(which.times, cands.2).render(chunks[2], buf);
|
for (x, chunk) in chunks.iter().enumerate() {
|
||||||
|
let Some(&cand) = which.cands.get(y as usize * cols + x) else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
Cand::new(cand, which.times).render(Rect { y: chunk.y + y + 1, height: 1, ..*chunk }, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
mod cand;
|
||||||
mod layout;
|
mod layout;
|
||||||
mod side;
|
|
||||||
|
|
||||||
|
use cand::*;
|
||||||
pub(super) use layout::*;
|
pub(super) use layout::*;
|
||||||
use side::*;
|
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
use ratatui::{buffer::Buffer, layout::Rect, text::{Line, Span}, widgets::{Block, List, ListItem, Padding, Widget}};
|
|
||||||
use yazi_config::{keymap::Control, THEME};
|
|
||||||
|
|
||||||
pub(super) struct Side<'a> {
|
|
||||||
times: usize,
|
|
||||||
cands: Vec<&'a Control>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Side<'a> {
|
|
||||||
pub(super) fn new(times: usize, cands: Vec<&'a Control>) -> Self { Self { times, cands } }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for Side<'_> {
|
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
||||||
let items = self
|
|
||||||
.cands
|
|
||||||
.into_iter()
|
|
||||||
.map(|c| {
|
|
||||||
let mut spans = Vec::with_capacity(10);
|
|
||||||
|
|
||||||
// Keys
|
|
||||||
let keys = c.on[self.times..].iter().map(ToString::to_string).collect::<Vec<_>>();
|
|
||||||
spans.push(Span::raw(" ".repeat(10usize.saturating_sub(keys.join("").len()))));
|
|
||||||
spans.push(Span::styled(keys[0].clone(), THEME.which.cand.into()));
|
|
||||||
spans.extend(
|
|
||||||
keys.iter().skip(1).map(|k| Span::styled(k.to_string(), THEME.which.rest.into())),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Separator
|
|
||||||
spans.push(Span::styled(
|
|
||||||
THEME.which.separator.to_string(),
|
|
||||||
THEME.which.separator_style.into(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Desc / Exec
|
|
||||||
spans.push(Span::styled(c.desc_or_exec(), THEME.which.desc.into()));
|
|
||||||
|
|
||||||
ListItem::new(Line::from(spans))
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
List::new(items).block(Block::new().padding(Padding::new(0, 1, 1, 1))).render(area, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,8 +6,8 @@ function Progress:render(area, offset)
|
||||||
self.area = ui.Rect {
|
self.area = ui.Rect {
|
||||||
x = math.max(0, area.w - offset - 21),
|
x = math.max(0, area.w - offset - 21),
|
||||||
y = area.y,
|
y = area.y,
|
||||||
w = math.max(0, math.min(20, area.w - offset - 1)),
|
w = ya.clamp(0, area.w - offset - 1, 20),
|
||||||
h = 1,
|
h = math.min(1, area.h),
|
||||||
}
|
}
|
||||||
return self:partial_render()
|
return self:partial_render()
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue