use serde::{Deserialize, Serialize};
use super::task::Task;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TrackState {
Active,
Shelved,
Archived,
}
#[derive(Debug, Clone)]
pub enum TrackNode {
Literal(Vec<String>),
Section {
kind: SectionKind,
header_lines: Vec<String>,
tasks: Vec<Task>,
trailing_lines: Vec<String>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
Backlog,
Parked,
Done,
}
impl std::fmt::Display for SectionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SectionKind::Backlog => write!(f, "Backlog"),
SectionKind::Parked => write!(f, "Parked"),
SectionKind::Done => write!(f, "Done"),
}
}
}
#[derive(Debug, Clone)]
pub struct Track {
pub title: String,
pub description: Option<String>,
pub nodes: Vec<TrackNode>,
pub source_lines: Vec<String>,
}
impl Track {
pub fn section_tasks(&self, kind: SectionKind) -> &[Task] {
for node in &self.nodes {
if let TrackNode::Section { kind: k, tasks, .. } = node
&& *k == kind
{
return tasks;
}
}
&[]
}
pub fn section_tasks_mut(&mut self, kind: SectionKind) -> Option<&mut Vec<Task>> {
for node in &mut self.nodes {
if let TrackNode::Section { kind: k, tasks, .. } = node
&& *k == kind
{
return Some(tasks);
}
}
None
}
pub fn backlog(&self) -> &[Task] {
self.section_tasks(SectionKind::Backlog)
}
pub fn parked(&self) -> &[Task] {
self.section_tasks(SectionKind::Parked)
}
pub fn done(&self) -> &[Task] {
self.section_tasks(SectionKind::Done)
}
pub fn ensure_section(&mut self, kind: SectionKind) {
if self.section_tasks_mut(kind).is_some() {
return;
}
let header = match kind {
SectionKind::Backlog => "## Backlog",
SectionKind::Parked => "## Parked",
SectionKind::Done => "## Done",
};
let new_node = TrackNode::Section {
kind,
header_lines: vec![header.to_string()],
tasks: Vec::new(),
trailing_lines: vec![String::new()],
};
let order = |k: SectionKind| -> u8 {
match k {
SectionKind::Backlog => 0,
SectionKind::Parked => 1,
SectionKind::Done => 2,
}
};
let target_order = order(kind);
let insert_pos = self
.nodes
.iter()
.position(|n| {
if let TrackNode::Section { kind: k, .. } = n {
order(*k) > target_order
} else {
false
}
})
.unwrap_or(self.nodes.len());
self.nodes.insert(insert_pos, new_node);
}
}