on master help sign in
Add themes loader
commitf424a61054a0495336862ff8d90627fb6f5ce572 authorwojciechkepka <wojtek.kepka@protonmail.com> dateSat 19 Jun 2021, 13:21 (5 years ago) parent3b534e1
1 file changed+84−2
helix-view/src/theme.rs+84−2
helix-view/src/theme.rs+84−2
@@ -1,6 +1,11 @@
1−use std::collections::HashMap;
1+use std::{
2+ collections::HashMap,
3+ path::{Path, PathBuf},
4+};
25
6+use anyhow::Context;
37use log::warn;
8+use once_cell::sync::Lazy;
49use serde::{Deserialize, Deserializer};
510use toml::Value;
611
@@ -86,7 +91,84 @@ pub use tui::style::{Color, Modifier, Style};
8691// }
8792
8893/// Color theme for syntax highlighting.
89−#[derive(Debug)]
94+
95+pub static DEFAULT_THEME: Lazy<Theme> = Lazy::new(|| {
96+ toml::from_slice(include_bytes!("../../theme.toml")).expect("Failed to parse default theme")
97+});
98+
99+#[derive(Clone, Debug)]
100+pub struct Loader {
101+ user_dir: PathBuf,
102+ default_dir: PathBuf,
103+}
104+impl Loader {
105+ /// Creates a new loader that can load themes from two directories.
106+ pub fn new<P: AsRef<Path>>(user_dir: P, default_dir: P) -> Self {
107+ Self {
108+ user_dir: user_dir.as_ref().join("themes"),
109+ default_dir: default_dir.as_ref().join("themes"),
110+ }
111+ }
112+
113+ /// Loads a theme first looking in the `user_dir` then in `default_dir`
114+ pub fn load(&self, name: &str) -> Result<Theme, anyhow::Error> {
115+ if name == "default" {
116+ return Ok(self.default());
117+ }
118+ let filename = format!("{}.toml", name);
119+
120+ let user_path = self.user_dir.join(&filename);
121+ let path = if user_path.exists() {
122+ user_path
123+ } else {
124+ self.default_dir.join(filename)
125+ };
126+
127+ let data = std::fs::read(&path)?;
128+ toml::from_slice(data.as_slice()).context("Failed to deserialize theme")
129+ }
130+
131+ pub fn read_names(path: &Path) -> Vec<String> {
132+ std::fs::read_dir(path)
133+ .map(|entries| {
134+ entries
135+ .filter_map(|entry| {
136+ if let Ok(entry) = entry {
137+ let path = entry.path();
138+ if let Some(ext) = path.extension() {
139+ if ext != "toml" {
140+ return None;
141+ }
142+ return Some(
143+ entry
144+ .file_name()
145+ .to_string_lossy()
146+ .trim_end_matches(".toml")
147+ .to_owned(),
148+ );
149+ }
150+ }
151+ None
152+ })
153+ .collect()
154+ })
155+ .unwrap_or_default()
156+ }
157+
158+ /// Lists all theme names available in default and user directory
159+ pub fn names(&self) -> Vec<String> {
160+ let mut names = Self::read_names(&self.user_dir);
161+ names.extend(Self::read_names(&self.default_dir));
162+ names
163+ }
164+
165+ /// Returns the default theme
166+ pub fn default(&self) -> Theme {
167+ DEFAULT_THEME.clone()
168+ }
169+}
170+
171+#[derive(Clone, Debug)]
90172pub struct Theme {
91173 scopes: Vec<String>,
92174 styles: HashMap<String, Style>,