css_variable_lsp/
types.rs1use serde::{Deserialize, Serialize};
2use tower_lsp::lsp_types::{Position, Range, Url};
3
4use crate::runtime_config::RuntimeConfig;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CssVariable {
9 pub name: String,
11
12 pub value: String,
14
15 pub uri: Url,
17
18 pub range: Range,
20
21 pub name_range: Option<Range>,
23
24 pub value_range: Option<Range>,
26
27 pub selector: String,
29
30 pub important: bool,
32
33 pub inline: bool,
35
36 pub source_position: usize,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct CssVariableUsage {
43 pub name: String,
45
46 pub uri: Url,
48
49 pub range: Range,
51
52 pub name_range: Option<Range>,
54
55 pub usage_context: String,
57
58 pub dom_node: Option<DOMNodeInfo>,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct DOMNodeInfo {
65 pub tag: String,
67
68 pub id: Option<String>,
70
71 pub classes: Vec<String>,
73
74 pub position: usize,
76
77 pub node_index: Option<usize>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct Config {
84 pub lookup_files: Vec<String>,
86
87 pub ignore_globs: Vec<String>,
89
90 pub enable_color_provider: bool,
92
93 pub color_only_on_variables: bool,
95}
96
97impl Default for Config {
98 fn default() -> Self {
99 Self {
100 lookup_files: vec![
101 "**/*.css".to_string(),
102 "**/*.scss".to_string(),
103 "**/*.sass".to_string(),
104 "**/*.less".to_string(),
105 "**/*.html".to_string(),
106 "**/*.vue".to_string(),
107 "**/*.svelte".to_string(),
108 "**/*.astro".to_string(),
109 "**/*.jsx".to_string(),
110 "**/*.tsx".to_string(),
111 "**/*.ripple".to_string(),
112 ],
113 ignore_globs: vec![
114 "**/node_modules/**".to_string(),
115 "**/dist/**".to_string(),
116 "**/out/**".to_string(),
117 "**/.git/**".to_string(),
118 ],
119 enable_color_provider: true,
120 color_only_on_variables: false,
121 }
122 }
123}
124
125impl Config {
126 pub fn from_runtime(runtime: &RuntimeConfig) -> Self {
127 let mut config = Config::default();
128 if let Some(lookup) = &runtime.lookup_files {
129 if !lookup.is_empty() {
130 config.lookup_files = lookup.clone();
131 }
132 }
133 if let Some(ignore) = &runtime.ignore_globs {
134 if !ignore.is_empty() {
135 config.ignore_globs = ignore.clone();
136 }
137 }
138 config.enable_color_provider = runtime.enable_color_provider;
139 config.color_only_on_variables = runtime.color_only_on_variables;
140 config
141 }
142}
143
144pub fn offset_to_position(text: &str, offset: usize) -> Position {
146 let mut line = 0;
147 let mut character = 0;
148
149 for (idx, ch) in text.char_indices() {
150 if idx >= offset {
151 break;
152 }
153 if ch == '\n' {
154 line += 1;
155 character = 0;
156 } else {
157 character += ch.len_utf16() as u32;
158 }
159 }
160
161 Position::new(line, character)
162}
163
164pub fn position_to_offset(text: &str, position: Position) -> Option<usize> {
166 let mut line = 0;
167 let mut character = 0;
168
169 for (idx, ch) in text.char_indices() {
170 if line == position.line && character == position.character {
171 return Some(idx);
172 }
173 if ch == '\n' {
174 line += 1;
175 character = 0;
176 } else {
177 character += ch.len_utf16() as u32;
178 }
179 }
180
181 if line == position.line && character == position.character {
182 Some(text.len())
183 } else {
184 None
185 }
186}