///| Rev-list pure helper functions
///|
/// Simple glob matching with * and ? wildcards.
pub fn rev_list_glob_match(pattern : String, text : String) -> Bool {
let p_chars : Array[Char] = []
let t_chars : Array[Char] = []
for ch in pattern {
p_chars.push(ch)
}
for ch in text {
t_chars.push(ch)
}
let mut pi = 0
let mut ti = 0
let mut star_pi = -1
let mut star_ti = -1
while ti < t_chars.length() {
if pi < p_chars.length() && p_chars[pi] == '?' {
// ? matches exactly one character (but not /)
if t_chars[ti] != '/' {
pi += 1
ti += 1
} else if star_pi >= 0 {
pi = star_pi + 1
star_ti += 1
ti = star_ti
} else {
return false
}
} else if pi < p_chars.length() && p_chars[pi] == t_chars[ti] {
pi += 1
ti += 1
} else if pi < p_chars.length() && p_chars[pi] == '*' {
star_pi = pi
star_ti = ti
pi += 1
} else if star_pi >= 0 {
pi = star_pi + 1
star_ti += 1
ti = star_ti
} else {
return false
}
}
while pi < p_chars.length() && p_chars[pi] == '*' {
pi += 1
}
pi >= p_chars.length()
}
///|
/// Find ".." or "..." in a rev-list argument. Returns (position, is_symmetric).
pub fn rev_list_find_range_dots(arg : String) -> (Int, Bool)? {
// Look for "..." first (must check before "..")
match arg.find("...") {
Some(pos) => return Some((pos, true))
None => ()
}
match arg.find("..") {
Some(pos) => Some((pos, false))
None => None
}
}
///|
/// Compute start/end indices for skip/max-count window.
pub fn rev_list_window(
length : Int,
skip_count : Int,
max_count : Int?,
) -> (Int, Int) {
let normalized_skip = rev_list_normalize_skip(skip_count)
let start = if normalized_skip > length { length } else { normalized_skip }
match rev_list_normalize_max_count(max_count) {
Some(count) => {
let end = start + count
(start, if end > length { length } else { end })
}
None => (start, length)
}
}
///|
/// Clamp skip to non-negative.
pub fn rev_list_normalize_skip(skip_count : Int) -> Int {
if skip_count < 0 {
0
} else {
skip_count
}
}
///|
/// Filter invalid max_count (negative values become None).
pub fn rev_list_normalize_max_count(max_count : Int?) -> Int? {
match max_count {
Some(count) if count >= 0 => Some(count)
_ => None
}
}