use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::parsing::SyntaxSet;
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Debug)]
pub struct RGBA {
pub red: f64,
pub green: f64,
pub blue: f64,
pub alpha: f64,
}
impl RGBA {
pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
RGBA {
red,
green,
blue,
alpha,
}
}
}
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Debug)]
pub struct RGB {
pub red: f64,
pub green: f64,
pub blue: f64,
}
impl RGB {
pub fn new(red: f64, green: f64, blue: f64) -> Self {
RGB { red, green, blue }
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct ColoredSegment {
pub foreground: RGBA,
pub background: RGBA,
pub content: String,
}
impl ColoredSegment {
pub fn new(string: String) -> Self {
ColoredSegment {
foreground: RGBA::new(0f64, 0f64, 0f64, 1f64),
background: RGBA::new(0f64, 0f64, 0f64, 0f64),
content: string,
}
}
pub fn set_foreground(&mut self, color: RGBA) {
self.foreground = color;
}
pub fn set_background(&mut self, color: RGBA) {
self.background = color;
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct ColoredString {
pub segments: Vec<ColoredSegment>,
}
impl ColoredString {
pub fn new() -> Self {
ColoredString {
segments: Vec::new(),
}
}
pub fn add(&mut self, segment: ColoredSegment) {
self.segments.push(segment);
}
}
lazy_static! {
static ref THEME_SET: ThemeSet = ThemeSet::load_defaults();
static ref SYNTAX_SET: SyntaxSet = SyntaxSet::load_defaults_newlines();
}
pub fn highlight(
code: String,
lang: String,
theme: String,
) -> Result<ColoredString, Box<rhai::EvalAltResult>> {
let syntax = match SYNTAX_SET.find_syntax_by_extension(&lang) {
Some(syntax) => syntax,
None => return Err(format!("Syntax {} not found.", lang).into()),
};
let theme = match THEME_SET.themes.get(&theme) {
Some(theme) => theme,
None => return Err(format!("Theme {} not found.", theme).into()),
};
let mut h = HighlightLines::new(syntax, theme);
let mut cs = ColoredString::new();
for line in code.lines() {
for (style, code) in h.highlight(line, &SYNTAX_SET).iter() {
let mut segment = ColoredSegment::new((*code).into());
let fg = style.foreground;
segment.set_foreground(RGBA::new(
fg.r as f64 / 256f64,
fg.g as f64 / 256f64,
fg.b as f64 / 256f64,
1f64,
));
cs.add(segment);
}
cs.add(ColoredSegment::new("\n".into()));
}
cs.segments.pop();
Ok(cs)
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Size {
pub x: f64,
pub y: f64,
}
impl Size {
pub fn new(x: f64, y: f64) -> Self {
Size { x, y }
}
pub fn scaled(&self, factor: f64) -> Self {
Self::new(self.x * factor, self.y * factor)
}
}
impl Default for Size {
fn default() -> Self {
Size::new(0f64, 0f64)
}
}
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
pub enum Anchor {
North,
South,
East,
West,
Center,
}
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct AudioItem {
name: String,
start: f64,
stretch: f64,
}
impl AudioItem {
pub fn new<S: Into<String>>(name: S) -> AudioItem {
AudioItem {
name: name.into(),
start: 0f64,
stretch: 1f64,
}
}
pub fn set_start(&mut self, start: f64) {
self.start = start;
}
pub fn set_stretch(&mut self, stretch: f64) {
self.stretch = stretch;
}
}