Skip to main content

iris_reader/renderer/
mod.rs

1pub mod markdown;
2pub mod text;
3
4use std::path::Path;
5
6use ratatui::text::Line;
7
8use crate::{
9    image::ImageManager,
10    input::{Input, InputKind},
11    search::{SearchMatch, SearchMatcher},
12    theme::Theme,
13};
14
15pub type NodeId = usize;
16pub type HeadingId = NodeId;
17
18#[derive(Debug, Clone)]
19pub struct RenderedLine {
20    pub line: Line<'static>,
21    pub plain: String,
22    pub source_id: Option<NodeId>,
23}
24
25impl RenderedLine {
26    pub fn empty() -> Self {
27        Self {
28            line: Line::default(),
29            plain: String::new(),
30            source_id: None,
31        }
32    }
33}
34
35#[derive(Debug, Clone)]
36pub struct RenderedHeading {
37    pub id: HeadingId,
38    pub level: u8,
39    pub title: String,
40    pub slug: String,
41    pub line: usize,
42}
43
44#[derive(Debug, Clone)]
45pub struct RenderedLink {
46    pub source_id: NodeId,
47    pub destination: String,
48    pub line: usize,
49    pub start_column: usize,
50    pub end_column: usize,
51}
52
53#[derive(Debug, Clone)]
54pub struct RenderedImage {
55    pub source_id: NodeId,
56    pub source: String,
57    pub alt: String,
58    pub destination: Option<String>,
59    pub line: usize,
60    pub column: usize,
61    pub height: u16,
62}
63
64#[derive(Debug, Clone, Default)]
65pub struct RenderedDocument {
66    pub lines: Vec<RenderedLine>,
67    pub headings: Vec<RenderedHeading>,
68    pub links: Vec<RenderedLink>,
69    pub images: Vec<RenderedImage>,
70    pub max_width: usize,
71}
72
73impl RenderedDocument {
74    pub fn finish(mut self) -> Self {
75        self.max_width = self
76            .lines
77            .iter()
78            .map(|line| unicode_width::UnicodeWidthStr::width(line.plain.as_str()))
79            .max()
80            .unwrap_or(0);
81        self
82    }
83}
84
85pub enum ViewDocument {
86    Text(text::TextDocument),
87    Markdown(markdown::Document),
88}
89
90impl ViewDocument {
91    pub fn from_input(input: &Input) -> Self {
92        match input.kind {
93            InputKind::Text => Self::Text(text::TextDocument::new(&input.content)),
94            InputKind::Markdown => Self::Markdown(markdown::parse(&input.content)),
95        }
96    }
97
98    pub fn render(
99        &self,
100        width: u16,
101        theme: &Theme,
102        wrap: bool,
103        tab_width: usize,
104        images: &mut ImageManager,
105        base_dir: Option<&Path>,
106    ) -> RenderedDocument {
107        match self {
108            Self::Text(document) => text::render(document, width, theme, wrap, tab_width),
109            Self::Markdown(document) => {
110                markdown::render(document, width, theme, wrap, tab_width, images, base_dir)
111            }
112        }
113    }
114
115    pub fn search(&self, matcher: &SearchMatcher) -> Vec<SearchMatch> {
116        match self {
117            Self::Text(document) => document.search(matcher),
118            Self::Markdown(document) => document.search(matcher),
119        }
120    }
121
122    pub fn is_markdown(&self) -> bool {
123        matches!(self, Self::Markdown(_))
124    }
125}