Skip to main content

gitprint/pdf/
toc.rs

1use std::path::PathBuf;
2
3use printpdf::{Color, Pt, Rgb};
4
5use super::layout::{PageBuilder, Span};
6
7/// A single entry in the Table of Contents.
8pub struct TocEntry {
9    pub path: PathBuf,
10    pub line_count: usize,
11    pub size_str: String,
12    pub last_modified: String,
13    pub start_page: usize,
14}
15
16pub fn render(builder: &mut PageBuilder, entries: &[TocEntry]) {
17    let bold = builder.font(true, false).clone();
18    let regular = builder.font(false, false).clone();
19    let gray = Color::Rgb(Rgb::new(0.47, 0.47, 0.47, None));
20    let black = Color::Rgb(Rgb::new(0.0, 0.0, 0.0, None));
21
22    builder.write_centered("Table of Contents", &bold, Pt(16.0), black);
23    builder.vertical_space(10.0);
24
25    entries.iter().for_each(|entry| {
26        let meta = format!(
27            "p.{}  {} LOC \u{00B7} {} \u{00B7} {}",
28            entry.start_page, entry.line_count, entry.size_str, entry.last_modified
29        );
30        builder.write_line_justified(
31            &[Span {
32                text: entry.path.display().to_string(),
33                font_id: regular.clone(),
34                size: Pt(8.0),
35                color: gray.clone(),
36            }],
37            &[Span {
38                text: meta,
39                font_id: regular.clone(),
40                size: Pt(7.0),
41                color: gray.clone(),
42            }],
43        );
44    });
45
46    builder.page_break();
47}
48
49#[cfg(test)]
50mod tests {
51    use crate::pdf;
52    use crate::types::Config;
53    use std::path::PathBuf;
54
55    fn make_entry(path: &str, lines: usize, page: usize) -> super::TocEntry {
56        super::TocEntry {
57            path: PathBuf::from(path),
58            line_count: lines,
59            size_str: "1.2 KB".to_string(),
60            last_modified: "2024-01-15".to_string(),
61            start_page: page,
62        }
63    }
64
65    #[test]
66    fn render_toc_does_not_panic() {
67        let mut doc = printpdf::PdfDocument::new("test");
68        let fonts = pdf::fonts::load_fonts(&mut doc).unwrap();
69        let config = Config::test_default();
70        let mut builder = pdf::create_builder(&config, fonts);
71        let entries = vec![
72            make_entry("src/main.rs", 20, 5),
73            make_entry("src/lib.rs", 50, 7),
74        ];
75        super::render(&mut builder, &entries);
76    }
77
78    #[test]
79    fn render_toc_empty_files() {
80        let mut doc = printpdf::PdfDocument::new("test");
81        let fonts = pdf::fonts::load_fonts(&mut doc).unwrap();
82        let config = Config::test_default();
83        let mut builder = pdf::create_builder(&config, fonts);
84        super::render(&mut builder, &[]);
85    }
86
87    #[test]
88    fn render_toc_many_files() {
89        let mut doc = printpdf::PdfDocument::new("test");
90        let fonts = pdf::fonts::load_fonts(&mut doc).unwrap();
91        let config = Config::test_default();
92        let mut builder = pdf::create_builder(&config, fonts);
93        let entries: Vec<_> = (0..100)
94            .map(|i| make_entry("src/file.rs", i * 10, i + 5))
95            .collect();
96        super::render(&mut builder, &entries);
97    }
98}