Highlight code with line numbers prepended. Returns lines in the format: `{line_number} | {highlighted_code}`
(
content: &str,
file_ext: &str,
hl_theme: HighlightTheme,
line_num_style: Style,
separator_style: Style,
)
| 131 | /// |
| 132 | /// Returns lines in the format: `{line_number} | {highlighted_code}` |
| 133 | pub fn highlight_code_with_line_numbers<'a>( |
| 134 | content: &str, |
| 135 | file_ext: &str, |
| 136 | hl_theme: HighlightTheme, |
| 137 | line_num_style: Style, |
| 138 | separator_style: Style, |
| 139 | ) -> Vec<Line<'a>> { |
| 140 | let syntax = SYNTAX_SET |
| 141 | .find_syntax_by_extension(file_ext) |
| 142 | .unwrap_or_else(|| SYNTAX_SET.find_syntax_plain_text()); |
| 143 | |
| 144 | let theme = &THEME_SET.themes[hl_theme.syntect_theme_name()]; |
| 145 | let mut highlighter = HighlightLines::new(syntax, theme); |
| 146 | let mut lines = Vec::new(); |
| 147 | |
| 148 | let total_lines = content.lines().count(); |
| 149 | let num_width = total_lines.to_string().len().max(3); |
| 150 | |
| 151 | for (i, line_str) in LinesWithEndings::from(content).enumerate() { |
| 152 | let line_num = i + 1; |
| 153 | let mut spans = vec![ |
| 154 | Span::styled( |
| 155 | format!("{:>width$}", line_num, width = num_width), |
| 156 | line_num_style, |
| 157 | ), |
| 158 | Span::styled(" \u{2502} ", separator_style), // │ |
| 159 | ]; |
| 160 | |
| 161 | match highlighter.highlight_line(line_str, &SYNTAX_SET) { |
| 162 | Ok(ranges) => { |
| 163 | for (style, text) in ranges { |
| 164 | spans.push(Span::styled( |
| 165 | text.trim_end_matches('\n').to_string(), |
| 166 | syntect_to_ratatui_style(&style), |
| 167 | )); |
| 168 | } |
| 169 | } |
| 170 | Err(_) => { |
| 171 | spans.push(Span::raw(line_str.trim_end_matches('\n').to_string())); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | lines.push(Line::from(spans)); |
| 176 | } |
| 177 | |
| 178 | lines |
| 179 | } |
| 180 | |
| 181 | /// Extract file extension from a file path. |
| 182 | /// Returns "txt" if no extension is found. |
no test coverage detected