1#[derive(Clone, PartialEq, Debug)]2pub struct CodeLocation {3 pub offset: usize,45 pub line: usize,6 pub column: usize,78 pub line_start_offset: usize,9 pub line_end_offset: usize,10}1112pub fn location_to_offset(mut file: &str, mut line: usize, column: usize) -> Option<usize> {13 let mut offset = 0;14 while line > 1 {15 let pos = file.find('\n')?;16 offset += pos + 1;17 file = &file[pos + 1..];18 line -= 1;19 }20 offset += column - 1;21 Some(offset)22}2324pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {25 if offsets.is_empty() {26 return vec![];27 }28 let mut line = 1;29 let mut column = 1;30 let max_offset = *offsets.iter().max().unwrap();3132 let mut offset_map = offsets33 .iter()34 .enumerate()35 .map(|(pos, offset)| (*offset, pos))36 .collect::<Vec<_>>();37 offset_map.sort_by_key(|v| v.0);38 offset_map.reverse();3940 let mut out = vec![41 CodeLocation {42 offset: 0,43 column: 0,44 line: 0,45 line_start_offset: 0,46 line_end_offset: 047 };48 offsets.len()49 ];50 let mut with_no_known_line_ending = vec![];51 let mut this_line_offset = 0;52 for (pos, ch) in file53 .chars()54 .enumerate()55 .chain(std::iter::once((file.len(), ' ')))56 {57 column += 1;58 match offset_map.last() {59 Some(x) if x.0 == pos => {60 let out_idx = x.1;61 with_no_known_line_ending.push(out_idx);62 out[out_idx].offset = pos;63 out[out_idx].line = line;64 out[out_idx].column = column;65 out[out_idx].line_start_offset = this_line_offset;66 offset_map.pop();67 }68 _ => {}69 }70 if ch == '\n' {71 line += 1;72 column = 1;7374 for idx in with_no_known_line_ending.drain(..) {75 out[idx].line_end_offset = pos;76 }77 this_line_offset = pos + 1;7879 if pos == max_offset + 1 {80 break;81 }82 }83 }84 let file_end = file.chars().count();85 for idx in with_no_known_line_ending {86 out[idx].line_end_offset = file_end;87 }8889 out90}9192#[cfg(test)]93pub mod tests {94 use super::{offset_to_location, CodeLocation};9596 #[test]97 fn test() {98 assert_eq!(99 offset_to_location(100 "hello world\n_______________________________________________________",101 &[0, 14]102 ),103 vec![104 CodeLocation {105 offset: 0,106 line: 1,107 column: 2,108 line_start_offset: 0,109 line_end_offset: 11,110 },111 CodeLocation {112 offset: 14,113 line: 2,114 column: 4,115 line_start_offset: 12,116 line_end_offset: 67117 }118 ]119 )120 }121}