mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Merge pull request #309 from djmitche/issue286
use TW's semantics for `start`
This commit is contained in:
commit
ae80cbef2a
3 changed files with 28 additions and 100 deletions
1
.changelogs/2021-10-25-issue23-integration.md
Normal file
1
.changelogs/2021-10-25-issue23-integration.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
- The details of how task start/stop is represented have changed. Any existing tasks will all be treated as inactive (stopped).
|
|
@ -30,7 +30,7 @@ The following keys, and key formats, are defined:
|
||||||
* `status` - one of `P` for a pending task (the default), `C` for completed or `D` for deleted
|
* `status` - one of `P` for a pending task (the default), `C` for completed or `D` for deleted
|
||||||
* `description` - the one-line summary of the task
|
* `description` - the one-line summary of the task
|
||||||
* `modified` - the time of the last modification of this task
|
* `modified` - the time of the last modification of this task
|
||||||
* `start.<timestamp>` - either an empty string (representing work on the task to the task that has not been stopped) or a timestamp (representing the time that work stopped)
|
* `start` - the most recent time at which this task was started (a task with no `start` key is not active)
|
||||||
* `tag.<tag>` - indicates this task has tag `<tag>` (value is an empty string)
|
* `tag.<tag>` - indicates this task has tag `<tag>` (value is an empty string)
|
||||||
* `wait` - indicates the time before which this task should be hidden, as it is not actionable
|
* `wait` - indicates the time before which this task should be hidden, as it is not actionable
|
||||||
|
|
||||||
|
|
|
@ -100,9 +100,7 @@ impl Task {
|
||||||
/// Determine whether this task is active -- that is, that it has been started
|
/// Determine whether this task is active -- that is, that it has been started
|
||||||
/// and not stopped.
|
/// and not stopped.
|
||||||
pub fn is_active(&self) -> bool {
|
pub fn is_active(&self) -> bool {
|
||||||
self.taskmap
|
self.taskmap.contains_key("start")
|
||||||
.iter()
|
|
||||||
.any(|(k, v)| k.starts_with("start.") && v.is_empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether a given synthetic tag is present on this task. All other
|
/// Determine whether a given synthetic tag is present on this task. All other
|
||||||
|
@ -192,31 +190,18 @@ impl<'r> TaskMut<'r> {
|
||||||
self.set_timestamp("modified", Some(modified))
|
self.set_timestamp("modified", Some(modified))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the task by creating "start.<timestamp": "", if the task is not already
|
/// Start the task by creating "start": "<timestamp>", if the task is not already
|
||||||
/// active.
|
/// active.
|
||||||
pub fn start(&mut self) -> anyhow::Result<()> {
|
pub fn start(&mut self) -> anyhow::Result<()> {
|
||||||
if self.is_active() {
|
if self.is_active() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let k = format!("start.{}", Utc::now().timestamp());
|
self.set_timestamp("start", Some(Utc::now()))
|
||||||
self.set_string(k, Some(String::from("")))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop the task by adding the current timestamp to all un-resolved "start.<timestamp>" keys.
|
/// Stop the task by removing the `start` key
|
||||||
pub fn stop(&mut self) -> anyhow::Result<()> {
|
pub fn stop(&mut self) -> anyhow::Result<()> {
|
||||||
let keys = self
|
self.set_timestamp("start", None)
|
||||||
.taskmap
|
|
||||||
.iter()
|
|
||||||
.filter(|(k, v)| k.starts_with("start.") && v.is_empty())
|
|
||||||
.map(|(k, _)| k)
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let now = Utc::now();
|
|
||||||
for key in keys {
|
|
||||||
println!("{}", key);
|
|
||||||
self.set_timestamp(&key, Some(now))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark this task as complete
|
/// Mark this task as complete
|
||||||
|
@ -340,10 +325,10 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_active() {
|
fn test_is_active_active() {
|
||||||
let task = Task::new(
|
let task = Task::new(
|
||||||
Uuid::new_v4(),
|
Uuid::new_v4(),
|
||||||
vec![(String::from("start.1234"), String::from(""))]
|
vec![(String::from("start"), String::from("1234"))]
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
@ -352,14 +337,8 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_active_stopped() {
|
fn test_is_active_inactive() {
|
||||||
let task = Task::new(
|
let task = Task::new(Uuid::new_v4(), Default::default());
|
||||||
Uuid::new_v4(),
|
|
||||||
vec![(String::from("start.1234"), String::from("1235"))]
|
|
||||||
.drain(..)
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(!task.is_active());
|
assert!(!task.is_active());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +384,7 @@ mod test {
|
||||||
Uuid::new_v4(),
|
Uuid::new_v4(),
|
||||||
vec![
|
vec![
|
||||||
(String::from("tag.abc"), String::from("")),
|
(String::from("tag.abc"), String::from("")),
|
||||||
(String::from("start.1234"), String::from("")),
|
(String::from("start"), String::from("1234")),
|
||||||
]
|
]
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -463,35 +442,21 @@ mod test {
|
||||||
assert_eq!(tags, vec![utag("ok"), stag(SyntheticTag::Pending)]);
|
assert_eq!(tags, vec![utag("ok"), stag(SyntheticTag::Pending)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_taskmap(task: &TaskMut, f: fn(&(&String, &String)) -> bool) -> usize {
|
|
||||||
task.taskmap.iter().filter(f).count()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_start() {
|
fn test_start() {
|
||||||
with_mut_task(|mut task| {
|
with_mut_task(|mut task| {
|
||||||
task.start().unwrap();
|
task.start().unwrap();
|
||||||
assert_eq!(
|
assert!(task.taskmap.contains_key("start"));
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
task.reload().unwrap();
|
task.reload().unwrap();
|
||||||
assert_eq!(
|
assert!(task.taskmap.contains_key("start"));
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
// second start doesn't change anything..
|
// second start doesn't change anything..
|
||||||
task.start().unwrap();
|
task.start().unwrap();
|
||||||
assert_eq!(
|
assert!(task.taskmap.contains_key("start"));
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
task.reload().unwrap();
|
task.reload().unwrap();
|
||||||
assert_eq!(
|
assert!(task.taskmap.contains_key("start"));
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,23 +465,17 @@ mod test {
|
||||||
with_mut_task(|mut task| {
|
with_mut_task(|mut task| {
|
||||||
task.start().unwrap();
|
task.start().unwrap();
|
||||||
task.stop().unwrap();
|
task.stop().unwrap();
|
||||||
assert_eq!(
|
assert!(!task.taskmap.contains_key("start"));
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && !v.is_empty()),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
task.reload().unwrap();
|
task.reload().unwrap();
|
||||||
assert_eq!(
|
assert!(!task.taskmap.contains_key("start"));
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
0
|
// redundant call does nothing..
|
||||||
);
|
task.stop().unwrap();
|
||||||
assert_eq!(
|
assert!(!task.taskmap.contains_key("start"));
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && !v.is_empty()),
|
|
||||||
1
|
task.reload().unwrap();
|
||||||
);
|
assert!(!task.taskmap.contains_key("start"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,38 +493,6 @@ mod test {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stop_multiple() {
|
|
||||||
with_mut_task(|mut task| {
|
|
||||||
// simulate a task that has (through the synchronization process) been started twice
|
|
||||||
task.task
|
|
||||||
.taskmap
|
|
||||||
.insert(String::from("start.1234"), String::from(""));
|
|
||||||
task.task
|
|
||||||
.taskmap
|
|
||||||
.insert(String::from("start.5678"), String::from(""));
|
|
||||||
|
|
||||||
task.stop().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && !v.is_empty()),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
task.reload().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && v.is_empty()),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
count_taskmap(&task, |(k, v)| k.starts_with("start.") && !v.is_empty()),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_tags() {
|
fn test_add_tags() {
|
||||||
with_mut_task(|mut task| {
|
with_mut_task(|mut task| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue