orgize/README.md

152 lines
3.9 KiB
Markdown
Raw Normal View History

2019-02-06 12:50:18 +00:00
# Orgize
2019-06-27 17:13:05 +01:00
A Rust library for parsing orgmode files.
2019-02-06 12:50:18 +00:00
2019-06-27 17:13:05 +01:00
## Parse
2019-02-06 12:50:18 +00:00
2019-06-27 17:13:05 +01:00
To parse a orgmode string, simply invoking the `Org::parse` function:
2019-02-06 12:50:18 +00:00
```rust
2019-06-27 17:13:05 +01:00
use orgize::Org;
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
let org = Org::parse(r#"* Title 1
2019-02-06 12:50:18 +00:00
*Section 1*
** Title 2
_Section 2_
* Title 3
/Section 3/
* Title 4
2019-04-24 14:54:51 +01:00
=Section 4="#);
2019-02-06 12:50:18 +00:00
```
2019-06-27 17:13:05 +01:00
## Iter
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
`Org::iter` function will return a iteractor of `Event`s, which is
a simple wrapper of `Element`.
2019-04-24 14:54:51 +01:00
```rust
2019-06-27 17:13:05 +01:00
for event in org.iter() {
// handling the event
}
```
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
**Note**: whether an element is container or not, it will appears two times in a loop.
One as `Event::Start(element)`, one as `Event::End(element)`.
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
## Render html
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
You can call the `Org::html_default` function to generate html directly, which
uses the `DefaultHtmlHandler` internally:
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
```rust
let mut writer = Vec::new();
org.html_default(&mut writer).unwrap();
assert_eq!(
String::from_utf8(writer).unwrap(),
"<main><h1>Title 1</h1><section><p><b>Section 1</b></p></section>\
<h2>Title 2</h2><section><p><u>Section 2</u></p></section>\
<h1>Title 3</h1><section><p><i>Section 3</i></p></section>\
<h1>Title 4</h1><section><p><code>Section 4</code></p></section></main>"
);
2019-04-24 14:54:51 +01:00
```
2019-06-27 17:13:05 +01:00
## Render html with custom HtmlHandler
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
To customize html rending, simply implementing `HtmlHandler` trait and passing
it to the `Org::html` function.
2019-04-24 14:54:51 +01:00
2019-06-27 17:13:05 +01:00
The following code demonstrates how to add a id for every headline and return
own error type while rendering.
2019-02-06 12:50:18 +00:00
2019-02-07 07:54:16 +00:00
```rust
2019-04-24 14:54:51 +01:00
#[derive(Debug)]
2019-06-27 17:13:05 +01:00
enum MyError {
2019-04-24 14:54:51 +01:00
IO(IOError),
2019-06-27 17:13:05 +01:00
Heading,
2019-04-24 14:54:51 +01:00
Utf8(FromUtf8Error),
}
2019-02-07 07:54:16 +00:00
2019-04-24 14:54:51 +01:00
// From<std::io::Error> trait is required for custom error type
2019-06-27 17:13:05 +01:00
impl From<IOError> for MyError {
fn from(err: IOError) -> Self {
MyError::IO(err)
}
}
impl From<FromUtf8Error> for MyError {
fn from(err: FromUtf8Error) -> Self {
MyError::Utf8(err)
2019-04-24 14:54:51 +01:00
}
}
2019-06-27 17:13:05 +01:00
struct MyHtmlHandler;
impl HtmlHandler<MyError> for MyHtmlHandler {
fn start<W: Write>(&mut self, mut w: W, element: &Element<'_>) -> Result<(), MyError> {
let mut default_handler = DefaultHtmlHandler;
match element {
Element::Headline { headline, .. } => {
if headline.level > 6 {
return Err(MyError::Heading);
} else {
let slugify = slugify!(headline.title);
write!(
w,
"<h{0}><a id=\"{1}\" href=\"#{1}\">{2}</a></h{0}>",
headline.level,
slugify,
Escape(headline.title),
)?;
}
}
// fallthrough to default handler
_ => default_handler.start(w, element)?,
}
Ok(())
2019-04-24 14:54:51 +01:00
}
}
2019-06-27 17:13:05 +01:00
fn main() -> Result<(), MyError> {
2019-04-24 14:54:51 +01:00
let contents = r"* Title 1
2019-02-07 07:54:16 +00:00
*Section 1*
** Title 2
_Section 2_
* Title 3
/Section 3/
* Title 4
=Section 4=";
2019-02-07 07:54:16 +00:00
2019-06-27 17:13:05 +01:00
let mut writer = Vec::new();
Org::parse(&contents).html(&mut writer, MyHtmlHandler)?;
2019-04-24 14:54:51 +01:00
assert_eq!(
2019-06-27 17:13:05 +01:00
String::from_utf8(writer)?,
"<main><h1><a id=\"title-1\" href=\"#title-1\">Title 1</a></h1><section><p><b>Section 1</b></p></section>\
<h2><a id=\"title-2\" href=\"#title-2\">Title 2</a></h2><section><p><u>Section 2</u></p></section>\
<h1><a id=\"title-3\" href=\"#title-3\">Title 3</a></h1><section><p><i>Section 3</i></p></section>\
<h1><a id=\"title-4\" href=\"#title-4\">Title 4</a></h1><section><p><code>Section 4</code></p></section></main>"
2019-04-24 14:54:51 +01:00
);
Ok(())
}
2019-02-07 07:54:16 +00:00
```
2019-06-27 17:13:05 +01:00
**Note**: as I mentioned above, each element will appears two times while iterating.
And handler will silently ignores all end events from non-container elements.
So if you want to change how a non-container element renders, just redefine the start
function and leave the end function untouched.
## Serde
`Org` struct have already implemented serde's `Serialize` trait. It means you can
freely serialize it into any format that serde supports such as json:
```rust
println!("{}", to_string(&org).unwrap());
```
2019-02-06 12:50:18 +00:00
## License
MIT