feat: enable state filtering
This commit is contained in:
parent
960a5210c6
commit
79c3174f4f
|
@ -36,10 +36,12 @@ Dots can be repeated to move to parent tasks
|
||||||
- `:[IND][COL]` - add / remove property column COL to IND or end
|
- `:[IND][COL]` - add / remove property column COL to IND or end
|
||||||
- `>[TEXT]` - Complete active task and move to parent, with optional state description
|
- `>[TEXT]` - Complete active task and move to parent, with optional state description
|
||||||
- `<[TEXT]` - Close active task and move to parent, with optional state description
|
- `<[TEXT]` - Close active task and move to parent, with optional state description
|
||||||
- `-TEXT` - add text note (comment / description)
|
|
||||||
- `#TAG` - filter by tag
|
- `#TAG` - filter by tag
|
||||||
|
- `?TAG` - filter by state (type or description)
|
||||||
|
- `-TEXT` - add text note (comment / description)
|
||||||
|
|
||||||
State descriptions can be used for example for Kanban columns.
|
State descriptions can be used for example for Kanban columns.
|
||||||
|
An active tag or state filter will also create new tasks with those corresponding attributes.
|
||||||
|
|
||||||
### Available Columns
|
### Available Columns
|
||||||
|
|
||||||
|
|
42
src/main.rs
42
src/main.rs
|
@ -139,23 +139,24 @@ async fn main() {
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
loop {
|
loop {
|
||||||
while let Ok(notification) = notifications.try_recv() {
|
|
||||||
if let RelayPoolNotification::Event {
|
|
||||||
subscription_id,
|
|
||||||
event,
|
|
||||||
..
|
|
||||||
} = notification
|
|
||||||
{
|
|
||||||
print_event(&event);
|
|
||||||
tasks.add(*event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.print_current_tasks();
|
tasks.print_current_tasks();
|
||||||
|
|
||||||
print!(" {}) ", tasks.taskpath(tasks.get_position()));
|
print!(" {}) ", tasks.taskpath(tasks.get_position()));
|
||||||
stdout().flush().unwrap();
|
stdout().flush().unwrap();
|
||||||
match stdin().lines().next() {
|
match stdin().lines().next() {
|
||||||
Some(Ok(input)) => {
|
Some(Ok(input)) => {
|
||||||
|
while let Ok(notification) = notifications.try_recv() {
|
||||||
|
if let RelayPoolNotification::Event {
|
||||||
|
subscription_id,
|
||||||
|
event,
|
||||||
|
..
|
||||||
|
} = notification
|
||||||
|
{
|
||||||
|
print_event(&event);
|
||||||
|
tasks.add(*event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut iter = input.chars();
|
let mut iter = input.chars();
|
||||||
let op = iter.next();
|
let op = iter.next();
|
||||||
match op {
|
match op {
|
||||||
|
@ -188,6 +189,25 @@ async fn main() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Some('?') => {
|
||||||
|
let arg = &input[1..];
|
||||||
|
tasks.move_to(tasks.get_position());
|
||||||
|
tasks.set_filter(
|
||||||
|
tasks
|
||||||
|
.current_tasks()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|t| {
|
||||||
|
if arg.is_empty() {
|
||||||
|
t.pure_state() == State::Open
|
||||||
|
} else {
|
||||||
|
t.state().is_some_and(|s| s.get_label() == arg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|t| t.event.id)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Some('-') => tasks.add_note(&input[1..]),
|
Some('-') => tasks.add_note(&input[1..]),
|
||||||
|
|
||||||
Some('>') | Some('<') => {
|
Some('>') | Some('<') => {
|
||||||
|
|
31
src/task.rs
31
src/task.rs
|
@ -42,14 +42,7 @@ impl Task {
|
||||||
|
|
||||||
fn states(&self) -> impl Iterator<Item = TaskState> + '_ {
|
fn states(&self) -> impl Iterator<Item = TaskState> + '_ {
|
||||||
self.props.iter().filter_map(|event| {
|
self.props.iter().filter_map(|event| {
|
||||||
match event.kind.as_u32() {
|
event.kind.try_into().ok().map(|s| TaskState {
|
||||||
1630 => Some(State::Open),
|
|
||||||
1631 => Some(State::Done),
|
|
||||||
1632 => Some(State::Closed),
|
|
||||||
1633 => Some(State::Active),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
.map(|s| TaskState {
|
|
||||||
name: if event.content.is_empty() {
|
name: if event.content.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -61,7 +54,7 @@ impl Task {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state(&self) -> Option<TaskState> {
|
pub(crate) fn state(&self) -> Option<TaskState> {
|
||||||
self.states().max_by_key(|t| t.time)
|
self.states().max_by_key(|t| t.time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,11 +123,16 @@ impl Task {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TaskState {
|
pub(crate) struct TaskState {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
state: State,
|
state: State,
|
||||||
time: Timestamp,
|
time: Timestamp,
|
||||||
}
|
}
|
||||||
|
impl TaskState {
|
||||||
|
pub(crate) fn get_label(&self) -> String {
|
||||||
|
self.name.clone().unwrap_or_else(|| self.state.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
impl fmt::Display for TaskState {
|
impl fmt::Display for TaskState {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
@ -155,6 +153,19 @@ pub(crate) enum State {
|
||||||
Active,
|
Active,
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
impl TryFrom<Kind> for State {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: Kind) -> Result<Self, Self::Error> {
|
||||||
|
match value.as_u32() {
|
||||||
|
1630 => Ok(State::Open),
|
||||||
|
1631 => Ok(State::Done),
|
||||||
|
1632 => Ok(State::Closed),
|
||||||
|
1633 => Ok(State::Active),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl State {
|
impl State {
|
||||||
pub(crate) fn kind(&self) -> Kind {
|
pub(crate) fn kind(&self) -> Kind {
|
||||||
match self {
|
match self {
|
||||||
|
|
Loading…
Reference in New Issue