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
//! Turning byte offsets into human positions.
/// The 1-based `(line, column)` of byte offset `byte` in `src`, for error
/// messages, linters and editors — pair it with
/// [`NodeRef::source_range`](crate::NodeRef::source_range) or
/// [`ParseError::position`](crate::ParseError::position).
///
/// Lines end at `\n`, `\r\n` (one break) or a lone `\r`. Columns count
/// `char`s (Unicode scalar values), not bytes. Never panics: an offset past
/// the end is clamped to the end, and one inside a multi-byte character to
/// that character's start. Runs in O(`byte`); for many lookups into one large
/// input, precompute line starts instead.
///
/// ```
/// let src = "<ul>\r\n <li>café\n <li>x</ul>";
/// let dom = domq::parse(src);
/// let second = dom.find_by_tag("li").nth(1).unwrap();
/// let start = second.source_range().unwrap().start;
/// assert_eq!(domq::line_col(src, start), (3, 3));
/// assert_eq!(domq::line_col(src, 0), (1, 1));
///
/// let after_e = src.find('é').unwrap() + 'é'.len_utf8();
/// assert_eq!(domq::line_col(src, after_e), (2, 11)); // `é`: 2 bytes, 1 column
/// assert_eq!(domq::line_col(src, after_e - 1), (2, 10)); // mid-char: its start
/// assert_eq!(domq::line_col(src, usize::MAX), (3, 13)); // clamped to the end
/// ```