aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/by-name/ts/tskm/src/task
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/ts/tskm/src/task')
-rw-r--r--pkgs/by-name/ts/tskm/src/task/mod.rs176
1 files changed, 98 insertions, 78 deletions
diff --git a/pkgs/by-name/ts/tskm/src/task/mod.rs b/pkgs/by-name/ts/tskm/src/task/mod.rs
index c3a6d614..03a12faa 100644
--- a/pkgs/by-name/ts/tskm/src/task/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/task/mod.rs
@@ -9,109 +9,136 @@ use std::{
use anyhow::{bail, Context, Result};
use log::{debug, info, trace};
+use taskchampion::Tag;
-use crate::interface::project::ProjectName;
+use crate::{interface::project::ProjectName, state::State};
/// The `taskwarrior` id of a task.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
-pub struct Id {
- id: u64,
+pub struct Task {
+ uuid: taskchampion::Uuid,
}
-impl Id {
- /// # Errors
- /// When `task` execution fails
- pub fn get_current() -> Result<Option<Self>> {
- // We have ensured that only one task may be active
- let self_str = run_task(&["+ACTIVE", "_ids"])?;
- if self_str.is_empty() {
- Ok(None)
+impl From<&taskchampion::Task> for Task {
+ fn from(value: &taskchampion::Task) -> Self {
+ Self {
+ uuid: value.get_uuid(),
+ }
+ }
+}
+impl From<&taskchampion::TaskData> for Task {
+ fn from(value: &taskchampion::TaskData) -> Self {
+ Self {
+ uuid: value.get_uuid(),
+ }
+ }
+}
+
+impl Task {
+ pub fn from_working_set(id: usize, state: &mut State) -> Result<Option<Self>> {
+ Ok(state
+ .replica()
+ .working_set()?
+ .by_index(id)
+ .map(|uuid| Self { uuid }))
+ }
+
+ pub fn get_current(state: &mut State) -> Result<Option<Self>> {
+ let tasks = state
+ .replica()
+ .pending_tasks()?
+ .into_iter()
+ .filter(taskchampion::Task::is_active)
+ .collect::<Vec<_>>();
+
+ assert!(
+ tasks.len() <= 1,
+ "We have ensured that only one task may be active, via a hook"
+ );
+ if let Some(active) = tasks.first() {
+ Ok(Some(Self::from(active)))
} else {
- Self::from_str(&self_str).map(Some)
+ Ok(None)
}
}
- /// # Errors
- /// When `task` execution fails
- pub fn to_uuid(&self) -> Result<String> {
- let uuid = run_task(&[self.to_string().as_str(), "uuids"])?;
+ #[must_use]
+ pub fn uuid(&self) -> &taskchampion::Uuid {
+ &self.uuid
+ }
- Ok(uuid)
+ fn as_task(&self, state: &mut State) -> Result<taskchampion::Task> {
+ Ok(state
+ .replica()
+ .get_task(self.uuid)?
+ .expect("We have the task from this replica, it should still be in it"))
}
- /// # Panics
- /// When internal assertions fail.
- /// # Errors
- /// When `task` execution fails
- pub fn annotate(&self, message: &str) -> Result<()> {
- run_task(&["annotate", self.to_string().as_str(), "--", message])?;
+ /// Adds a tag to the task, to show the user that it has additional neorg data.
+ pub fn mark_neorg_data(&self, state: &mut State) -> Result<()> {
+ let mut ops = vec![];
+ self.as_task(state)?
+ .add_tag(&Tag::from_str("neorg_data").expect("Is valid"), &mut ops)?;
+ state.replica().commit_operations(ops)?;
Ok(())
}
- /// # Panics
- /// When internal assertions fail.
- /// # Errors
- /// When `task` execution fails
- pub fn start(&self) -> Result<()> {
+ /// Try to start this task.
+ /// It will stop previously active tasks.
+ pub fn start(&self, state: &mut State) -> Result<()> {
info!("Activating {self}");
- let output = run_task(&["start", self.to_string().as_str()])?;
- assert!(output.is_empty());
+ if let Some(active) = Self::get_current(state)? {
+ active.stop(state)?;
+ }
+
+ let mut ops = vec![];
+ self.as_task(state)?.start(&mut ops)?;
+ state.replica().commit_operations(ops)?;
Ok(())
}
- /// # Panics
- /// When internal assertions fail.
- /// # Errors
- /// When `task` execution fails
- pub fn stop(&self) -> Result<()> {
+
+ /// Stops this task.
+ pub fn stop(&self, state: &mut State) -> Result<()> {
info!("Stopping {self}");
- let output = run_task(&["stop", self.to_string().as_str()])?;
- assert!(output.is_empty());
+ let mut ops = vec![];
+ self.as_task(state)?.stop(&mut ops)?;
+ state.replica().commit_operations(ops)?;
Ok(())
}
- /// # Panics
- /// When internal assertions fail.
- /// # Errors
- /// When `task` execution fails
- pub fn description(&self) -> Result<String> {
- let output = run_task(&["rc.context=none", "_zshids", self.to_string().as_str()])?;
- let (id, desc) = output
- .split_once(':')
- .expect("The output should always contain one colon");
- assert_eq!(id.parse::<Id>().expect("This should be a valid id"), *self);
- Ok(desc.to_owned())
+ pub fn description(&self, state: &mut State) -> Result<String> {
+ Ok(self.as_task(state)?.get_description().to_owned())
}
- /// # Panics
- /// When internal assertions fail.
- /// # Errors
- /// When `task` execution fails
- pub fn project(&self) -> Result<Project> {
- let output = run_task(&[
- "rc.context=none",
- "_get",
- format!("{self}.project").as_str(),
- ])?;
+ pub fn project(&self, state: &mut State) -> Result<Project> {
+ let output = {
+ let task = self.as_task(state)?;
+ let task_data = task.into_task_data();
+ task_data
+ .get("project")
+ .expect("Every task should have a project")
+ .to_owned()
+ };
let project = Project::from_project_string(output.as_str())
.expect("This comes from tw, it should be valid");
Ok(project)
}
}
-impl Display for Id {
+impl Display for Task {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.id.fmt(f)
+ self.uuid.fmt(f)
}
}
-impl FromStr for Id {
+impl FromStr for Task {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
- let id = u64::from_str(s)?;
- Ok(Self { id })
+ let uuid = taskchampion::Uuid::from_str(s)?;
+ Ok(Self { uuid })
}
}
@@ -259,21 +286,14 @@ impl Project {
/// # Errors
/// When `task` execution fails.
- pub fn get_tasks(&self) -> Result<Vec<Id>> {
- let output = run_task(&[
- "rc.context=none",
- format!("project:{}", self.to_project_display()).as_str(),
- "_ids",
- ])?;
-
- if output.is_empty() {
- Ok(vec![])
- } else {
- output
- .lines()
- .map(Id::from_str)
- .collect::<Result<Vec<Id>>>()
- }
+ pub fn get_tasks(&self, state: &mut State) -> Result<Vec<Task>> {
+ Ok(state
+ .replica()
+ .pending_task_data()?
+ .into_iter()
+ .filter(|t| t.get("project").expect("Is set") == self.to_project_display())
+ .map(|t| Task::from(&t))
+ .collect())
}
/// # Errors