mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-26 10:55:12 +03:00
feat: add self-provided themes (#2224)
* chore: move themes to default assets * feat: add self-provided themes * fix: embed themes into binary
This commit is contained in:
parent
a263c34925
commit
63bfe9c5e4
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -1270,6 +1270,25 @@ dependencies = [
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "include_dir"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e"
|
||||
dependencies = [
|
||||
"include_dir_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "include_dir_macros"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.2"
|
||||
@ -4085,6 +4104,7 @@ dependencies = [
|
||||
"colorsys",
|
||||
"crossbeam",
|
||||
"directories-next",
|
||||
"include_dir",
|
||||
"insta",
|
||||
"interprocess",
|
||||
"kdl",
|
||||
|
@ -1,19 +1,5 @@
|
||||
# Themes
|
||||
|
||||
Themes can contain different flavors in one file, or can be created as individual files.
|
||||
It contains examples showing how to write a theme.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
gruvbox.kdl
|
||||
├─ gruvbox-light
|
||||
└─ gruvbox-dark
|
||||
|
||||
or
|
||||
|
||||
gruvbox-light.kdl
|
||||
└─ gruvbox-light
|
||||
|
||||
gruvbox-dark.kdl
|
||||
└─ gruvbox-dark
|
||||
```
|
||||
If you would like to add a theme to zellij, please refer [zellij-utils/assets/themes](../../zellij-utils/assets/themes).
|
34
example/themes/example.kdl
Normal file
34
example/themes/example.kdl
Normal file
@ -0,0 +1,34 @@
|
||||
// This file shows how to write a theme file
|
||||
// using `gruvbox` theme.
|
||||
|
||||
themes {
|
||||
// example of how to set a theme in RGB format
|
||||
gruvbox-light {
|
||||
fg 60 56 54
|
||||
bg 251 82 75
|
||||
black 40 40 40
|
||||
red 205 75 69
|
||||
green 152 151 26
|
||||
yellow 215 153 33
|
||||
blue 69 133 136
|
||||
magenta 177 98 134
|
||||
cyan 104 157 106
|
||||
white 213 196 161
|
||||
orange 214 93 14
|
||||
}
|
||||
|
||||
// example of how to set a theme in HEX format
|
||||
gruvbox-dark {
|
||||
fg "#D5C4A1"
|
||||
bg "#282828"
|
||||
black "#3C3836"
|
||||
red "#CC241D"
|
||||
green "#98971A"
|
||||
yellow "#D79921"
|
||||
blue "#3C8588"
|
||||
magenta "#B16286"
|
||||
cyan "#689D6A"
|
||||
white "#FBF1C7"
|
||||
orange "#D65D0E"
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ miette = { version = "3.3.0", features = ["fancy"] }
|
||||
regex = "1.5.5"
|
||||
tempfile = "3.2.0"
|
||||
kdl = { version = "4.5.0", features = ["span"] }
|
||||
include_dir = "0.7.3"
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Zellij program-wide constants.
|
||||
|
||||
use directories_next::ProjectDirs;
|
||||
use include_dir::{include_dir, Dir};
|
||||
use lazy_static::lazy_static;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::path::PathBuf;
|
||||
@ -15,6 +16,7 @@ pub static DEBUG_MODE: OnceCell<bool> = OnceCell::new();
|
||||
|
||||
pub const SYSTEM_DEFAULT_CONFIG_DIR: &str = "/etc/zellij";
|
||||
pub const SYSTEM_DEFAULT_DATA_DIR_PREFIX: &str = system_default_data_dir();
|
||||
pub static ZELLIJ_THEMES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/assets/themes");
|
||||
|
||||
const fn system_default_data_dir() -> &'static str {
|
||||
if let Some(data_dir) = std::option_env!("PREFIX") {
|
||||
|
@ -1734,12 +1734,8 @@ impl Themes {
|
||||
Ok(themes)
|
||||
}
|
||||
|
||||
pub fn from_path(path_to_theme_file: PathBuf) -> Result<Self, ConfigError> {
|
||||
// String is the theme name
|
||||
let mut file = File::open(path_to_theme_file.clone())?;
|
||||
let mut kdl_config = String::new();
|
||||
file.read_to_string(&mut kdl_config)?;
|
||||
let kdl_config: KdlDocument = kdl_config.parse()?;
|
||||
pub fn from_string(raw_string: String) -> Result<Self, ConfigError> {
|
||||
let kdl_config: KdlDocument = raw_string.parse()?;
|
||||
let kdl_themes = kdl_config.get("themes").ok_or(ConfigError::new_kdl_error(
|
||||
"No theme node found in file".into(),
|
||||
kdl_config.span().offset(),
|
||||
@ -1748,4 +1744,26 @@ impl Themes {
|
||||
let all_themes_in_file = Themes::from_kdl(kdl_themes)?;
|
||||
Ok(all_themes_in_file)
|
||||
}
|
||||
|
||||
pub fn from_path(path_to_theme_file: PathBuf) -> Result<Self, ConfigError> {
|
||||
// String is the theme name
|
||||
let mut file = File::open(path_to_theme_file.clone())?;
|
||||
let mut kdl_config = String::new();
|
||||
file.read_to_string(&mut kdl_config)?;
|
||||
Themes::from_string(kdl_config)
|
||||
}
|
||||
|
||||
pub fn from_dir(path_to_theme_dir: PathBuf) -> Result<Self, ConfigError> {
|
||||
let mut themes = Themes::default();
|
||||
for entry in std::fs::read_dir(path_to_theme_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if let Some(extension) = path.extension() {
|
||||
if extension == "kdl" {
|
||||
themes = themes.merge(Themes::from_path(path)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(themes)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use crate::consts::ASSET_MAP;
|
||||
use crate::consts::ZELLIJ_THEMES_DIR;
|
||||
use crate::input::theme::Themes;
|
||||
use crate::{
|
||||
cli::{CliArgs, Command},
|
||||
@ -51,6 +52,22 @@ fn default_config_dirs() -> Vec<Option<PathBuf>> {
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
fn get_default_themes() -> Result<Themes, ConfigError> {
|
||||
let mut themes = Themes::default();
|
||||
for entry in ZELLIJ_THEMES_DIR.files() {
|
||||
if let Some(entry) = entry.contents_utf8() {
|
||||
themes = themes.merge(Themes::from_string(entry.to_string())?);
|
||||
}
|
||||
}
|
||||
Ok(themes)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn get_default_themes() -> Result<Themes, ConfigError> {
|
||||
Ok(Themes::default())
|
||||
}
|
||||
|
||||
/// Looks for an existing dir, uses that, else returns a
|
||||
/// dir matching the config spec.
|
||||
pub fn get_default_data_dir() -> PathBuf {
|
||||
@ -87,6 +104,7 @@ pub fn get_layout_dir(config_dir: Option<PathBuf>) -> Option<PathBuf> {
|
||||
pub fn get_theme_dir(config_dir: Option<PathBuf>) -> Option<PathBuf> {
|
||||
config_dir.map(|dir| dir.join("themes"))
|
||||
}
|
||||
|
||||
pub fn dump_asset(asset: &[u8]) -> std::io::Result<()> {
|
||||
std::io::stdout().write_all(asset)?;
|
||||
Ok(())
|
||||
@ -310,25 +328,13 @@ impl Setup {
|
||||
None => config.options.clone(),
|
||||
};
|
||||
|
||||
if let Some(theme_dir) = config_options
|
||||
.theme_dir
|
||||
.clone()
|
||||
.or_else(|| get_theme_dir(cli_args.config_dir.clone().or_else(find_default_config_dir)))
|
||||
{
|
||||
if theme_dir.is_dir() {
|
||||
for entry in (theme_dir.read_dir()?).flatten() {
|
||||
if let Some(extension) = entry.path().extension() {
|
||||
if extension == "kdl" {
|
||||
match Themes::from_path(entry.path()) {
|
||||
Ok(themes) => config.themes = config.themes.merge(themes),
|
||||
Err(e) => {
|
||||
log::error!("error loading theme file: {:?}", e);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
config.themes = config.themes.merge(get_default_themes()?);
|
||||
|
||||
let user_theme_dir = config_options.theme_dir.clone().or_else(|| {
|
||||
get_theme_dir(cli_args.config_dir.clone().or_else(find_default_config_dir))
|
||||
});
|
||||
if let Some(user_dir) = user_theme_dir {
|
||||
config.themes = config.themes.merge(Themes::from_dir(user_dir)?);
|
||||
}
|
||||
|
||||
if let Some(Command::Setup(ref setup)) = &cli_args.command {
|
||||
@ -514,6 +520,7 @@ impl Setup {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_completion(shell: &str) {
|
||||
let shell: Shell = match shell.to_lowercase().parse() {
|
||||
Ok(shell) => shell,
|
||||
@ -564,6 +571,7 @@ impl Setup {
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_layout_and_override_config(
|
||||
cli_config_options: Option<&Options>,
|
||||
config: Config,
|
||||
@ -593,6 +601,7 @@ impl Setup {
|
||||
// that needs to take precedence
|
||||
Layout::from_path_or_default(chosen_layout.as_ref(), layout_dir.clone(), config)
|
||||
}
|
||||
|
||||
fn handle_setup_commands(cli_args: &CliArgs) {
|
||||
if let Some(Command::Setup(ref setup)) = &cli_args.command {
|
||||
setup.from_cli().map_or_else(
|
||||
|
Loading…
Reference in New Issue
Block a user