Strip planning line and drawers from section body
section_body() now filters out: - Leading planning line (SCHEDULED/DEADLINE/CLOSED) - Property drawers (:PROPERTIES: ... :END:) - Any other drawers (:LOGBOOK:, etc.) - Leading/trailing blank lines These are displayed separately in the UI.
This commit is contained in:
parent
ff48f9c7ee
commit
f5f2bffce4
|
|
@ -461,11 +461,11 @@ impl OrkState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get section body content (text between headline and first child).
|
/// 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<String> {
|
pub fn section_body(&self, doc_name: &str, id: &str) -> Option<String> {
|
||||||
self.get_doc(doc_name).and_then(|d| {
|
self.get_doc(doc_name).and_then(|d| {
|
||||||
self.find_section(&d.doc, id).map(|s| {
|
self.find_section(&d.doc, id).map(|s| {
|
||||||
// Body is section content minus children
|
// Body is section content minus children
|
||||||
// For now, extract from raw content using spans
|
|
||||||
let start = s.headline.span.end.offset;
|
let start = s.headline.span.end.offset;
|
||||||
let end = if let Some(first_child) = s.children.first() {
|
let end = if let Some(first_child) = s.children.first() {
|
||||||
first_child.headline.span.start.offset
|
first_child.headline.span.start.offset
|
||||||
|
|
@ -473,11 +473,59 @@ impl OrkState {
|
||||||
s.span.end.offset
|
s.span.end.offset
|
||||||
};
|
};
|
||||||
|
|
||||||
if start < end && end <= d.content.len() {
|
if start >= end || end > d.content.len() {
|
||||||
d.content[start..end].to_string()
|
return String::new();
|
||||||
} else {
|
|
||||||
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")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue