summaryrefslogtreecommitdiff
path: root/src/org.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/org.rs')
-rw-r--r--src/org.rs139
1 files changed, 92 insertions, 47 deletions
diff --git a/src/org.rs b/src/org.rs
index 3ba918d..84df9c2 100644
--- a/src/org.rs
+++ b/src/org.rs
@@ -1,77 +1,122 @@
use regex::Regex;
-
-#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Debug)]
-pub enum Org<'a> {
- Unknown,
- Header(u16, &'a str),
-}
+use std::str;
#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Debug)]
-pub struct OrgNode<'a> {
- pub raw: &'a str,
- pub e: Org<'a>,
+pub enum Org {
+ Unknown(String),
+ Header(u16, String),
+ Properties(Vec<(String, String)>)
}
-type OrgDocument<'a> = Vec<OrgNode<'a>>;
+type OrgDocument = Vec<Org>;
-struct Parser<'a> {
- doc: OrgDocument<'a>
-}
-
-impl<'a> Parser<'a> {
- fn parse_line(&mut self, line: &'a str) {
+macro_rules! matchers {
+ (
+ $($id:ident <- $e:expr;)*
+ ) => {
lazy_static! {
- static ref header: Regex = Regex::new(r"(\*)+ (.*)").unwrap();
+ $(static ref $id: Regex = Regex::new($e).unwrap();)*
}
+ }
+}
+
+matchers! {
+ header <- r"^(\*)+ (.*)";
+ properties_start <- r"^\s*:PROPERTIES:\s*$";
+ property <- r"^\s*:([^:]*): (.*)$";
+ properties_end <- r"^\s*:END:\s*$";
+}
+
+struct Parser<I: Iterator<Item=String>> {
+ doc: OrgDocument,
+ iter: I,
+}
- if let Some(g) = header.captures(line) {
- self.doc.push(OrgNode {
- raw: line,
- e: Org::Header(
- g.get(1).unwrap().as_str().len() as u16,
- g.get(2).unwrap().as_str()
- )});
- } else {
- self.doc.push(OrgNode {
- raw: line,
- e: Org::Unknown
- });
+impl<I: Iterator<Item=String>> Parser<I> {
+ fn go(&mut self) {
+ while let Some(line) = self.iter.next() {
+ if let Some(g) = header.captures(&line) {
+ self.doc.push(
+ Org::Header(
+ g.get(1).unwrap().as_str().len() as u16,
+ g.get(2).unwrap().as_str().to_string()));
+ } else if properties_start.is_match(&line) {
+ &mut self.go_properties(line.clone());
+ } else {
+ self.doc.push(Org::Unknown(line.to_string()));
+ }
}
}
- pub fn parse(input: &'a str) -> OrgDocument<'a> {
- let mut parser = Parser{doc: vec!()};
- for line in input.split('\n') {
- parser.parse_line(line);
+ fn go_properties(&mut self, first_line: String) {
+ let mut fallback = vec!(first_line);
+ let mut properties = vec!();
+
+ while let Some(line) = self.iter.next() {
+ fallback.push(line.clone());
+
+ if let Some(g) = property.captures(&line) {
+ properties.push((
+ g.get(1).unwrap().as_str().to_string(),
+ g.get(2).unwrap().as_str().to_string()));
+ } else if properties_end.is_match(&line) {
+ break;
+ } else {
+ self.doc.push(Org::Unknown(fallback.join("\n")));
+ return;
+ }
}
- parser.doc
+ self.doc.push(Org::Properties(properties));
}
}
+pub fn parse(input: &str) -> OrgDocument {
+ let mut parser = Parser{
+ doc: vec!(),
+ iter: input.split('\n').map(|line| line.to_string())
+ };
+ parser.go();
+ parser.doc
+}
+
#[cfg(test)]
mod tests {
use super::*;
+ fn s<S: AsRef<str>>(m: S) -> String {
+ m.as_ref().to_string()
+ }
+
#[test]
fn parse_unknown() {
let doc = "hello\nhello";
- assert_eq!(Parser::parse(doc),
- vec!(OrgNode {
- raw: "hello",
- e: Org::Unknown
- }, OrgNode {
- raw: "hello",
- e: Org::Unknown
- }));
+ assert_eq!(parse(doc),
+ vec!(Org::Unknown("hello".to_string()),
+ Org::Unknown("hello".to_string())));
}
#[test]
fn parse_header() {
let doc = "* hello";
- assert_eq!(Parser::parse(doc),
- vec!(OrgNode {
- raw: doc,
- e: Org::Header(1, "hello")
- }));
+ assert_eq!(parse(doc),
+ vec!(Org::Header(1, "hello".to_string())));
+ assert_eq!(parse(" * hello"),
+ vec!(Org::Unknown(" * hello".to_string())));
+ }
+
+ #[test]
+ fn parse_properties() {
+ let doc = ":PROPERTIES:
+ :VERSION: 1.0
+ :ANIMAL: dog
+ :END:";
+ assert_eq!(parse(doc),
+ vec!(Org::Properties(vec!(
+ (s("VERSION"), s("1.0")),
+ (s("ANIMAL"), s("dog"))))));
+ let doc = ":PROPERTIES:\ninvalid\n:END:";
+ assert_eq!(parse(doc),
+ vec!(Org::Unknown(s(":PROPERTIES:\ninvalid")),
+ Org::Unknown(s(":END:"))));
}
}