cursive_syntect/
lib.rs

1//! Parse text using a [`syntect`] highlighter.
2//!
3//! The [`parse()`] function can be used to generate a StyledString using a
4//! highlighter and a syntax set.
5//!
6//! [`syntect`]: https://docs.rs/syntect
7#![deny(missing_docs)]
8
9use cursive_core::style;
10use cursive_core::utils::markup::{StyledIndexedSpan, StyledString};
11use cursive_core::utils::span::IndexedCow;
12
13use unicode_width::UnicodeWidthStr;
14
15/// Translate a syntect font style into a set of cursive effects.
16pub fn translate_effects(font_style: syntect::highlighting::FontStyle) -> style::Effects {
17    let mut effects = style::Effects::empty();
18
19    for &(style, effect) in &[
20        (syntect::highlighting::FontStyle::BOLD, style::Effect::Bold),
21        (
22            syntect::highlighting::FontStyle::UNDERLINE,
23            style::Effect::Underline,
24        ),
25        (
26            syntect::highlighting::FontStyle::ITALIC,
27            style::Effect::Italic,
28        ),
29    ] {
30        if font_style.contains(style) {
31            effects.insert(effect);
32        }
33    }
34
35    effects
36}
37
38/// Translate a syntect color into a cursive color.
39pub fn translate_color(color: syntect::highlighting::Color) -> style::Color {
40    style::Color::Rgb(color.r, color.g, color.b)
41}
42
43/// Translate a syntect style into a cursive style.
44pub fn translate_style(style: syntect::highlighting::Style) -> style::Style {
45    let front = translate_color(style.foreground);
46    let back = translate_color(style.background);
47
48    style::Style {
49        color: (front, back).into(),
50        effects: translate_effects(style.font_style),
51    }
52}
53
54/// Parse text using a syntect highlighter.
55pub fn parse<S: Into<String>>(
56    input: S,
57    highlighter: &mut syntect::easy::HighlightLines,
58    syntax_set: &syntect::parsing::SyntaxSet,
59) -> Result<StyledString, syntect::Error> {
60    let input = input.into();
61    let mut spans = Vec::new();
62
63    for line in input.split_inclusive('\n') {
64        for (style, text) in highlighter.highlight_line(line, syntax_set)? {
65            spans.push(StyledIndexedSpan {
66                content: IndexedCow::from_str(text, &input),
67                attr: translate_style(style),
68                width: text.width(),
69            });
70        }
71    }
72
73    Ok(StyledString::with_spans(input, spans))
74}