Compare commits

..

3 Commits

Author SHA1 Message Date
2d4f611de1 begun development for single file generation
All checks were successful
Test the running changes / Test (push) Successful in 40s
2025-11-26 19:31:21 +02:00
1c7504e3e0 added special character escaping to md
All checks were successful
Test the running changes / Test (push) Successful in 42s
2025-11-23 22:31:24 +02:00
7d602fffba added cargo-tarpaulin to flake, added some tests to cracked_md
All checks were successful
Test the running changes / Test (push) Successful in 40s
2025-11-23 20:52:05 +02:00
8 changed files with 104 additions and 18 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ site/
target/
result
tarpaulin-report.html

View File

@@ -16,15 +16,10 @@ pub enum Block {
language: Option<String>,
content: String,
},
List(Vec<ListItem>),
List(Vec<Block>),
Quote(Vec<Block>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ListItem {
pub blocks: Vec<Block>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Inline {
Text(String),

View File

@@ -133,6 +133,20 @@ mod test {
);
}
#[test]
fn code_block_content_after_end() {
let md = "```\necho hello\n```abc";
let doc_res = parse(md);
assert!(doc_res.is_err());
}
#[test]
fn code_block_no_terminating() {
let md = "```\nabc\n";
let doc_res = parse(md);
assert!(doc_res.is_err());
}
#[test]
fn rust_code_block() {
let md = "```rust\nfn main() {\n\tprintln!(\"Hello world!\");\n}\n```";

View File

@@ -48,6 +48,11 @@ pub fn parse_blocks(input: &str) -> Result<Vec<Block>, MdParseError> {
}
*/
// unordered list TODO
if line_chars.parse_str("- ") {
todo!()
}
// code
if line_chars.parse_str("```") {
let lang_line: String = line_chars.collect();

View File

@@ -36,12 +36,18 @@ pub fn parse_inlines(input: &str) -> Result<Vec<Inline>, MdParseError> {
_ => {
let mut text = String::new();
text.push(c);
let mut escaped = false;
while let Some(&nc) = chars.peek() {
if matches!(nc, '*' | '_' | '`' | '[') {
if matches!(nc, '*' | '_' | '`' | '[') && !escaped {
break;
}
let c = chars.next().ok_or(MdParseError::new("a character", ""))?;
text.push(c);
let next_c = chars.next().ok_or(MdParseError::new("a character", ""))?;
if next_c == '\\' && !escaped {
escaped = true;
} else {
escaped = false;
text.push(next_c);
}
}
inlines.push(Inline::Text(text));
}
@@ -69,7 +75,14 @@ fn collect_until<I: Iterator<Item = char>>(
mod test {
use crate::ast::Inline;
use super::parse_inlines;
use super::{collect_until, parse_inlines};
#[test]
fn collect_until_without_end() {
let mut s = "abcdef".chars().peekable();
let res = collect_until(&mut s, '.');
assert!(res.is_err());
}
#[test]
fn bold_text() {
@@ -128,4 +141,43 @@ mod test {
]
);
}
#[test]
fn single_hyperlink() {
let md = "a link to [my site](https://example.com)";
let inl = parse_inlines(md).unwrap();
assert_eq!(
inl,
vec![
Inline::Text("a link to ".to_string()),
Inline::Link {
text: vec![Inline::Text("my site".to_string())],
href: "https://example.com".to_string()
}
]
);
}
#[test]
fn hyperlink_without_link() {
let md = "[abc]";
let inl = parse_inlines(md);
assert!(inl.is_err());
}
#[test]
fn escape_brackets() {
let md = r"some \[text\]";
let inl = parse_inlines(md).unwrap();
assert_eq!(inl, vec![Inline::Text("some [text]".to_string())]);
}
#[test]
fn escape_escape() {
let md = r"backslash \\";
let inl = parse_inlines(md).unwrap();
assert_eq!(inl, vec![Inline::Text(r"backslash \".to_string())]);
}
}

View File

@@ -25,6 +25,7 @@
cargo-nextest
cargo-expand
cargo-watch
cargo-tarpaulin
];
};
}

View File

@@ -10,14 +10,17 @@ use std::net::Ipv4Addr;
use std::path::{Path, PathBuf};
pub enum Command {
Generate { force: bool },
Generate { force: bool, single: bool },
Serve { addr: Ipv4Addr, port: u16 },
Init,
}
impl Default for Command {
fn default() -> Self {
Self::Generate { force: true }
Self::Generate {
force: true,
single: false,
}
}
}
@@ -67,10 +70,18 @@ impl TryFrom<Args> for Command {
comm = Command::Init;
}
// `gravel` command
else if let Some(a) = value.next() {
Err(Error::CommandLineArgsParse(format!(
"Unexpected argument: `{a}`"
)))?;
for a in value {
match a.as_str() {
"-s" => {
comm = Command::Generate {
force: true,
single: true,
}
}
_ => Err(Error::CommandLineArgsParse(format!(
"Unknown argument: `{a}`"
)))?,
}
}
Ok(comm)

View File

@@ -15,9 +15,16 @@ fn run() -> Result<(), Error> {
let conf = ProgramConfig::new("gravel.toml", std::env::args())?;
match conf.command {
Command::Init => todo!("project init not implemented"),
Command::Init => todo!("project init"),
Command::Serve { addr, port } => serve(addr, port, conf.outdir)?,
Command::Generate { force } => generate(&conf.indir, &conf.outdir, force)?,
Command::Generate {
force,
single: false,
} => generate(&conf.indir, &conf.outdir, force)?,
Command::Generate {
force: _f,
single: true,
} => todo!("single file generation"),
}
Ok(())
}