syntect/highlighting/
theme_set.rs
1use super::super::LoadingError;
2#[cfg(feature = "plist-load")]
3use super::settings::*;
4use super::theme::Theme;
5use serde_derive::{Deserialize, Serialize};
6use std::collections::BTreeMap;
7use std::path::{Path, PathBuf};
8
9#[derive(Debug, Default, Serialize, Deserialize)]
10pub struct ThemeSet {
11 pub themes: BTreeMap<String, Theme>,
13}
14
15impl ThemeSet {
17 pub fn new() -> ThemeSet {
19 ThemeSet::default()
20 }
21
22 pub fn discover_theme_paths<P: AsRef<Path>>(folder: P) -> Result<Vec<PathBuf>, LoadingError> {
26 let mut themes = Vec::new();
27 for entry in crate::utils::walk_dir(folder) {
28 let entry = entry.map_err(LoadingError::WalkDir)?;
29 if entry.path().is_file()
30 && entry
31 .path()
32 .extension()
33 .map_or(false, |e| e.eq_ignore_ascii_case("tmTheme"))
34 {
35 themes.push(entry.path().to_owned());
36 }
37 }
38 Ok(themes)
39 }
40
41 #[cfg(feature = "plist-load")]
43 pub fn get_theme<P: AsRef<Path>>(path: P) -> Result<Theme, LoadingError> {
44 let file = std::fs::File::open(path)?;
45 let mut file = std::io::BufReader::new(file);
46 Self::load_from_reader(&mut file)
47 }
48
49 #[cfg(feature = "plist-load")]
51 pub fn load_from_reader<R: std::io::BufRead + std::io::Seek>(
52 r: &mut R,
53 ) -> Result<Theme, LoadingError> {
54 Ok(Theme::parse_settings(read_plist(r)?)?)
55 }
56
57 #[cfg(feature = "plist-load")]
59 pub fn load_from_folder<P: AsRef<Path>>(folder: P) -> Result<ThemeSet, LoadingError> {
60 let mut theme_set = Self::new();
61 theme_set.add_from_folder(folder)?;
62 Ok(theme_set)
63 }
64
65 #[cfg(feature = "plist-load")]
67 pub fn add_from_folder<P: AsRef<Path>>(&mut self, folder: P) -> Result<(), LoadingError> {
68 let paths = Self::discover_theme_paths(folder)?;
69 for p in &paths {
70 let theme = Self::get_theme(p)?;
71 let basename = p
72 .file_stem()
73 .and_then(|x| x.to_str())
74 .ok_or(LoadingError::BadPath)?;
75 self.themes.insert(basename.to_owned(), theme);
76 }
77
78 Ok(())
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use crate::highlighting::{Color, ThemeSet};
85 #[cfg(feature = "plist-load")]
86 #[test]
87 fn can_parse_common_themes() {
88 let themes = ThemeSet::load_from_folder("testdata").unwrap();
89 let all_themes: Vec<&str> = themes.themes.keys().map(|x| &**x).collect();
90 assert!(all_themes.contains(&"base16-ocean.dark"));
91
92 println!("{:?}", all_themes);
93
94 let theme = ThemeSet::get_theme("testdata/spacegray/base16-ocean.dark.tmTheme").unwrap();
95 assert_eq!(theme.name.unwrap(), "Base16 Ocean Dark");
96 assert_eq!(
97 theme.settings.selection.unwrap(),
98 Color {
99 r: 0x4f,
100 g: 0x5b,
101 b: 0x66,
102 a: 0xff,
103 }
104 );
105 assert_eq!(
106 theme.scopes[0].style.foreground.unwrap(),
107 Color {
108 r: 0xc0,
109 g: 0xc5,
110 b: 0xce,
111 a: 0xff,
112 }
113 );
114 assert_eq!(
115 theme.settings.gutter_foreground.unwrap(),
116 Color {
117 r: 0x65,
118 g: 0x73,
119 b: 0x7e,
120 a: 0xff,
121 }
122 );
123 assert_eq!(
124 theme.settings.gutter.unwrap(),
125 Color {
126 r: 0x34,
127 g: 0x3d,
128 b: 0x46,
129 a: 0xff,
130 }
131 );
132 }
134}