mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-01-15 01:00:02 +00:00
draft ANSI/SGR format (terminal emulation)
This commit is contained in:
parent
8c9cabfcda
commit
90ddac2033
@ -38,6 +38,9 @@ version = "0.10.68"
|
||||
[dependencies.syntect]
|
||||
version = "5.2.0"
|
||||
|
||||
[dependencies.cansi]
|
||||
version = "2.2.1"
|
||||
|
||||
# development
|
||||
[patch.crates-io]
|
||||
# ggemini = { path = "ggemini" }
|
||||
|
11
README.md
11
README.md
@ -68,8 +68,17 @@ GTK 4 / Libadwaita client written in Rust
|
||||
* [x] Inline
|
||||
* [x] Multiline
|
||||
* [x] Alt
|
||||
* [ ] Terminal emulation*
|
||||
* [x] Syntax highlight* (by [syntect](https://github.com/trishume/syntect))
|
||||
* [ ] Terminal emulation* (by [cansi](https://github.com/colored-rs/cansi))
|
||||
* [x] foreground
|
||||
* [x] background
|
||||
* [ ] intensity
|
||||
* [x] italic
|
||||
* [x] underline
|
||||
* [ ] blink
|
||||
* [ ] reversed
|
||||
* [ ] hidden
|
||||
* [x] strikethrough
|
||||
* [x] Header
|
||||
* [x] H1
|
||||
* [x] H2
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod ansi;
|
||||
pub mod error;
|
||||
mod syntax;
|
||||
mod tag;
|
||||
@ -81,7 +82,7 @@ impl Reader {
|
||||
for line in gemtext.lines() {
|
||||
// Is inline code
|
||||
if let Some(code) = Inline::from(line) {
|
||||
// Try auto-detect code syntax for given `value`
|
||||
// Try auto-detect code syntax for given `value` @TODO optional
|
||||
match syntax.highlight(&code.value, None) {
|
||||
Ok(highlight) => {
|
||||
for (syntax_tag, entity) in highlight {
|
||||
@ -98,12 +99,19 @@ impl Reader {
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Nothing match, append default `Code` tag into the main buffer
|
||||
buffer.insert_with_tags(
|
||||
&mut buffer.end_iter(),
|
||||
&code.value,
|
||||
&[&tag.code.text_tag],
|
||||
);
|
||||
// Try ANSI/SGR format (terminal emulation) @TODO optional
|
||||
for (syntax_tag, entity) in ansi::format(&code.value) {
|
||||
// Register new tag
|
||||
if !tag.text_tag_table.add(&syntax_tag) {
|
||||
todo!()
|
||||
}
|
||||
// Append tag to buffer
|
||||
buffer.insert_with_tags(
|
||||
&mut buffer.end_iter(),
|
||||
&entity,
|
||||
&[&syntax_tag],
|
||||
);
|
||||
}
|
||||
} // @TODO handle
|
||||
}
|
||||
|
||||
@ -151,7 +159,7 @@ impl Reader {
|
||||
};
|
||||
|
||||
// Begin code block construction
|
||||
// Try auto-detect code syntax for given `value` and `alt`
|
||||
// Try auto-detect code syntax for given `value` and `alt` @TODO optional
|
||||
match syntax.highlight(&this.value, alt) {
|
||||
Ok(highlight) => {
|
||||
for (syntax_tag, entity) in highlight {
|
||||
@ -168,14 +176,19 @@ impl Reader {
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Try ANSI/SGR highlight (terminal emulation)
|
||||
|
||||
// Nothing match, append default `Code` tag into the main buffer
|
||||
buffer.insert_with_tags(
|
||||
&mut buffer.end_iter(),
|
||||
&this.value,
|
||||
&[&tag.code.text_tag],
|
||||
);
|
||||
// Try ANSI/SGR format (terminal emulation) @TODO optional
|
||||
for (syntax_tag, entity) in ansi::format(&this.value) {
|
||||
// Register new tag
|
||||
if !tag.text_tag_table.add(&syntax_tag) {
|
||||
todo!()
|
||||
}
|
||||
// Append tag to buffer
|
||||
buffer.insert_with_tags(
|
||||
&mut buffer.end_iter(),
|
||||
&entity,
|
||||
&[&syntax_tag],
|
||||
);
|
||||
}
|
||||
} // @TODO handle
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,72 @@
|
||||
mod tag;
|
||||
use tag::Tag;
|
||||
|
||||
use cansi::{v3::categorise_text, Color};
|
||||
use gtk::{
|
||||
gdk::RGBA,
|
||||
pango::{Style, Underline},
|
||||
prelude::TextTagExt,
|
||||
TextTag,
|
||||
};
|
||||
|
||||
/// Apply `ANSI` format to new buffer
|
||||
pub fn format(source_code: &str) -> Vec<(TextTag, String)> {
|
||||
// Init new line buffer
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
for entity in categorise_text(&source_code) {
|
||||
// Create new tag from default preset
|
||||
let tag = Tag::new();
|
||||
|
||||
// Apply supported decorations
|
||||
if let Some(fg) = entity.fg {
|
||||
tag.text_tag.set_foreground_rgba(Some(&color_to_rgba(fg)));
|
||||
}
|
||||
|
||||
if let Some(bg) = entity.bg {
|
||||
tag.text_tag.set_background_rgba(Some(&color_to_rgba(bg)));
|
||||
}
|
||||
|
||||
if let Some(italic) = entity.italic {
|
||||
if italic {
|
||||
tag.text_tag.set_style(Style::Italic);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(underline) = entity.underline {
|
||||
if underline {
|
||||
tag.text_tag.set_underline(Underline::Single);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(strikethrough) = entity.strikethrough {
|
||||
tag.text_tag.set_strikethrough(strikethrough);
|
||||
}
|
||||
|
||||
// Append
|
||||
buffer.push((tag.text_tag, entity.text.to_string()));
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
fn color_to_rgba(value: Color) -> RGBA {
|
||||
match value {
|
||||
Color::Black => RGBA::new(0.0, 0.0, 0.0, 1.0),
|
||||
Color::Red => RGBA::new(0.8, 0.0, 0.0, 1.0),
|
||||
Color::Green => RGBA::new(0.0, 0.8, 0.0, 1.0),
|
||||
Color::Yellow => RGBA::new(0.8, 0.8, 0.0, 1.0),
|
||||
Color::Blue => RGBA::new(0.0, 0.0, 0.9, 1.0),
|
||||
Color::Magenta => RGBA::new(0.8, 0.0, 0.8, 1.0),
|
||||
Color::Cyan => RGBA::new(0.0, 0.8, 0.8, 1.0),
|
||||
Color::White => RGBA::new(0.9, 0.9, 0.9, 1.0),
|
||||
Color::BrightBlack => RGBA::new(0.5, 0.5, 0.5, 1.0),
|
||||
Color::BrightRed => RGBA::new(1.0, 0.0, 0.0, 1.0),
|
||||
Color::BrightGreen => RGBA::new(0.0, 1.0, 0.0, 1.0),
|
||||
Color::BrightYellow => RGBA::new(1.0, 1.0, 0.0, 1.0),
|
||||
Color::BrightBlue => RGBA::new(0.4, 0.4, 1.0, 1.0),
|
||||
Color::BrightMagenta => RGBA::new(1.0, 0.0, 1.0, 1.0),
|
||||
Color::BrightCyan => RGBA::new(0.0, 1.0, 1.0, 1.0),
|
||||
Color::BrightWhite => RGBA::new(1.0, 1.0, 1.0, 1.0),
|
||||
}
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
use gtk::{TextTag, WrapMode};
|
||||
|
||||
pub struct Code {
|
||||
/// Default [TextTag](https://docs.gtk.org/gtk4/class.TextTag.html) preset
|
||||
/// for ANSI buffer
|
||||
pub struct Tag {
|
||||
pub text_tag: TextTag,
|
||||
}
|
||||
|
||||
impl Code {
|
||||
// Construct
|
||||
impl Tag {
|
||||
// Constructors
|
||||
|
||||
/// Create new `Self`
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
text_tag: TextTag::builder()
|
@ -98,7 +98,7 @@ impl Syntax {
|
||||
Ok(result) => {
|
||||
// Build tags
|
||||
for (style, entity) in result {
|
||||
// Create new tag preset from source
|
||||
// Create new tag from default preset
|
||||
let tag = Tag::new();
|
||||
|
||||
// Tuneup using syntect conversion
|
||||
|
@ -1,4 +1,3 @@
|
||||
mod code;
|
||||
mod h1;
|
||||
mod h2;
|
||||
mod h3;
|
||||
@ -6,7 +5,6 @@ mod list;
|
||||
mod quote;
|
||||
mod title;
|
||||
|
||||
use code::Code;
|
||||
use h1::H1;
|
||||
use h2::H2;
|
||||
use h3::H3;
|
||||
@ -19,7 +17,6 @@ use gtk::TextTagTable;
|
||||
pub struct Tag {
|
||||
pub text_tag_table: TextTagTable,
|
||||
// Tags
|
||||
pub code: Code,
|
||||
pub h1: H1,
|
||||
pub h2: H2,
|
||||
pub h3: H3,
|
||||
@ -32,7 +29,6 @@ impl Tag {
|
||||
// Construct
|
||||
pub fn new() -> Self {
|
||||
// Init components
|
||||
let code = Code::new();
|
||||
let h1 = H1::new();
|
||||
let h2 = H2::new();
|
||||
let h3 = H3::new();
|
||||
@ -43,7 +39,6 @@ impl Tag {
|
||||
// Init tag table
|
||||
let text_tag_table = TextTagTable::new();
|
||||
|
||||
text_tag_table.add(&code.text_tag);
|
||||
text_tag_table.add(&h1.text_tag);
|
||||
text_tag_table.add(&h2.text_tag);
|
||||
text_tag_table.add(&h3.text_tag);
|
||||
@ -54,7 +49,6 @@ impl Tag {
|
||||
Self {
|
||||
text_tag_table,
|
||||
// Tags
|
||||
code,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
|
Loading…
x
Reference in New Issue
Block a user