diff --git a/crates/ork-server/src/state.rs b/crates/ork-server/src/state.rs index 2e564ee..dc117da 100644 --- a/crates/ork-server/src/state.rs +++ b/crates/ork-server/src/state.rs @@ -461,11 +461,11 @@ impl OrkState { } /// Get section body content (text between headline and first child). + /// Strips planning line and properties drawer. pub fn section_body(&self, doc_name: &str, id: &str) -> Option { self.get_doc(doc_name).and_then(|d| { self.find_section(&d.doc, id).map(|s| { // Body is section content minus children - // For now, extract from raw content using spans let start = s.headline.span.end.offset; let end = if let Some(first_child) = s.children.first() { first_child.headline.span.start.offset @@ -473,11 +473,59 @@ impl OrkState { s.span.end.offset }; - if start < end && end <= d.content.len() { - d.content[start..end].to_string() - } else { - String::new() + if start >= end || end > d.content.len() { + return String::new(); } + + let raw_body = &d.content[start..end]; + + // Strip leading planning line (SCHEDULED/DEADLINE/CLOSED) + // and properties drawer (:PROPERTIES: ... :END:) + let lines: Vec<&str> = raw_body.lines().collect(); + let mut result_lines = Vec::new(); + let mut in_drawer = false; + let mut first_line = true; + + for line in lines { + let trimmed = line.trim(); + + // Skip planning line at the very start + if first_line && (trimmed.starts_with("SCHEDULED:") || + trimmed.starts_with("DEADLINE:") || + trimmed.starts_with("CLOSED:")) { + first_line = false; + continue; + } + first_line = false; + + // Handle drawer + if trimmed.starts_with(":") && trimmed.ends_with(":") && trimmed.len() > 2 { + let drawer_name = &trimmed[1..trimmed.len()-1]; + if drawer_name.chars().all(|c| c.is_ascii_uppercase() || c == '_') { + in_drawer = true; + continue; + } + } + + if in_drawer { + if trimmed == ":END:" { + in_drawer = false; + } + continue; + } + + result_lines.push(line); + } + + // Trim leading/trailing empty lines + while result_lines.first().map(|l| l.trim().is_empty()).unwrap_or(false) { + result_lines.remove(0); + } + while result_lines.last().map(|l| l.trim().is_empty()).unwrap_or(false) { + result_lines.pop(); + } + + result_lines.join("\n") }) }) }