1use smol_str::SmolStr;
4
5#[derive(Debug, Clone)]
7pub struct HighlightConfig {
8 pub highlighted_lines: Vec<usize>,
10 pub rainbow: bool,
12}
13
14impl Default for HighlightConfig {
15 fn default() -> Self {
16 Self {
17 highlighted_lines: Vec::new(),
18 rainbow: true,
19 }
20 }
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Highlighted<'a> {
29 pub lines: Vec<Line<'a>>,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct Line<'a> {
36 pub number: usize,
38 pub highlighted: bool,
40 pub tokens: Vec<Token<'a>>,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct Token<'a> {
47 pub text: &'a str,
49 pub highlight: Option<&'a str>,
51 pub rainbow: Option<usize>,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct HighlightResult {
58 pub lines: Vec<OwnedLine>,
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct OwnedLine {
65 pub number: usize,
67 pub highlighted: bool,
69 pub tokens: Vec<OwnedToken>,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct OwnedToken {
76 pub text: String,
78 pub highlight: Option<SmolStr>,
80 pub rainbow: Option<usize>,
82}
83
84impl Highlighted<'_> {
85 pub fn to_owned(&self) -> HighlightResult {
87 HighlightResult {
88 lines: self
89 .lines
90 .iter()
91 .map(|line| OwnedLine {
92 number: line.number,
93 highlighted: line.highlighted,
94 tokens: line
95 .tokens
96 .iter()
97 .map(|token| OwnedToken {
98 text: token.text.to_owned(),
99 highlight: token.highlight.map(SmolStr::new),
100 rainbow: token.rainbow,
101 })
102 .collect(),
103 })
104 .collect(),
105 }
106 }
107}
108
109impl HighlightResult {
110 pub fn as_highlighted(&self) -> Highlighted<'_> {
115 Highlighted {
116 lines: self
117 .lines
118 .iter()
119 .map(|line| Line {
120 number: line.number,
121 highlighted: line.highlighted,
122 tokens: line
123 .tokens
124 .iter()
125 .map(|token| Token {
126 text: &token.text,
127 highlight: token.highlight.as_deref(),
128 rainbow: token.rainbow,
129 })
130 .collect(),
131 })
132 .collect(),
133 }
134 }
135
136 pub fn with_highlighted_lines(&self, lines: &[usize]) -> Highlighted<'_> {
138 let mut highlighted = self.as_highlighted();
139 let mut selected = lines.to_vec();
140 selected.sort_unstable();
141 let mut selected = selected.into_iter().peekable();
142
143 for line in &mut highlighted.lines {
144 while selected.peek().is_some_and(|number| *number < line.number) {
145 selected.next();
146 }
147 line.highlighted = selected.peek() == Some(&line.number);
148 }
149 highlighted
150 }
151
152 #[cfg(feature = "render-html")]
153 pub fn render_html(&self, theme: &crate::Theme, config: &crate::RenderHtmlConfig) -> String {
154 crate::render::html::render(self.lines.iter(), Some(theme), &[], config, false)
155 }
156
157 #[cfg(feature = "render-html")]
158 pub fn render_html_classes(&self, config: &crate::RenderHtmlConfig) -> String {
159 crate::render::html::render(self.lines.iter(), None, &[], config, false)
160 }
161
162 #[cfg(feature = "render-html")]
163 pub fn render_html_themes(
164 &self,
165 themes: &[(&str, &crate::Theme)],
166 default_theme: &str,
167 config: &crate::RenderHtmlConfig,
168 ) -> Result<String, crate::Error> {
169 crate::render::html::render_themes(self.lines.iter(), themes, default_theme, config)
170 }
171
172 #[cfg(feature = "render-ansi")]
173 pub fn render_ansi(&self, theme: &crate::Theme) -> String {
174 crate::render::ansi::render(self.lines.iter(), theme)
175 }
176}