1use std::borrow::Cow;
2
3use mos_core::{AttrValue, Node};
4
5use crate::style::pt_to_f32;
6use crate::{Page, PageStyle};
7
8pub(crate) fn blank_page(number: u32, style: PageStyle) -> Page {
9 Page {
10 number,
11 width_pt: style.width_pt,
12 height_pt: style.height_pt,
13 runs: Vec::new(),
14 images: Vec::new(),
15 }
16}
17
18pub(crate) fn read_level(section: &Node) -> Option<u8> {
19 match section.attributes.get("level") {
20 Some(AttrValue::Int(n)) if *n >= 1 => u8::try_from((*n).clamp(1, 255)).ok(),
21 _ => None,
22 }
23}
24
25pub(crate) fn read_str_attr<'a>(node: &'a Node, key: &str) -> Option<&'a str> {
26 match node.attributes.get(key) {
27 Some(AttrValue::Str(s)) => Some(s.as_str()),
28 _ => None,
29 }
30}
31
32pub(crate) fn read_int_attr(node: &Node, key: &str) -> Option<i64> {
33 match node.attributes.get(key) {
34 Some(AttrValue::Int(n)) => Some(*n),
35 _ => None,
36 }
37}
38
39pub(crate) fn read_length_attr(node: &Node, key: &str) -> Option<f32> {
40 match node.attributes.get(key) {
41 Some(AttrValue::Length(pt)) => Some(pt_to_f32(*pt)),
42 _ => None,
43 }
44}
45
46pub(crate) fn expand_tabs(line: &str, tab_width: usize) -> Cow<'_, str> {
47 if !line.contains('\t') {
48 return Cow::Borrowed(line);
49 }
50
51 let tab_width = tab_width.max(1);
52 let mut out = String::with_capacity(line.len());
53 let mut col = 0_usize;
54 for ch in line.chars() {
55 if ch == '\t' {
56 let spaces = tab_width - (col % tab_width);
57 out.extend(std::iter::repeat_n(' ', spaces));
58 col += spaces;
59 } else {
60 out.push(ch);
61 col += 1;
62 }
63 }
64 Cow::Owned(out)
65}