use std::path::Path;
use super::Fragment;
use super::LINES_PER_CHUNK;
use super::chunker::chunk_naive;
pub(crate) struct OrphanInput<'a> {
pub(crate) file_bytes: &'a [u8],
pub(crate) path: &'a Path,
pub(crate) node_ranges: &'a [(usize, usize)],
pub(crate) file_doc_end: usize,
pub(crate) max_bytes: usize,
}
pub(crate) fn orphan_fragments<'a>(input: OrphanInput<'a>) -> Vec<Fragment<'a>> {
let code = match std::str::from_utf8(input.file_bytes) {
Ok(code) => code,
Err(_) => return Vec::new(),
};
let file_len = code.len();
let doc_end = input.file_doc_end.min(file_len);
let max_bytes = if input.max_bytes == 0 {
file_len
} else {
input.max_bytes
};
let mut ranges: Vec<(usize, usize)> = input.node_ranges.to_vec();
ranges.retain(|(start, end)| start < end && *start < file_len);
ranges.sort_unstable();
let mut merged: Vec<(usize, usize)> = Vec::new();
for (start, end) in ranges {
let end = end.min(file_len);
match merged.last_mut() {
Some(last) if start <= last.1 => {
last.1 = last.1.max(end);
}
_ => merged.push((start, end)),
}
}
let mut regions: Vec<(usize, usize)> = Vec::new();
let mut cursor = doc_end;
for (start, end) in merged {
let start = start.max(doc_end);
if start > cursor {
regions.push((cursor, start));
}
cursor = cursor.max(end);
}
if cursor < file_len {
regions.push((cursor, file_len));
}
let mut orphans = Vec::new();
for (region_start, region_end) in regions {
if region_end <= region_start {
continue;
}
let region_code = &code[region_start..region_end];
let line_base = code[..region_start].bytes().filter(|&b| b == b'\n').count();
let mut fragments = chunk_naive(region_code, input.path, max_bytes, LINES_PER_CHUNK);
for fragment in &mut fragments {
fragment.start_byte_index += region_start;
fragment.end_byte_index += region_start;
fragment.start_line += line_base;
fragment.end_line += line_base;
}
orphans.append(&mut fragments);
}
orphans
}