feat(export): add SyntectHtmlHandler
This commit is contained in:
parent
e4a3247f63
commit
78a6b33aa9
|
@ -199,6 +199,8 @@ By now, orgize provides two features:
|
||||||
|
|
||||||
+ `chrono`: adds the ability to convert `Datetime` into `chrono` structs, disabled by default.
|
+ `chrono`: adds the ability to convert `Datetime` into `chrono` structs, disabled by default.
|
||||||
|
|
||||||
|
+ `syntect`: provides `SyntectHtmlHandler` for highlighting code block, disabled by default.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
|
@ -28,10 +28,10 @@ memchr = "2.2.1"
|
||||||
nom = "5.0.1"
|
nom = "5.0.1"
|
||||||
serde = { version = "1.0.100", optional = true, features = ["derive"] }
|
serde = { version = "1.0.100", optional = true, features = ["derive"] }
|
||||||
serde_indextree = { version = "0.2.0", optional = true }
|
serde_indextree = { version = "0.2.0", optional = true }
|
||||||
|
syntect = { version = "3.2.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
pretty_assertions = "0.6.1"
|
pretty_assertions = "0.6.1"
|
||||||
serde_json = "1.0.40"
|
serde_json = "1.0.40"
|
||||||
slugify = "0.1.0"
|
slugify = "0.1.0"
|
||||||
syntect = "3.2.1"
|
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
use std::env::args;
|
|
||||||
use std::fs;
|
|
||||||
use std::io::{Error, Result, Write};
|
|
||||||
use syntect::{
|
|
||||||
easy::HighlightLines,
|
|
||||||
highlighting::ThemeSet,
|
|
||||||
html::{styled_line_to_highlighted_html, IncludeBackground},
|
|
||||||
parsing::SyntaxSet,
|
|
||||||
};
|
|
||||||
|
|
||||||
use orgize::export::{DefaultHtmlHandler, HtmlHandler};
|
|
||||||
use orgize::{Element, Org};
|
|
||||||
|
|
||||||
pub struct SyntectHtmlHandler {
|
|
||||||
syntax_set: SyntaxSet,
|
|
||||||
theme_set: ThemeSet,
|
|
||||||
default_hanlder: DefaultHtmlHandler,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SyntectHtmlHandler {
|
|
||||||
fn default() -> Self {
|
|
||||||
SyntectHtmlHandler {
|
|
||||||
syntax_set: SyntaxSet::load_defaults_newlines(),
|
|
||||||
theme_set: ThemeSet::load_defaults(),
|
|
||||||
default_hanlder: DefaultHtmlHandler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyntectHtmlHandler {
|
|
||||||
fn highlight(&self, language: Option<&str>, content: &str) -> String {
|
|
||||||
let mut highlighter = HighlightLines::new(
|
|
||||||
language
|
|
||||||
.and_then(|lang| self.syntax_set.find_syntax_by_token(lang))
|
|
||||||
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()),
|
|
||||||
&self.theme_set.themes["InspiredGitHub"],
|
|
||||||
);
|
|
||||||
let regions = highlighter.highlight(content, &self.syntax_set);
|
|
||||||
styled_line_to_highlighted_html(®ions[..], IncludeBackground::No)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HtmlHandler<Error> for SyntectHtmlHandler {
|
|
||||||
fn start<W: Write>(&mut self, mut w: W, element: &Element<'_>) -> Result<()> {
|
|
||||||
match element {
|
|
||||||
Element::InlineSrc(inline_src) => write!(
|
|
||||||
w,
|
|
||||||
"<code>{}</code>",
|
|
||||||
self.highlight(Some(&inline_src.lang), &inline_src.body)
|
|
||||||
)?,
|
|
||||||
Element::SourceBlock(block) => {
|
|
||||||
if block.language.is_empty() {
|
|
||||||
write!(w, "<pre class=\"example\">{}</pre>", block.contents)?;
|
|
||||||
} else {
|
|
||||||
write!(
|
|
||||||
w,
|
|
||||||
"<div class=\"org-src-container\"><pre class=\"src src-{}\">{}</pre></div>",
|
|
||||||
block.language,
|
|
||||||
self.highlight(Some(&block.language), &block.contents)
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Element::FixedWidth { value } => write!(
|
|
||||||
w,
|
|
||||||
"<pre class=\"example\">{}</pre>",
|
|
||||||
self.highlight(None, value)
|
|
||||||
)?,
|
|
||||||
Element::ExampleBlock(block) => write!(
|
|
||||||
w,
|
|
||||||
"<pre class=\"example\">{}</pre>",
|
|
||||||
self.highlight(None, &block.contents)
|
|
||||||
)?,
|
|
||||||
_ => self.default_hanlder.start(w, element)?,
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args: Vec<_> = args().collect();
|
|
||||||
|
|
||||||
if args.len() < 2 {
|
|
||||||
eprintln!("Usage: {} <org-file>", args[0]);
|
|
||||||
} else {
|
|
||||||
let contents = String::from_utf8(fs::read(&args[1]).unwrap()).unwrap();
|
|
||||||
|
|
||||||
let mut writer = Vec::new();
|
|
||||||
Org::parse(&contents)
|
|
||||||
.html_with_handler(&mut writer, SyntectHtmlHandler::default())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("{}", String::from_utf8(writer).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ use crate::elements::Element;
|
||||||
use jetscii::bytes;
|
use jetscii::bytes;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{Error, Write};
|
use std::io::{Error, Write};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub struct Escape<S: AsRef<str>>(pub S);
|
pub struct Escape<S: AsRef<str>>(pub S);
|
||||||
|
|
||||||
|
@ -195,3 +196,93 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
pub struct DefaultHtmlHandler;
|
pub struct DefaultHtmlHandler;
|
||||||
|
|
||||||
impl HtmlHandler<Error> for DefaultHtmlHandler {}
|
impl HtmlHandler<Error> for DefaultHtmlHandler {}
|
||||||
|
|
||||||
|
#[cfg(feature = "syntect")]
|
||||||
|
pub mod syntect_feature {
|
||||||
|
use super::*;
|
||||||
|
use syntect::{
|
||||||
|
easy::HighlightLines,
|
||||||
|
highlighting::ThemeSet,
|
||||||
|
html::{styled_line_to_highlighted_html, IncludeBackground},
|
||||||
|
parsing::SyntaxSet,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct SyntectHtmlHandler<E: From<Error>, H: HtmlHandler<E>> {
|
||||||
|
pub syntax_set: SyntaxSet,
|
||||||
|
pub theme_set: ThemeSet,
|
||||||
|
pub inner: H,
|
||||||
|
error_type: PhantomData<E>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SyntectHtmlHandler<Error, DefaultHtmlHandler> {
|
||||||
|
fn default() -> Self {
|
||||||
|
SyntectHtmlHandler {
|
||||||
|
syntax_set: SyntaxSet::load_defaults_newlines(),
|
||||||
|
theme_set: ThemeSet::load_defaults(),
|
||||||
|
inner: DefaultHtmlHandler,
|
||||||
|
error_type: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: From<Error>, H: HtmlHandler<E>> SyntectHtmlHandler<E, H> {
|
||||||
|
pub fn new(inner: H) -> Self {
|
||||||
|
SyntectHtmlHandler {
|
||||||
|
syntax_set: SyntaxSet::load_defaults_newlines(),
|
||||||
|
theme_set: ThemeSet::load_defaults(),
|
||||||
|
inner,
|
||||||
|
error_type: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight(&self, language: Option<&str>, content: &str) -> String {
|
||||||
|
let mut highlighter = HighlightLines::new(
|
||||||
|
language
|
||||||
|
.and_then(|lang| self.syntax_set.find_syntax_by_token(lang))
|
||||||
|
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()),
|
||||||
|
&self.theme_set.themes["InspiredGitHub"],
|
||||||
|
);
|
||||||
|
let regions = highlighter.highlight(content, &self.syntax_set);
|
||||||
|
styled_line_to_highlighted_html(®ions[..], IncludeBackground::No)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: From<Error>, H: HtmlHandler<E>> HtmlHandler<E> for SyntectHtmlHandler<E, H> {
|
||||||
|
fn start<W: Write>(&mut self, mut w: W, element: &Element<'_>) -> Result<(), E> {
|
||||||
|
match element {
|
||||||
|
Element::InlineSrc(inline_src) => write!(
|
||||||
|
w,
|
||||||
|
"<code>{}</code>",
|
||||||
|
self.highlight(Some(&inline_src.lang), &inline_src.body)
|
||||||
|
)?,
|
||||||
|
Element::SourceBlock(block) => {
|
||||||
|
if block.language.is_empty() {
|
||||||
|
write!(w, "<pre class=\"example\">{}</pre>", block.contents)?;
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
w,
|
||||||
|
"<div class=\"org-src-container\"><pre class=\"src src-{}\">{}</pre></div>",
|
||||||
|
block.language,
|
||||||
|
self.highlight(Some(&block.language), &block.contents)
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Element::FixedWidth { value } => write!(
|
||||||
|
w,
|
||||||
|
"<pre class=\"example\">{}</pre>",
|
||||||
|
self.highlight(None, value)
|
||||||
|
)?,
|
||||||
|
Element::ExampleBlock(block) => write!(
|
||||||
|
w,
|
||||||
|
"<pre class=\"example\">{}</pre>",
|
||||||
|
self.highlight(None, &block.contents)
|
||||||
|
)?,
|
||||||
|
_ => self.inner.start(w, element)?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "syntect")]
|
||||||
|
pub use syntect_feature::*;
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
pub mod html;
|
pub mod html;
|
||||||
pub mod org;
|
pub mod org;
|
||||||
|
|
||||||
pub use html::{DefaultHtmlHandler, HtmlHandler};
|
pub use html::*;
|
||||||
pub use org::{DefaultOrgHandler, OrgHandler};
|
pub use org::*;
|
||||||
|
|
||||||
use std::io::{Error, Write};
|
use std::io::{Error, Write};
|
||||||
|
|
||||||
|
|
|
@ -210,6 +210,8 @@
|
||||||
//!
|
//!
|
||||||
//! + `chrono`: adds the ability to convert `Datetime` into `chrono` structs, disabled by default.
|
//! + `chrono`: adds the ability to convert `Datetime` into `chrono` structs, disabled by default.
|
||||||
//!
|
//!
|
||||||
|
//! + `syntect`: provides `SyntectHtmlHandler` for highlighting code block, disabled by default.
|
||||||
|
//!
|
||||||
//! # License
|
//! # License
|
||||||
//!
|
//!
|
||||||
//! MIT
|
//! MIT
|
||||||
|
|
|
@ -104,10 +104,10 @@ impl<'a> Org<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn html<W: Write>(&self, wrtier: W) -> Result<(), Error> {
|
pub fn html<W: Write>(&self, wrtier: W) -> Result<(), Error> {
|
||||||
self.html_with_handler(wrtier, DefaultHtmlHandler)
|
self.html_with_handler(wrtier, &mut DefaultHtmlHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn html_with_handler<W, H, E>(&self, mut writer: W, mut handler: H) -> Result<(), E>
|
pub fn html_with_handler<W, H, E>(&self, mut writer: W, handler: &mut H) -> Result<(), E>
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
E: From<Error>,
|
E: From<Error>,
|
||||||
|
@ -124,10 +124,10 @@ impl<'a> Org<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn org<W: Write>(&self, wrtier: W) -> Result<(), Error> {
|
pub fn org<W: Write>(&self, wrtier: W) -> Result<(), Error> {
|
||||||
self.org_with_handler(wrtier, DefaultOrgHandler)
|
self.org_with_handler(wrtier, &mut DefaultOrgHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn org_with_handler<W, H, E>(&self, mut writer: W, mut handler: H) -> Result<(), E>
|
pub fn org_with_handler<W, H, E>(&self, mut writer: W, handler: &mut H) -> Result<(), E>
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
E: From<Error>,
|
E: From<Error>,
|
||||||
|
|
Loading…
Reference in a new issue