mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01: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]
|
||||
cols = 3
|
||||
mask = { bg = "black" }
|
||||
cand = { fg = "lightcyan" }
|
||||
rest = { fg = "darkgray" }
|
||||
|
|
|
|||
|
|
@ -95,8 +95,10 @@ pub struct Tasks {
|
|||
pub hovered: Style,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Deserialize, Serialize, Validate)]
|
||||
pub struct Which {
|
||||
#[validate(range(min = 1, max = 3, message = "Must be between 1 and 3"))]
|
||||
pub cols: u8,
|
||||
pub mask: Style,
|
||||
pub cand: Style,
|
||||
pub rest: Style,
|
||||
|
|
@ -139,6 +141,7 @@ impl Default for Theme {
|
|||
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
||||
|
||||
check_validation(theme.manager.validate());
|
||||
check_validation(theme.which.validate());
|
||||
|
||||
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 yazi_config::THEME;
|
||||
|
||||
use super::Side;
|
||||
use super::Cand;
|
||||
use crate::{widgets, Ctx};
|
||||
|
||||
const PADDING_X: u16 = 1;
|
||||
const PADDING_Y: u16 = 1;
|
||||
|
||||
pub(crate) struct Which<'a> {
|
||||
cx: &'a Ctx,
|
||||
}
|
||||
|
|
@ -15,31 +18,42 @@ impl<'a> Which<'a> {
|
|||
impl Widget for Which<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let which = &self.cx.which;
|
||||
let mut cands: (Vec<_>, Vec<_>, Vec<_>) = Default::default();
|
||||
for (i, &c) in which.cands.iter().enumerate() {
|
||||
match i % 3 {
|
||||
0 => cands.0.push(c),
|
||||
1 => cands.1.push(c),
|
||||
2 => cands.2.push(c),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let cols = THEME.which.cols as usize;
|
||||
|
||||
let height = area.height.min(which.cands.len().div_ceil(cols) as u16 + PADDING_Y * 2);
|
||||
let area = Rect {
|
||||
x: PADDING_X.min(area.width),
|
||||
y: area.height.saturating_sub(height + PADDING_Y * 2),
|
||||
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 y = area.height.saturating_sub(height + 2);
|
||||
let area = Rect { x: area.width.min(1), y, width: area.width.saturating_sub(2), height };
|
||||
|
||||
let chunks = layout::Layout::new(Direction::Horizontal, [
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
])
|
||||
.split(area);
|
||||
let chunks = {
|
||||
use Constraint::*;
|
||||
layout::Layout::new(Direction::Horizontal, match cols {
|
||||
1 => &[Ratio(1, 1)] as &[Constraint],
|
||||
2 => &[Ratio(1, 2), Ratio(1, 2)],
|
||||
_ => &[Ratio(1, 3), Ratio(1, 3), Ratio(1, 3)],
|
||||
})
|
||||
.split(area)
|
||||
};
|
||||
|
||||
widgets::Clear.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);
|
||||
Side::new(which.times, cands.2).render(chunks[2], buf);
|
||||
|
||||
for y in 0..area.height {
|
||||
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 side;
|
||||
|
||||
use cand::*;
|
||||
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 {
|
||||
x = math.max(0, area.w - offset - 21),
|
||||
y = area.y,
|
||||
w = math.max(0, math.min(20, area.w - offset - 1)),
|
||||
h = 1,
|
||||
w = ya.clamp(0, area.w - offset - 1, 20),
|
||||
h = math.min(1, area.h),
|
||||
}
|
||||
return self:partial_render()
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue