Skip to main content

ass_core/parser/incremental/
range_adjust.rs

1//! Byte-range adjustment for incremental text changes
2
3use alloc::string::String;
4use core::ops::Range;
5
6#[cfg(not(feature = "std"))]
7extern crate alloc;
8/// Represents a text change in the source
9#[derive(Debug, Clone)]
10pub struct TextChange {
11    /// Byte range that was modified
12    pub range: Range<usize>,
13    /// Replacement text
14    pub new_text: String,
15    /// Affected line numbers (1-based)
16    pub line_range: Range<u32>,
17}
18
19/// Adjust a byte range for a text change
20///
21/// This function calculates how a range should be adjusted after a text change.
22/// It handles cases where the change is before, after, or overlapping with the range.
23#[must_use]
24pub fn adjust_range_for_change(original_range: Range<usize>, change: &TextChange) -> Range<usize> {
25    // Case 1: Change is entirely before the range
26    if change.range.end <= original_range.start {
27        let new_len = change.new_text.len();
28        let old_len = change.range.end - change.range.start;
29
30        if new_len >= old_len {
31            let offset = new_len - old_len;
32            return (original_range.start + offset)..(original_range.end + offset);
33        }
34        let offset = old_len - new_len;
35        return original_range.start.saturating_sub(offset)
36            ..original_range.end.saturating_sub(offset);
37    }
38
39    // Case 2: Change is entirely after the range
40    if change.range.start >= original_range.end {
41        return original_range;
42    }
43
44    // Case 3: Change overlaps - need careful handling
45    // Start stays same if change starts after range start
46    let new_start = original_range.start.min(change.range.start);
47
48    // End needs adjustment based on size difference
49    let new_len = change.new_text.len();
50    let old_len = change.range.end - change.range.start;
51    let new_end = if change.range.end >= original_range.end {
52        // Change extends past range
53        change.range.start + new_len
54    } else {
55        // Change is within range
56        if new_len >= old_len {
57            original_range.end + (new_len - old_len)
58        } else {
59            original_range.end.saturating_sub(old_len - new_len)
60        }
61    };
62
63    new_start..new_end
64}