Start parsing lines
This commit is contained in:
parent
f6c249393b
commit
2a1560cfb9
3 changed files with 117 additions and 0 deletions
|
|
@ -3,6 +3,7 @@ use std::path::PathBuf;
|
|||
use structopt::StructOpt;
|
||||
|
||||
mod commands;
|
||||
mod parse;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
pub struct Opt {
|
||||
|
|
@ -13,4 +14,7 @@ pub struct Opt {
|
|||
fn main() {
|
||||
let opt = Opt::from_args();
|
||||
println!("{:#?}", opt);
|
||||
|
||||
let commands = parse::parse(&opt.file);
|
||||
println!("{:#?}", commands);
|
||||
}
|
||||
|
|
|
|||
16
src/parse.rs
Normal file
16
src/parse.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::commands::Command;
|
||||
|
||||
use self::line::parse_lines;
|
||||
|
||||
mod line;
|
||||
|
||||
pub fn parse(file: &Path) -> anyhow::Result<Vec<Command>> {
|
||||
let content = fs::read_to_string(file)?;
|
||||
let lines = parse_lines(&content)?;
|
||||
|
||||
println!("{:#?}", lines);
|
||||
todo!()
|
||||
}
|
||||
97
src/parse/line.rs
Normal file
97
src/parse/line.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
use std::result;
|
||||
|
||||
use chrono::NaiveDate;
|
||||
|
||||
use crate::commands::{BirthdaySpec, Done, Spec};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Line {
|
||||
Empty,
|
||||
Indented(String),
|
||||
|
||||
Task(String),
|
||||
Note(String),
|
||||
Birthday(String),
|
||||
Date(Spec),
|
||||
BDate(BirthdaySpec),
|
||||
From(NaiveDate),
|
||||
Until(NaiveDate),
|
||||
Except(NaiveDate),
|
||||
Done(Done),
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("line {line}: unknown command {name:?}")]
|
||||
UnknownCommand { line: usize, name: String },
|
||||
#[error("line {line}: unknown format")]
|
||||
UnknownFormat { line: usize },
|
||||
}
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub fn parse_lines(content: &str) -> Result<Vec<Line>> {
|
||||
content
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(line, content)| parse_line(line, content))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_line(line: usize, content: &str) -> Result<Line> {
|
||||
println!("Parsing line {:?}", content);
|
||||
|
||||
if content.is_empty() {
|
||||
Ok(Line::Empty)
|
||||
} else if content.starts_with('\t') || content.starts_with(' ') {
|
||||
Ok(Line::Indented(content.to_string()))
|
||||
} else if let Some((name, rest)) = parse_command(content) {
|
||||
match name {
|
||||
"TASK" => Ok(Line::Task(rest.to_string())),
|
||||
"NOTE" => Ok(Line::Note(rest.to_string())),
|
||||
"BIRTHDAY" => Ok(Line::Birthday(rest.to_string())),
|
||||
"DATE" => parse_date(rest),
|
||||
"BDATE" => parse_bdate(rest),
|
||||
"FROM" => parse_datum(rest).map(Line::From),
|
||||
"UNTIL" => parse_datum(rest).map(Line::Until),
|
||||
"EXCEPT" => parse_datum(rest).map(Line::Except),
|
||||
"DONE" => parse_done(rest),
|
||||
_ => Err(Error::UnknownCommand {
|
||||
line,
|
||||
name: name.to_string(),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
Err(Error::UnknownFormat { line })
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_command(line: &str) -> Option<(&str, &str)> {
|
||||
if let Some(space) = line.find(' ') {
|
||||
let name = &line[..space];
|
||||
let content = &line[space + 1..];
|
||||
Some((name, content))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_date(s: &str) -> Result<Line> {
|
||||
println!(" parsing date from {:?}", s);
|
||||
Ok(Line::Empty) // TODO
|
||||
}
|
||||
|
||||
fn parse_bdate(s: &str) -> Result<Line> {
|
||||
println!(" parsing bdate from {:?}", s);
|
||||
Ok(Line::Empty) // TODO
|
||||
}
|
||||
|
||||
fn parse_datum(s: &str) -> Result<NaiveDate> {
|
||||
println!(" parsing datum from {:?}", s);
|
||||
Ok(NaiveDate::from_ymd(2015, 3, 14)) // TODO
|
||||
}
|
||||
|
||||
fn parse_done(s: &str) -> Result<Line> {
|
||||
println!(" parsing done from {:?}", s);
|
||||
Ok(Line::Empty) // TODO
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue