mirror of https://github.com/TaKO8Ki/gobang
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.3 KiB
Rust
107 lines
3.3 KiB
Rust
use std::ops::Range;
|
|
use syntect::{
|
|
highlighting::{
|
|
FontStyle, HighlightState, Highlighter, RangedHighlightIterator, Style, ThemeSet,
|
|
},
|
|
parsing::{ParseState, ScopeStack, SyntaxSet},
|
|
};
|
|
use tui::text::{Span, Spans};
|
|
|
|
struct SyntaxLine {
|
|
items: Vec<(Style, usize, Range<usize>)>,
|
|
}
|
|
|
|
pub struct SyntaxText {
|
|
text: String,
|
|
lines: Vec<SyntaxLine>,
|
|
}
|
|
|
|
impl SyntaxText {
|
|
pub fn new(text: String) -> Self {
|
|
let syntax_set: SyntaxSet = SyntaxSet::load_defaults_nonewlines();
|
|
let theme_set: ThemeSet = ThemeSet::load_defaults();
|
|
|
|
let mut state = ParseState::new(syntax_set.find_syntax_by_extension("sql").unwrap());
|
|
let highlighter = Highlighter::new(&theme_set.themes["base16-eighties.dark"]);
|
|
let mut syntax_lines: Vec<SyntaxLine> = Vec::new();
|
|
let mut highlight_state = HighlightState::new(&highlighter, ScopeStack::new());
|
|
|
|
for (number, line) in text.lines().enumerate() {
|
|
let ops = state.parse_line(line, &syntax_set);
|
|
let iter =
|
|
RangedHighlightIterator::new(&mut highlight_state, &ops[..], line, &highlighter);
|
|
|
|
syntax_lines.push(SyntaxLine {
|
|
items: iter
|
|
.map(|(style, _, range)| (style, number, range))
|
|
.collect(),
|
|
});
|
|
}
|
|
|
|
Self {
|
|
text,
|
|
lines: syntax_lines,
|
|
}
|
|
}
|
|
|
|
pub fn convert(&self) -> tui::text::Text<'_> {
|
|
let mut result_lines: Vec<Spans> = Vec::with_capacity(self.lines.len());
|
|
|
|
for (syntax_line, line_content) in self.lines.iter().zip(self.text.lines()) {
|
|
let mut line_span = Spans(Vec::with_capacity(syntax_line.items.len()));
|
|
|
|
for (style, _, range) in &syntax_line.items {
|
|
let item_content = &line_content[range.clone()];
|
|
let item_style = syntact_style_to_tui(style);
|
|
|
|
line_span.0.push(Span::styled(item_content, item_style));
|
|
}
|
|
|
|
result_lines.push(line_span);
|
|
}
|
|
|
|
result_lines.into()
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a SyntaxText> for tui::text::Text<'a> {
|
|
fn from(v: &'a SyntaxText) -> Self {
|
|
let mut result_lines: Vec<Spans> = Vec::with_capacity(v.lines.len());
|
|
|
|
for (syntax_line, line_content) in v.lines.iter().zip(v.text.lines()) {
|
|
let mut line_span = Spans(Vec::with_capacity(syntax_line.items.len()));
|
|
|
|
for (style, _, range) in &syntax_line.items {
|
|
let item_content = &line_content[range.clone()];
|
|
let item_style = syntact_style_to_tui(style);
|
|
|
|
line_span.0.push(Span::styled(item_content, item_style));
|
|
}
|
|
|
|
result_lines.push(line_span);
|
|
}
|
|
|
|
result_lines.into()
|
|
}
|
|
}
|
|
|
|
fn syntact_style_to_tui(style: &Style) -> tui::style::Style {
|
|
let mut res = tui::style::Style::default().fg(tui::style::Color::Rgb(
|
|
style.foreground.r,
|
|
style.foreground.g,
|
|
style.foreground.b,
|
|
));
|
|
|
|
if style.font_style.contains(FontStyle::BOLD) {
|
|
res = res.add_modifier(tui::style::Modifier::BOLD);
|
|
}
|
|
if style.font_style.contains(FontStyle::ITALIC) {
|
|
res = res.add_modifier(tui::style::Modifier::ITALIC);
|
|
}
|
|
if style.font_style.contains(FontStyle::UNDERLINE) {
|
|
res = res.add_modifier(tui::style::Modifier::UNDERLINED);
|
|
}
|
|
|
|
res
|
|
}
|