pub mod error; pub(crate) mod fs; mod git; mod journal; mod settings; mod table; mod wikarden; pub use error::WikError; pub use journal::JournalName; pub use settings::Settings; pub use table::SectionData; pub use wikarden::{PathType, Source, Wikarden}; use crate::fs::{Open, WikFile, WikPath}; pub(crate) fn quotes_encode(raw: &str) -> String { let mut ret = String::with_capacity(raw.len() + 4); ret.push('"'); for ch in raw.chars() { match ch { '"' => { ret.push('\\'); ret.push('"'); } '\\' => { ret.push('\\'); ret.push('\\'); } ch => ret.push(ch), } } ret.push('"'); ret } pub(crate) fn quotes_decode(raw: &str) -> Option<(String, &str)> { let raw = match raw.chars().next() { Some('"') => &raw[1..], _ => return None, }; let mut ret = String::with_capacity(raw.len() / 2); let mut escaping = false; for (idx, ch) in raw.chars().enumerate() { match ch { '\\' if !escaping => escaping = true, '\\' if escaping => { ret.push('\\'); escaping = false; } '"' if !escaping => return Some((ret, &raw[idx + 1..])), '"' if escaping => { ret.push('"'); escaping = false; } ch if !escaping => ret.push(ch), ch if escaping => { ret.push('\\'); ret.push(ch); escaping = false; } _ => unreachable!(), } } None } #[cfg(test)] mod test { #[test] pub fn test_quotes_encode() { macro_rules! enc { ($encode:literal -> $expected:literal) => { let actual = crate::quotes_encode($encode); if actual != $expected { panic!( "quotes_encode failed!\nexpected: '{}'\n actual: '{}'", $expected, actual ); } }; } enc!("encode" -> r#""encode""#); enc!("encode\\" -> r#""encode\\""#); enc!("encode \"" -> r#""encode \"""#); } #[test] pub fn test_quotes_decode() { macro_rules! dec { ($encode:literal -> $expected:expr) => { let actual = crate::quotes_decode($encode).unwrap(); if actual != $expected { panic!( "quotes_encode failed!\nexpected: '{:?}'\n actual: '{:?}'", $expected, actual ); } }; } dec!(r#""decode""# -> (String::from("decode"), "")); dec!(r#""escape \\""# -> (String::from("escape \\"), "")); dec!(r#""quote \"""# -> (String::from("quote \""), "")); dec!(r#""more after" some"# -> (String::from("more after"), " some")); } }