1#[allow(clippy::module_name_repetitions)]2#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]3pub struct CodeLocation {4 pub offset: usize,56 pub line: usize,7 pub column: usize,89 pub line_start_offset: usize,10 pub line_end_offset: usize,11}1213#[allow(clippy::module_name_repetitions)]14pub fn location_to_offset(mut file: &str, mut line: usize, column: usize) -> Option<usize> {15 let mut offset = 0;16 while line > 1 {17 let pos = file.find('\n')?;18 offset += pos + 1;19 file = &file[pos + 1..];20 line -= 1;21 }22 offset += column - 1;23 Some(offset)24}2526#[allow(clippy::module_name_repetitions)]27pub fn offset_to_location<const S: usize>(file: &str, offsets: &[u32; S]) -> [CodeLocation; S] {28 if offsets.is_empty() {29 return [CodeLocation::default(); S];30 }31 let mut line = 1;32 let mut column = 0;33 let max_offset = *offsets.iter().max().expect("offsets is not empty");3435 let mut offset_map = offsets36 .iter()37 .enumerate()38 .map(|(pos, offset)| (*offset, pos))39 .collect::<Vec<_>>();40 offset_map.sort_by_key(|v| v.0);41 offset_map.reverse();4243 let mut out = [CodeLocation::default(); S];44 let mut with_no_known_line_ending = vec![];45 let mut this_line_offset = 0;46 for (pos, ch) in file47 .chars()48 .enumerate()49 .chain(std::iter::once((file.len(), ' ')))50 {51 column += 1;52 match offset_map.last() {53 Some(x) if x.0 == pos as u32 => {54 let out_idx = x.1;55 with_no_known_line_ending.push(out_idx);56 out[out_idx].offset = pos;57 out[out_idx].line = line;58 out[out_idx].column = column;59 out[out_idx].line_start_offset = this_line_offset;60 offset_map.pop();61 }62 _ => {}63 }64 if ch == '\n' {65 line += 1;66 column = 0;6768 for idx in with_no_known_line_ending.drain(..) {69 out[idx].line_end_offset = pos;70 }71 this_line_offset = pos + 1;7273 if pos == max_offset as usize + 1 {74 break;75 }76 }77 }78 let file_end = file.chars().count();79 for idx in with_no_known_line_ending {80 out[idx].line_end_offset = file_end;81 }8283 out84}8586#[cfg(test)]87pub mod tests {88 use super::{CodeLocation, offset_to_location};8990 #[test]91 fn test() {92 assert_eq!(93 offset_to_location(94 "hello world\n_______________________________________________________",95 &[0, 14]96 ),97 [98 CodeLocation {99 offset: 0,100 line: 1,101 column: 1,102 line_start_offset: 0,103 line_end_offset: 11,104 },105 CodeLocation {106 offset: 14,107 line: 2,108 column: 3,109 line_start_offset: 12,110 line_end_offset: 67111 }112 ]113 )114 }115}