Skip to main content

css_variable_lsp/
text_utils.rs

1use crate::types::{offset_to_position, position_to_offset, CssVariable};
2use ls_types::{Position, Range, TextDocumentContentChangeEvent};
3
4pub fn clamp_to_char_boundary(text: &str, mut idx: usize) -> usize {
5    if idx > text.len() {
6        idx = text.len();
7    }
8    while idx > 0 && !text.is_char_boundary(idx) {
9        idx -= 1;
10    }
11    idx
12}
13
14pub fn is_word_char(c: char) -> bool {
15    c.is_ascii_alphanumeric() || c == '-' || c == '_'
16}
17
18pub fn is_word_byte(b: u8) -> bool {
19    is_word_char(b as char)
20}
21
22pub fn range_contains_position(range: &Range, position: Position) -> bool {
23    range.start <= position && position <= range.end
24}
25
26/// Check if `outer` range completely contains `inner` range
27pub fn range_contains(outer: &Range, inner: &Range) -> bool {
28    outer.start <= inner.start && inner.end <= outer.end
29}
30
31pub fn apply_change_to_text(text: &mut String, change: &TextDocumentContentChangeEvent) {
32    if let Some(range) = change.range {
33        let start = position_to_offset(text, range.start);
34        let end = position_to_offset(text, range.end);
35        if let (Some(start), Some(end)) = (start, end) {
36            if start <= end && end <= text.len() {
37                text.replace_range(start..end, &change.text);
38                return;
39            }
40        }
41    }
42    *text = change.text.clone();
43}
44
45pub fn find_value_range_in_definition(text: &str, def: &CssVariable) -> Option<Range> {
46    let start = position_to_offset(text, def.range.start)?;
47    let end = position_to_offset(text, def.range.end)?;
48    if start >= end || end > text.len() {
49        return None;
50    }
51    let def_text = &text[start..end];
52    let colon_index = def_text.find(':')?;
53    let after_colon = &def_text[colon_index + 1..];
54    let value_trim = def.value.trim();
55    let value_index = after_colon.find(value_trim)?;
56
57    let absolute_start = start + colon_index + 1 + value_index;
58    let absolute_end = absolute_start + value_trim.len();
59
60    Some(Range::new(
61        offset_to_position(text, absolute_start),
62        offset_to_position(text, absolute_end),
63    ))
64}