mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat: status color customing
This commit is contained in:
parent
19fcc78a12
commit
ca08a8447a
9 changed files with 119 additions and 63 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -1844,9 +1844,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.12"
|
||||
version = "0.19.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78"
|
||||
checksum = "5f8751d9c1b03c6500c387e96f81f815a4f8e72d142d2d4a9ffa6fedd51ddee7"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"serde",
|
||||
|
|
@ -2328,9 +2328,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.9"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529"
|
||||
checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use serde::Deserialize;
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(try_from = "String")]
|
||||
pub struct Color(style::Color);
|
||||
pub struct Color(pub(super) style::Color);
|
||||
|
||||
impl Default for Color {
|
||||
fn default() -> Self { Self(style::Color::Reset) }
|
||||
|
|
@ -33,10 +33,15 @@ impl Deref for Color {
|
|||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ColorDual {
|
||||
#[serde(default)]
|
||||
pub fg: Color,
|
||||
#[serde(default)]
|
||||
pub bg: Color,
|
||||
impl Color {
|
||||
pub fn fg(&self) -> style::Style { style::Style::new().fg(self.0) }
|
||||
|
||||
pub fn bg(&self) -> style::Style { style::Style::new().bg(self.0) }
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ColorGroup {
|
||||
pub normal: Color,
|
||||
pub select: Color,
|
||||
pub unselect: Color,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
mod color;
|
||||
mod filetype;
|
||||
mod icon;
|
||||
mod style;
|
||||
mod theme;
|
||||
|
||||
pub use color::*;
|
||||
pub use filetype::*;
|
||||
pub use icon::*;
|
||||
pub use style::*;
|
||||
pub use theme::*;
|
||||
|
|
|
|||
40
src/config/theme/style.rs
Normal file
40
src/config/theme/style.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use ratatui::style::{self, Modifier};
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::Color;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Style {
|
||||
pub fg: Option<Color>,
|
||||
pub bg: Option<Color>,
|
||||
pub bold: Option<bool>,
|
||||
pub underline: Option<bool>,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn get(&self) -> style::Style {
|
||||
let mut style = style::Style::new();
|
||||
|
||||
if let Some(fg) = &self.fg {
|
||||
style = style.fg(fg.0);
|
||||
}
|
||||
if let Some(bg) = &self.bg {
|
||||
style = style.bg(bg.0);
|
||||
}
|
||||
if let Some(bold) = self.bold {
|
||||
if bold {
|
||||
style = style.add_modifier(Modifier::BOLD);
|
||||
} else {
|
||||
style = style.remove_modifier(Modifier::BOLD);
|
||||
}
|
||||
}
|
||||
if let Some(underline) = self.underline {
|
||||
if underline {
|
||||
style = style.add_modifier(Modifier::UNDERLINED);
|
||||
} else {
|
||||
style = style.remove_modifier(Modifier::UNDERLINED);
|
||||
}
|
||||
}
|
||||
style
|
||||
}
|
||||
}
|
||||
|
|
@ -3,27 +3,36 @@ use std::{fs, path::PathBuf};
|
|||
use serde::Deserialize;
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
use super::{ColorDual, Filetype, Icon};
|
||||
use super::{ColorGroup, Filetype, Icon, Style};
|
||||
use crate::misc::absolute_path;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Mode {
|
||||
pub normal: ColorDual,
|
||||
pub select: ColorDual,
|
||||
pub unselect: ColorDual,
|
||||
pub struct Tab {
|
||||
pub active: Style,
|
||||
pub inactive: Style,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Tab {
|
||||
pub active: ColorDual,
|
||||
pub inactive: ColorDual,
|
||||
pub struct Status {
|
||||
pub primary: ColorGroup,
|
||||
pub secondary: ColorGroup,
|
||||
pub emphasis: ColorGroup,
|
||||
pub body: ColorGroup,
|
||||
pub info: ColorGroup,
|
||||
pub success: ColorGroup,
|
||||
pub warning: ColorGroup,
|
||||
pub danger: ColorGroup,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Selection {
|
||||
pub normal: ColorDual,
|
||||
pub hovered: ColorDual,
|
||||
pub selected: ColorDual,
|
||||
pub hovered: Style,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Marker {
|
||||
pub selecting: Style,
|
||||
pub selected: Style,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
|
@ -33,9 +42,10 @@ pub struct Syntect {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Theme {
|
||||
pub mode: Mode,
|
||||
pub tab: Tab,
|
||||
pub status: Status,
|
||||
pub selection: Selection,
|
||||
pub marker: Marker,
|
||||
#[serde(deserialize_with = "Filetype::deserialize")]
|
||||
pub filetypes: Vec<Filetype>,
|
||||
#[serde(deserialize_with = "Icon::deserialize")]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use crate::config::{theme, THEME};
|
||||
use crate::config::theme::{self, ColorGroup};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Mode {
|
||||
|
|
@ -12,11 +12,11 @@ pub enum Mode {
|
|||
|
||||
impl Mode {
|
||||
#[inline]
|
||||
pub fn color(&self) -> &theme::ColorDual {
|
||||
pub fn color<'a>(&self, group: &'a ColorGroup) -> &'a theme::Color {
|
||||
match *self {
|
||||
Mode::Normal => &THEME.mode.normal,
|
||||
Mode::Select(_) => &THEME.mode.select,
|
||||
Mode::Unselect(_) => &THEME.mode.unselect,
|
||||
Mode::Normal => &group.normal,
|
||||
Mode::Select(_) => &group.select,
|
||||
Mode::Unselect(_) => &group.unselect,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ pub struct Folder<'a> {
|
|||
|
||||
impl<'a> Folder<'a> {
|
||||
pub fn new(folder: &'a core::manager::Folder) -> Self {
|
||||
Self { folder, is_preview: false, is_selection: false }
|
||||
Self { folder, is_preview: false, is_selection: true }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -28,11 +28,12 @@ impl<'a> Folder<'a> {
|
|||
|
||||
impl<'a> Widget for Folder<'a> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let items = self
|
||||
.folder
|
||||
.paginate()
|
||||
let page = self.folder.paginate();
|
||||
|
||||
let items = page
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
.enumerate()
|
||||
.map(|(i, (k, v))| {
|
||||
let icon = THEME
|
||||
.icons
|
||||
.iter()
|
||||
|
|
@ -40,34 +41,32 @@ impl<'a> Widget for Folder<'a> {
|
|||
.map(|x| x.display.as_ref())
|
||||
.unwrap_or("");
|
||||
|
||||
let name = readable_path(k, &self.folder.cwd);
|
||||
let item = ListItem::new(if v.is_selected {
|
||||
format!("> {} {}", icon, name)
|
||||
} else {
|
||||
format!("{} {}", icon, name)
|
||||
});
|
||||
let hovered = matches!(self.folder.hovered, Some(ref h) if h.path == *k);
|
||||
if v.is_selected {
|
||||
buf.set_style(
|
||||
Rect { x: area.x.saturating_sub(1), y: i as u16 + 1, width: 1, height: 1 },
|
||||
Style::default().fg(Color::Red).bg(Color::Red),
|
||||
);
|
||||
}
|
||||
|
||||
let name = if self.is_selection && v.is_selected {
|
||||
format!(" {} {}", icon, readable_path(k, &self.folder.cwd))
|
||||
} else {
|
||||
format!(" {} {}", icon, readable_path(k, &self.folder.cwd))
|
||||
};
|
||||
|
||||
let hovered = matches!(self.folder.hovered, Some(ref h) if h.path == *k);
|
||||
let mut style = Style::default();
|
||||
if self.is_selection {
|
||||
if hovered {
|
||||
style = style.fg(Color::Black).bg(Color::Red);
|
||||
} else if v.is_selected {
|
||||
style = style.fg(Color::Red);
|
||||
}
|
||||
} else if self.is_preview {
|
||||
if self.is_preview {
|
||||
if hovered {
|
||||
style = style.add_modifier(Modifier::UNDERLINED)
|
||||
}
|
||||
} else {
|
||||
if hovered {
|
||||
style = style.fg(Color::Black).bg(Color::Yellow);
|
||||
} else if v.is_selected {
|
||||
style = style.fg(Color::Red);
|
||||
}
|
||||
}
|
||||
|
||||
item.style(style)
|
||||
ListItem::new(name).style(style)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::{Block, Borders, Widget}};
|
||||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::{Block, Borders, Padding, Widget}};
|
||||
|
||||
use super::{Folder, Preview};
|
||||
use crate::{core::manager::{Mode, ALL_RATIO, CURRENT_RATIO, PARENT_RATIO, PREVIEW_RATIO}, ui::Ctx};
|
||||
|
|
@ -28,7 +28,7 @@ impl<'a> Widget for Layout<'a> {
|
|||
.split(area);
|
||||
|
||||
// Parent
|
||||
let block = Block::default().borders(Borders::RIGHT);
|
||||
let block = Block::default().borders(Borders::RIGHT).padding(Padding::new(1, 0, 0, 0));
|
||||
if let Some(ref parent) = manager.parent() {
|
||||
Folder::new(parent).render(block.inner(chunks[0]), buf);
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ impl<'a> Widget for Layout<'a> {
|
|||
.render(chunks[1], buf);
|
||||
|
||||
// Preview
|
||||
let block = Block::default().borders(Borders::LEFT);
|
||||
let block = Block::default().borders(Borders::LEFT).padding(Padding::new(0, 1, 0, 0));
|
||||
Preview::new(self.cx).render(block.inner(chunks[2]), buf);
|
||||
block.render(chunks[2], buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, style::{Color, Modifier, Style}, widgets::{Paragraph, Widget}};
|
||||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, style::Modifier, widgets::{Paragraph, Widget}};
|
||||
|
||||
use super::Progress;
|
||||
use crate::ui::Ctx;
|
||||
use crate::{config::THEME, ui::Ctx};
|
||||
|
||||
pub struct Layout<'a> {
|
||||
cx: &'a Ctx,
|
||||
|
|
@ -29,19 +29,19 @@ impl<'a> Widget for Layout<'a> {
|
|||
)
|
||||
.split(area);
|
||||
|
||||
Paragraph::new("").style(Style::default().fg(*mode.color().bg)).render(chunks[0], buf);
|
||||
let primary = mode.color(&THEME.status.primary);
|
||||
let secondary = mode.color(&THEME.status.secondary);
|
||||
let body = mode.color(&THEME.status.body);
|
||||
|
||||
Paragraph::new("").style(primary.fg()).render(chunks[0], buf);
|
||||
|
||||
Paragraph::new(format!(" {} ", mode))
|
||||
.style(
|
||||
Style::default().fg(*mode.color().fg).bg(*mode.color().bg).add_modifier(Modifier::BOLD),
|
||||
)
|
||||
.style(primary.bg().fg(**secondary).add_modifier(Modifier::BOLD))
|
||||
.render(chunks[1], buf);
|
||||
|
||||
Paragraph::new(" master ")
|
||||
.style(Style::default().fg(*mode.color().bg).bg(Color::Rgb(72, 77, 102)))
|
||||
.render(chunks[2], buf);
|
||||
Paragraph::new(" master ").style(body.bg().fg(**primary)).render(chunks[2], buf);
|
||||
|
||||
Paragraph::new("").style(Style::default().fg(Color::Rgb(72, 77, 102))).render(chunks[3], buf);
|
||||
Paragraph::new("").style(body.fg()).render(chunks[3], buf);
|
||||
|
||||
Progress::new(self.cx).render(chunks[4], buf);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue