#[cfg(feature = "syntax-highlighting")]
use syntect::easy::HighlightLines;
#[cfg(feature = "syntax-highlighting")]
use syntect::highlighting::ThemeSet;
#[cfg(feature = "syntax-highlighting")]
use syntect::parsing::SyntaxSet;
#[cfg(feature = "syntax-highlighting")]
use syntect::util::LinesWithEndings;
use ratatui::style::{Color, Style};
use ratatui::text::{Line, Span, Text};
#[cfg(feature = "syntax-highlighting")]
fn syntect_color_to_ratatui(color: syntect::highlighting::Color) -> Color {
Color::Rgb(color.r, color.g, color.b)
}
#[cfg(feature = "syntax-highlighting")]
pub fn highlight_shell_script(code: &str) -> Text<'static> {
let ps = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
let theme = &ts.themes["base16-ocean.dark"];
let syntax = ps
.find_syntax_by_extension("sh")
.or_else(|| ps.find_syntax_by_extension("bash"))
.or_else(|| ps.find_syntax_by_extension("zsh"))
.unwrap_or_else(|| ps.find_syntax_plain_text());
let mut highlighter = HighlightLines::new(syntax, theme);
let mut lines = Vec::new();
for line in LinesWithEndings::from(code) {
let ranges = highlighter.highlight_line(line, &ps).unwrap_or_default();
let mut spans = Vec::new();
for (style, text) in ranges {
let fg = syntect_color_to_ratatui(style.foreground);
let ratatui_style = Style::default().fg(fg);
spans.push(Span::styled(text.to_string(), ratatui_style));
}
lines.push(Line::from(spans));
}
Text::from(lines)
}
#[cfg(not(feature = "syntax-highlighting"))]
pub fn highlight_shell_script(code: &str) -> Text<'static> {
Text::from(code.to_string())
}
pub fn highlight_shell_script_with_style(
code: &str,
dim: bool,
) -> Text<'static> {
let text = highlight_shell_script(code);
let mut numbered_lines = Vec::new();
let line_count = text.lines.len();
let line_num_width = line_count.to_string().len().max(2);
for (idx, line) in text.lines.into_iter().enumerate() {
let line_num = idx + 1;
let line_num_str = format!("{:>width$} ", line_num, width = line_num_width);
let line_num_span = Span::styled(
line_num_str,
Style::default()
.fg(Color::Rgb(100, 100, 100)) .add_modifier(if dim { ratatui::style::Modifier::DIM } else { ratatui::style::Modifier::empty() }),
);
let mut new_spans = vec![line_num_span];
new_spans.extend(line.spans.into_iter().map(|span| {
if dim {
Span::styled(span.content, span.style.add_modifier(ratatui::style::Modifier::DIM))
} else {
span
}
}));
numbered_lines.push(Line::from(new_spans));
}
Text::from(numbered_lines)
}