use super::TodoStatus;
pub fn parse_status(s: &str) -> Option<TodoStatus> {
match s.to_lowercase().trim() {
"pending" | "todo" => Some(TodoStatus::Pending),
"in_progress" | "doing" | "in-progress" | "in progress" => Some(TodoStatus::InProgress),
"completed" | "done" | "complete" => Some(TodoStatus::Completed),
_ => None,
}
}
pub fn strip_markdown(text: &str) -> String {
text.replace("**", "")
.replace("__", "")
.replace('*', "")
.replace('_', " ")
.replace('`', "")
.replace("~~", "")
}
pub fn parse_plan_steps(plan_content: &str) -> Vec<String> {
let mut steps = Vec::new();
let mut in_steps_section = false;
for line in plan_content.lines() {
let trimmed = line.trim();
if trimmed.starts_with("## Implementation Steps")
|| trimmed.starts_with("## Steps")
|| trimmed.starts_with("## implementation steps")
{
in_steps_section = true;
continue;
}
if in_steps_section && trimmed.starts_with("## ") {
break;
}
if in_steps_section
&& let Some(text) = extract_numbered_step(trimmed)
&& !text.is_empty()
{
steps.push(text);
}
}
if steps.is_empty() {
for line in plan_content.lines() {
let trimmed = line.trim();
if trimmed.starts_with('#') {
continue;
}
if let Some(text) = extract_numbered_step(trimmed)
&& !text.is_empty()
{
steps.push(text);
}
}
}
steps
}
fn extract_numbered_step(line: &str) -> Option<String> {
let line = line.trim();
if line.is_empty() {
return None;
}
let mut chars = line.chars();
let first = chars.next()?;
if !first.is_ascii_digit() {
return None;
}
let rest: String = chars.collect();
let rest = rest.trim_start_matches(|c: char| c.is_ascii_digit());
let rest = if let Some(s) = rest.strip_prefix(". ") {
s
} else if let Some(s) = rest.strip_prefix(") ") {
s
} else if let Some(s) = rest.strip_prefix(" - ") {
s
} else {
return None;
};
let text = rest.trim();
if text.is_empty() {
None
} else {
let text = text.replace("**", "").replace("__", "");
Some(text)
}
}
#[cfg(test)]
#[path = "parsing_tests.rs"]
mod tests;