diff --git a/Cargo.lock b/Cargo.lock index 4f64bfb89..7f1878a25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/example/themes/README.md b/example/themes/README.md index 0102efe73..ec8da20b3 100644 --- a/example/themes/README.md +++ b/example/themes/README.md @@ -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). \ No newline at end of file diff --git a/example/themes/example.kdl b/example/themes/example.kdl new file mode 100644 index 000000000..2a6569dda --- /dev/null +++ b/example/themes/example.kdl @@ -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" + } +} \ No newline at end of file diff --git a/zellij-utils/Cargo.toml b/zellij-utils/Cargo.toml index 766031866..0af9d7c78 100644 --- a/zellij-utils/Cargo.toml +++ b/zellij-utils/Cargo.toml @@ -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] diff --git a/example/themes/catppuccin.kdl b/zellij-utils/assets/themes/catppuccin.kdl similarity index 100% rename from example/themes/catppuccin.kdl rename to zellij-utils/assets/themes/catppuccin.kdl diff --git a/example/themes/dracula.kdl b/zellij-utils/assets/themes/dracula.kdl similarity index 100% rename from example/themes/dracula.kdl rename to zellij-utils/assets/themes/dracula.kdl diff --git a/example/themes/everforest-dark.kdl b/zellij-utils/assets/themes/everforest-dark.kdl similarity index 100% rename from example/themes/everforest-dark.kdl rename to zellij-utils/assets/themes/everforest-dark.kdl diff --git a/example/themes/everforest-light.kdl b/zellij-utils/assets/themes/everforest-light.kdl similarity index 100% rename from example/themes/everforest-light.kdl rename to zellij-utils/assets/themes/everforest-light.kdl diff --git a/example/themes/gruvbox.kdl b/zellij-utils/assets/themes/gruvbox.kdl similarity index 100% rename from example/themes/gruvbox.kdl rename to zellij-utils/assets/themes/gruvbox.kdl diff --git a/example/themes/kanagawa.kdl b/zellij-utils/assets/themes/kanagawa.kdl similarity index 100% rename from example/themes/kanagawa.kdl rename to zellij-utils/assets/themes/kanagawa.kdl diff --git a/example/themes/molokai-dark.kdl b/zellij-utils/assets/themes/molokai-dark.kdl similarity index 100% rename from example/themes/molokai-dark.kdl rename to zellij-utils/assets/themes/molokai-dark.kdl diff --git a/example/themes/nord.kdl b/zellij-utils/assets/themes/nord.kdl similarity index 100% rename from example/themes/nord.kdl rename to zellij-utils/assets/themes/nord.kdl diff --git a/example/themes/one-half-dark.kdl b/zellij-utils/assets/themes/one-half-dark.kdl similarity index 100% rename from example/themes/one-half-dark.kdl rename to zellij-utils/assets/themes/one-half-dark.kdl diff --git a/example/themes/pencil.kdl b/zellij-utils/assets/themes/pencil.kdl similarity index 100% rename from example/themes/pencil.kdl rename to zellij-utils/assets/themes/pencil.kdl diff --git a/example/themes/solarized-dark.kdl b/zellij-utils/assets/themes/solarized-dark.kdl similarity index 100% rename from example/themes/solarized-dark.kdl rename to zellij-utils/assets/themes/solarized-dark.kdl diff --git a/example/themes/solarized-light.kdl b/zellij-utils/assets/themes/solarized-light.kdl similarity index 100% rename from example/themes/solarized-light.kdl rename to zellij-utils/assets/themes/solarized-light.kdl diff --git a/example/themes/tokyo-night-dark.kdl b/zellij-utils/assets/themes/tokyo-night-dark.kdl similarity index 100% rename from example/themes/tokyo-night-dark.kdl rename to zellij-utils/assets/themes/tokyo-night-dark.kdl diff --git a/example/themes/tokyo-night-light.kdl b/zellij-utils/assets/themes/tokyo-night-light.kdl similarity index 100% rename from example/themes/tokyo-night-light.kdl rename to zellij-utils/assets/themes/tokyo-night-light.kdl diff --git a/example/themes/tokyo-night-storm.kdl b/zellij-utils/assets/themes/tokyo-night-storm.kdl similarity index 100% rename from example/themes/tokyo-night-storm.kdl rename to zellij-utils/assets/themes/tokyo-night-storm.kdl diff --git a/example/themes/tokyo-night.kdl b/zellij-utils/assets/themes/tokyo-night.kdl similarity index 100% rename from example/themes/tokyo-night.kdl rename to zellij-utils/assets/themes/tokyo-night.kdl diff --git a/zellij-utils/src/consts.rs b/zellij-utils/src/consts.rs index 5709db891..7599a5ae0 100644 --- a/zellij-utils/src/consts.rs +++ b/zellij-utils/src/consts.rs @@ -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 = 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") { diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index 64fe0bac4..6d2c5958d 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -1734,12 +1734,8 @@ impl Themes { Ok(themes) } - pub fn from_path(path_to_theme_file: PathBuf) -> Result { - // 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 { + 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 { + // 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 { + 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) + } } diff --git a/zellij-utils/src/setup.rs b/zellij-utils/src/setup.rs index 0086c6a99..2466083da 100644 --- a/zellij-utils/src/setup.rs +++ b/zellij-utils/src/setup.rs @@ -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> { ] } +#[cfg(not(test))] +fn get_default_themes() -> Result { + 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 { + 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) -> Option { pub fn get_theme_dir(config_dir: Option) -> Option { 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(