asciidoc_parser/parser/source_map.rs
1use std::fmt;
2
3/// Generated by preprocessor: Sparse map of result ([`Span`]) line number to a
4/// tuple of file name and line number. This allows us to work backwards from
5/// the pre-processed and unified [`Span`] to the various inputs that were used
6/// to construct it. Line numbers here are 1-based.
7///
8/// [`Span`]: crate::Span
9#[derive(Clone, Default, Eq, PartialEq)]
10pub struct SourceMap {
11 data: Vec<(usize, SourceLine)>,
12}
13
14/// A `SourceLine` represents the original file and line number where a line of
15/// Asciidoc text was found before [include file] and [conditional]
16/// pre-processing occurred.
17///
18/// The first member is the file name as specified on the [include file]
19/// directive. The second member is the 1-based line number.
20///
21/// [include file]: https://docs.asciidoctor.org/asciidoc/latest/directives/include/
22/// [conditional]: https://docs.asciidoctor.org/asciidoc/latest/directives/conditionals/
23#[derive(Clone, Debug, Default, Eq, PartialEq)]
24pub struct SourceLine(pub Option<String>, pub usize);
25
26impl SourceMap {
27 pub(crate) fn append(&mut self, preprocessed_line: usize, source_line: SourceLine) {
28 // IMPORTANT: These _should_ be added in increasing order of
29 // `preprocessed_line`, but this is not enforced.
30 self.data.push((preprocessed_line, source_line));
31 }
32
33 /// Given a 1-based line number in the preprocessed source file, translate
34 /// that to a file name and line number as original inputs to the parsing
35 /// process.
36 pub fn original_file_and_line(&self, key: usize) -> Option<SourceLine> {
37 match self.data.binary_search_by_key(&key, |(k, _)| *k) {
38 Ok(i) => self.data.get(i).map(|(_k, v)| v.clone()),
39 Err(0) => None,
40 Err(i) => self
41 .data
42 .get(i - 1)
43 .map(|(k, v)| SourceLine(v.0.clone(), v.1 + key - k)),
44 }
45 }
46}
47
48impl fmt::Debug for SourceMap {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.debug_map()
51 .entries(self.data.iter().map(|(k, v)| (k, v)))
52 .finish()
53 }
54}