1use std::collections::BTreeMap;
9use std::str::FromStr;
10
11use serde::{Deserialize, json as serde_json};
12
13use crate::Error;
14
15#[derive(Clone, Debug, Deserialize)]
17pub struct RawGrammar {
18 #[serde(rename = "displayName")]
20 pub display_name: Option<String>,
21 pub name: String,
23 #[serde(rename = "scopeName")]
25 pub scope_name: String,
26 #[serde(rename = "fileTypes")]
28 pub file_types: Option<Vec<String>>,
29 #[serde(rename = "firstLineMatch")]
31 pub first_line_match: Option<serde_json::Value>,
32 pub patterns: Vec<RawPattern>,
34 pub repository: Option<BTreeMap<String, RawPattern>>,
36}
37
38#[derive(Clone, Debug, Default, Deserialize)]
40pub struct RawPattern {
41 pub name: Option<String>,
43 #[serde(rename = "match")]
45 pub match_rule: Option<String>,
46 pub begin: Option<String>,
48 pub end: Option<String>,
50 pub patterns: Option<Vec<RawPattern>>,
52 pub include: Option<String>,
54 pub captures: Option<BTreeMap<String, RawCapture>>,
56 #[serde(rename = "beginCaptures")]
58 pub begin_captures: Option<BTreeMap<String, RawCapture>>,
59 #[serde(rename = "endCaptures")]
61 pub end_captures: Option<BTreeMap<String, RawCapture>>,
62}
63
64#[derive(Clone, Debug, Deserialize)]
66pub struct RawCapture {
67 pub name: Option<String>,
69}
70
71#[derive(Clone, Debug, Deserialize)]
73pub struct RawTheme {
74 pub name: String,
76 pub settings: Option<Vec<RawThemeRule>>,
78 #[serde(rename = "tokenColors")]
80 pub token_colors: Option<Vec<RawThemeRule>>,
81}
82
83#[derive(Clone, Debug, Deserialize)]
85pub struct RawThemeRule {
86 pub scope: Option<serde_json::Value>,
88 pub settings: RawStyle,
90}
91
92#[derive(Clone, Debug, Default, Deserialize)]
94pub struct RawStyle {
95 pub foreground: Option<String>,
97 #[serde(rename = "fontStyle")]
99 pub font_style: Option<String>,
100}
101
102impl RawGrammar {
103 pub fn parse(input: &str) -> Result<Self, Error> {
105 input.parse()
106 }
107}
108
109impl FromStr for RawGrammar {
110 type Err = Error;
111
112 fn from_str(input: &str) -> Result<Self, Self::Err> {
113 serde_json::from_str(input).map_err(|_| Error::InvalidGrammar)
114 }
115}
116
117impl RawTheme {
118 pub fn parse(input: &str) -> Result<Self, Error> {
120 input.parse()
121 }
122}
123
124impl FromStr for RawTheme {
125 type Err = Error;
126
127 fn from_str(input: &str) -> Result<Self, Self::Err> {
128 serde_json::from_str(input).map_err(|_| Error::InvalidTheme)
129 }
130}
131
132impl RawThemeRule {
133 pub(crate) fn scope_selectors(&self) -> Vec<String> {
135 let Some(scope) = self.scope.as_ref() else {
136 return Vec::new();
137 };
138 let mut selectors = Vec::new();
139 match scope {
140 serde_json::Value::String(scope) => push_selectors(scope, &mut selectors),
141 serde_json::Value::Array(scopes) => {
142 for scope in scopes {
143 if let serde_json::Value::String(scope) = scope {
144 push_selectors(scope, &mut selectors);
145 }
146 }
147 }
148 _ => {}
149 }
150 selectors
151 }
152}
153
154pub(crate) fn first_line_patterns(value: Option<&serde_json::Value>) -> Vec<String> {
156 match value {
157 Some(serde_json::Value::String(pattern)) => vec![pattern.clone()],
158 Some(serde_json::Value::Array(values)) => values
159 .iter()
160 .filter_map(|value| {
161 if let serde_json::Value::String(pattern) = value {
162 Some(pattern.clone())
163 } else {
164 None
165 }
166 })
167 .collect(),
168 _ => Vec::new(),
169 }
170}
171
172fn push_selectors(input: &str, selectors: &mut Vec<String>) {
174 selectors.extend(
175 input
176 .split(',')
177 .map(str::trim)
178 .filter(|selector| !selector.is_empty())
179 .map(str::to_owned),
180 );
181}