css_variable_lsp/
types.rs1use ls_types::{Position, Range, Uri};
2use serde::{Deserialize, Serialize};
3
4use crate::color::NormalizedColorKey;
5use crate::runtime_config::RuntimeConfig;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct CssVariable {
10 pub name: String,
12
13 pub value: String,
15
16 pub uri: Uri,
18
19 pub range: Range,
21
22 pub name_range: Option<Range>,
24
25 pub value_range: Option<Range>,
27
28 pub selector: String,
30
31 pub important: bool,
33
34 pub inline: bool,
36
37 pub source_position: usize,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct CssVariableUsage {
44 pub name: String,
46
47 pub uri: Uri,
49
50 pub range: Range,
52
53 pub name_range: Option<Range>,
55
56 pub usage_context: String,
58
59 pub dom_node: Option<DOMNodeInfo>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct LiteralColorOccurrence {
66 pub text: String,
68
69 pub uri: Uri,
71
72 pub range: Range,
74
75 pub usage_context: String,
77
78 pub normalized_color: NormalizedColorKey,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct DOMNodeInfo {
85 pub tag: String,
87
88 pub id: Option<String>,
90
91 pub classes: Vec<String>,
93
94 pub position: usize,
96
97 pub node_index: Option<usize>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct Config {
104 pub lookup_files: Vec<String>,
106
107 pub ignore_globs: Vec<String>,
109
110 pub enable_color_provider: bool,
112
113 pub color_only_on_variables: bool,
115
116 pub max_documents: usize,
118}
119
120impl Default for Config {
121 fn default() -> Self {
122 Self {
123 lookup_files: vec![
124 "**/*.css".to_string(),
125 "**/*.scss".to_string(),
126 "**/*.sass".to_string(),
127 "**/*.less".to_string(),
128 "**/*.html".to_string(),
129 "**/*.vue".to_string(),
130 "**/*.svelte".to_string(),
131 "**/*.astro".to_string(),
132 "**/*.jsx".to_string(),
133 "**/*.tsx".to_string(),
134 "**/*.ripple".to_string(),
135 ],
136 ignore_globs: vec![
137 "**/node_modules/**".to_string(),
138 "**/dist/**".to_string(),
139 "**/out/**".to_string(),
140 "**/.git/**".to_string(),
141 ],
142 enable_color_provider: true,
143 color_only_on_variables: false,
144 max_documents: 10_000, }
146 }
147}
148
149impl Config {
150 pub fn from_runtime(runtime: &RuntimeConfig) -> Self {
151 let mut config = Config::default();
152 if let Some(lookup) = &runtime.lookup_files {
153 if !lookup.is_empty() {
154 config.lookup_files = lookup.clone();
155 }
156 }
157 if let Some(ignore) = &runtime.ignore_globs {
158 if !ignore.is_empty() {
159 config.ignore_globs = ignore.clone();
160 }
161 }
162 config.enable_color_provider = runtime.enable_color_provider;
163 config.color_only_on_variables = runtime.color_only_on_variables;
164 config
165 }
166}
167
168pub fn offset_to_position(text: &str, offset: usize) -> Position {
170 let mut line = 0;
171 let mut character = 0;
172
173 for (idx, ch) in text.char_indices() {
174 if idx >= offset {
175 break;
176 }
177 if ch == '\n' {
178 line += 1;
179 character = 0;
180 } else {
181 character += ch.len_utf16() as u32;
182 }
183 }
184
185 Position::new(line, character)
186}
187
188pub fn position_to_offset(text: &str, position: Position) -> Option<usize> {
190 let mut line = 0;
191 let mut character = 0;
192
193 for (idx, ch) in text.char_indices() {
194 if line == position.line && character == position.character {
195 return Some(idx);
196 }
197 if ch == '\n' {
198 line += 1;
199 character = 0;
200 } else {
201 character += ch.len_utf16() as u32;
202 }
203 }
204
205 if line == position.line && character == position.character {
206 Some(text.len())
207 } else {
208 None
209 }
210}