1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
#[derive(Clone, PartialEq, Debug)] pub struct CodeLocation { pub offset: usize, pub line: usize, pub column: usize, pub line_start_offset: usize, pub line_end_offset: usize, } pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> { if offsets.is_empty() { return vec![]; } let mut line = 1; let mut column = 1; let max_offset = *offsets.iter().max().unwrap(); let mut offset_map = offsets .iter() .enumerate() .map(|(pos, offset)| (*offset, pos)) .collect::<Vec<_>>(); offset_map.sort_by_key(|v| v.0); offset_map.reverse(); let mut out = vec![ CodeLocation { offset: 0, column: 0, line: 0, line_start_offset: 0, line_end_offset: 0 }; offsets.len() ]; let mut with_no_known_line_ending = vec![]; let mut this_line_offset = 0; for (pos, ch) in file .chars() .enumerate() .chain(std::iter::once((file.len(), ' '))) { column += 1; match offset_map.last() { Some(x) if x.0 == pos => { let out_idx = x.1; with_no_known_line_ending.push(out_idx); out[out_idx].offset = pos; out[out_idx].line = line; out[out_idx].column = column; out[out_idx].line_start_offset = this_line_offset; offset_map.pop(); } _ => {} } if ch == '\n' { line += 1; column = 1; for idx in with_no_known_line_ending.drain(..) { out[idx].line_end_offset = pos; } this_line_offset = pos + 1; if pos == max_offset + 1 { break; } } } let file_end = file.chars().count(); for idx in with_no_known_line_ending { out[idx].line_end_offset = file_end; } out } #[cfg(test)] pub mod tests { use super::{offset_to_location, CodeLocation}; #[test] fn test() { assert_eq!( offset_to_location( "hello world\n_______________________________________________________", &[0, 14] ), vec![ CodeLocation { offset: 0, line: 1, column: 2, line_start_offset: 0, line_end_offset: 11, }, CodeLocation { offset: 14, line: 2, column: 4, line_start_offset: 12, line_end_offset: 67 } ] ) } }