feat(export): export Org struct as org
This commit is contained in:
parent
53d8f9dc90
commit
73380b26bc
|
@ -1,4 +1,4 @@
|
||||||
//! Org-mode elements module
|
//! Org-mode elements
|
||||||
|
|
||||||
mod block;
|
mod block;
|
||||||
mod clock;
|
mod clock;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
//! Export `Org` struct to various formats.
|
||||||
|
|
||||||
pub mod html;
|
pub mod html;
|
||||||
// pub mod org;
|
pub mod org;
|
||||||
|
|
||||||
pub use html::{DefaultHtmlHandler, HtmlHandler};
|
pub use html::{DefaultHtmlHandler, HtmlHandler};
|
||||||
// pub use org::{DefaultOrgHandler, OrgHandler};
|
pub use org::{DefaultOrgHandler, OrgHandler};
|
||||||
|
|
219
src/export/org.rs
Normal file
219
src/export/org.rs
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
use crate::elements::Element;
|
||||||
|
use std::io::{Error, Write};
|
||||||
|
|
||||||
|
pub trait OrgHandler<E: From<Error>> {
|
||||||
|
fn start<W: Write>(&mut self, mut w: W, element: &Element) -> Result<(), E> {
|
||||||
|
use Element::*;
|
||||||
|
|
||||||
|
match element {
|
||||||
|
// container elements
|
||||||
|
Block(block) => {
|
||||||
|
write!(&mut w, "#+BEGIN_{}", block.name)?;
|
||||||
|
if let Some(parameters) = block.args {
|
||||||
|
write!(&mut w, " {}", parameters)?;
|
||||||
|
}
|
||||||
|
writeln!(&mut w)?;
|
||||||
|
}
|
||||||
|
Bold => write!(w, "*")?,
|
||||||
|
Document => (),
|
||||||
|
DynBlock(dyn_block) => {
|
||||||
|
write!(&mut w, "#+BEGIN: {}", dyn_block.block_name)?;
|
||||||
|
if let Some(parameters) = dyn_block.arguments {
|
||||||
|
write!(&mut w, " {}", parameters)?;
|
||||||
|
}
|
||||||
|
writeln!(&mut w)?;
|
||||||
|
}
|
||||||
|
Headline => (),
|
||||||
|
List(_list) => (),
|
||||||
|
Italic => write!(w, "/")?,
|
||||||
|
ListItem(list_item) => write!(w, "{}", list_item.bullet)?,
|
||||||
|
Paragraph => (),
|
||||||
|
Section => (),
|
||||||
|
Strike => write!(w, "+")?,
|
||||||
|
Underline => write!(w, "_")?,
|
||||||
|
Drawer(drawer) => writeln!(w, ":{}:", drawer.name)?,
|
||||||
|
// non-container elements
|
||||||
|
BabelCall(_babel_call) => (),
|
||||||
|
InlineSrc(inline_src) => {
|
||||||
|
write!(&mut w, "src_{}", inline_src.lang)?;
|
||||||
|
if let Some(options) = inline_src.options {
|
||||||
|
write!(&mut w, "[{}]", options)?;
|
||||||
|
}
|
||||||
|
write!(&mut w, "{{{}}}", inline_src.body)?;
|
||||||
|
}
|
||||||
|
Code { value } => write!(w, "~{}~", value)?,
|
||||||
|
FnRef(fn_ref) => {
|
||||||
|
write!(&mut w, "[fn:")?;
|
||||||
|
if let Some(label) = fn_ref.label {
|
||||||
|
write!(&mut w, "{}", label)?;
|
||||||
|
}
|
||||||
|
if let Some(definition) = fn_ref.definition {
|
||||||
|
write!(&mut w, ":{}", definition)?;
|
||||||
|
}
|
||||||
|
write!(&mut w, "]")?;
|
||||||
|
}
|
||||||
|
InlineCall(inline_call) => {
|
||||||
|
write!(&mut w, "call_{}", inline_call.name)?;
|
||||||
|
if let Some(header) = inline_call.inside_header {
|
||||||
|
write!(&mut w, "[{}]", header)?;
|
||||||
|
}
|
||||||
|
write!(&mut w, "({})", inline_call.arguments)?;
|
||||||
|
if let Some(header) = inline_call.end_header {
|
||||||
|
write!(&mut w, "[{}]", header)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Link(link) => {
|
||||||
|
write!(&mut w, "[[{}]", link.path)?;
|
||||||
|
if let Some(desc) = link.desc {
|
||||||
|
write!(&mut w, "[{}]", desc)?;
|
||||||
|
}
|
||||||
|
write!(&mut w, "]")?;
|
||||||
|
}
|
||||||
|
Macros(_macros) => (),
|
||||||
|
Planning(_planning) => (),
|
||||||
|
RadioTarget(_radio_target) => (),
|
||||||
|
Snippet(snippet) => write!(w, "@@{}:{}@@", snippet.name, snippet.value)?,
|
||||||
|
Target(_target) => (),
|
||||||
|
Text { value } => write!(w, "{}", value)?,
|
||||||
|
Timestamp(timestamp) => {
|
||||||
|
use crate::elements::{Date, Time, Timestamp::*};
|
||||||
|
|
||||||
|
fn write_date<W: Write>(mut w: W, date: &Date) -> Result<(), Error> {
|
||||||
|
write!(
|
||||||
|
w,
|
||||||
|
"{}-{}-{} {}",
|
||||||
|
date.year, date.month, date.day, date.dayname
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_time<W: Write>(mut w: W, time: &Option<Time>) -> Result<(), Error> {
|
||||||
|
if let Some(time) = time {
|
||||||
|
write!(w, " {}:{}", time.hour, time.minute)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match timestamp {
|
||||||
|
Active {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write!(&mut w, "<")?;
|
||||||
|
write_date(&mut w, start_date)?;
|
||||||
|
write_time(&mut w, start_time)?;
|
||||||
|
write!(&mut w, ">")?;
|
||||||
|
}
|
||||||
|
Inactive {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write!(&mut w, "[")?;
|
||||||
|
write_date(&mut w, start_date)?;
|
||||||
|
write_time(&mut w, start_time)?;
|
||||||
|
write!(&mut w, "]")?;
|
||||||
|
}
|
||||||
|
ActiveRange {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
end_date,
|
||||||
|
end_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write!(&mut w, "<")?;
|
||||||
|
write_date(&mut w, start_date)?;
|
||||||
|
write_time(&mut w, start_time)?;
|
||||||
|
write!(&mut w, ">--<")?;
|
||||||
|
write_date(&mut w, end_date)?;
|
||||||
|
write_time(&mut w, end_time)?;
|
||||||
|
write!(&mut w, ">")?;
|
||||||
|
}
|
||||||
|
InactiveRange {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
end_date,
|
||||||
|
end_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write!(&mut w, "[")?;
|
||||||
|
write_date(&mut w, start_date)?;
|
||||||
|
write_time(&mut w, start_time)?;
|
||||||
|
write!(&mut w, "]--[")?;
|
||||||
|
write_date(&mut w, end_date)?;
|
||||||
|
write_time(&mut w, end_time)?;
|
||||||
|
write!(&mut w, "]")?;
|
||||||
|
}
|
||||||
|
Diary(value) => write!(w, "<%%({})>", value)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Verbatim { value } => write!(w, "={}=", value)?,
|
||||||
|
FnDef(_fn_def) => (),
|
||||||
|
Clock(_clock) => (),
|
||||||
|
Comment { value } => write!(w, "{}", value)?,
|
||||||
|
FixedWidth { value } => write!(w, "{}", value)?,
|
||||||
|
Keyword(keyword) => {
|
||||||
|
write!(&mut w, "#+{}", keyword.key)?;
|
||||||
|
if let Some(optional) = keyword.optional {
|
||||||
|
write!(&mut w, "[{}]", optional)?;
|
||||||
|
}
|
||||||
|
writeln!(&mut w, ": {}", keyword.value)?;
|
||||||
|
}
|
||||||
|
Rule => writeln!(w, "-----")?,
|
||||||
|
Cookie(_cookie) => (),
|
||||||
|
Title(title) => {
|
||||||
|
for _ in 0..title.level {
|
||||||
|
write!(&mut w, "*")?;
|
||||||
|
}
|
||||||
|
if let Some(keyword) = title.keyword {
|
||||||
|
write!(&mut w, " {}", keyword)?;
|
||||||
|
}
|
||||||
|
if let Some(priority) = title.priority {
|
||||||
|
write!(&mut w, " [#{}]", priority)?;
|
||||||
|
}
|
||||||
|
write!(&mut w, " ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end<W: Write>(&mut self, mut w: W, element: &Element) -> Result<(), E> {
|
||||||
|
use Element::*;
|
||||||
|
|
||||||
|
match element {
|
||||||
|
// container elements
|
||||||
|
Block(block) => writeln!(w, "#+END_{}", block.name)?,
|
||||||
|
Bold => write!(w, "*")?,
|
||||||
|
Document => (),
|
||||||
|
DynBlock(_dyn_block) => writeln!(w, "#+END:")?,
|
||||||
|
Headline => (),
|
||||||
|
List(_list) => (),
|
||||||
|
Italic => write!(w, "/")?,
|
||||||
|
ListItem(_) => (),
|
||||||
|
Paragraph => write!(w, "\n\n")?,
|
||||||
|
Section => (),
|
||||||
|
Strike => write!(w, "+")?,
|
||||||
|
Underline => write!(w, "_")?,
|
||||||
|
Drawer(_) => writeln!(w, ":END:")?,
|
||||||
|
Title(title) => {
|
||||||
|
if !title.tags.is_empty() {
|
||||||
|
write!(&mut w, " :")?;
|
||||||
|
}
|
||||||
|
for tag in &title.tags {
|
||||||
|
write!(&mut w, "{}:", tag)?;
|
||||||
|
}
|
||||||
|
writeln!(&mut w)?;
|
||||||
|
}
|
||||||
|
// non-container elements
|
||||||
|
_ => debug_assert!(!element.is_container()),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DefaultOrgHandler;
|
||||||
|
|
||||||
|
impl OrgHandler<Error> for DefaultOrgHandler {}
|
|
@ -88,7 +88,7 @@
|
||||||
//! use std::io::{Error as IOError, Write};
|
//! use std::io::{Error as IOError, Write};
|
||||||
//! use std::string::FromUtf8Error;
|
//! use std::string::FromUtf8Error;
|
||||||
//!
|
//!
|
||||||
//! use orgize::export::{html::Escape, DefaultHtmlHandler, HtmlHandler};
|
//! use orgize::export::{DefaultHtmlHandler, HtmlHandler};
|
||||||
//! use orgize::{Element, Org};
|
//! use orgize::{Element, Org};
|
||||||
//! use slugify::slugify;
|
//! use slugify::slugify;
|
||||||
//!
|
//!
|
||||||
|
|
20
src/org.rs
20
src/org.rs
|
@ -146,6 +146,26 @@ impl<'a> Org<'a> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn org<W: Write>(&self, wrtier: W) -> Result<(), Error> {
|
||||||
|
self.org_with_handler(wrtier, DefaultOrgHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn org_with_handler<W, H, E>(&self, mut writer: W, mut handler: H) -> Result<(), E>
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
E: From<Error>,
|
||||||
|
H: OrgHandler<E>,
|
||||||
|
{
|
||||||
|
for event in self.iter() {
|
||||||
|
match event {
|
||||||
|
Event::Start(element) => handler.start(&mut writer, element)?,
|
||||||
|
Event::End(element) => handler.end(&mut writer, element)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_headline(text: &str) -> Option<usize> {
|
fn is_headline(text: &str) -> Option<usize> {
|
||||||
|
|
Loading…
Reference in a new issue