feat: implement priority parsing from task string
This commit is contained in:
parent
dd78a2f460
commit
f33d890d7f
40
README.md
40
README.md
|
@ -82,6 +82,46 @@ as you work.
|
|||
|
||||
The currently active task is automatically time-tracked.
|
||||
To stop time-tracking completely, simply move to the root of all tasks.
|
||||
Time-tracking by default recursively summarizes
|
||||
|
||||
### Priorities
|
||||
|
||||
Task priorities can be set as any natural number,
|
||||
with higher numbers denoting higher priorities.
|
||||
The syntax here allows for very convenient incremental usage:
|
||||
By default, using priorities between 1 and 9 is recommended,
|
||||
with an exemplary interpretation like this:
|
||||
|
||||
* 1 Ideas / "Someday"
|
||||
* 2 Later
|
||||
* 3 Soon
|
||||
* 4 Relevant
|
||||
* 5 Important
|
||||
* 9 DO NOW
|
||||
|
||||
Internally, when giving a single digit, a 0 is appended,
|
||||
so that the default priorities increment in steps of 10.
|
||||
So in case you need more than 10 priorities,
|
||||
instead of stacking them on top,
|
||||
you can granularly add them in between.
|
||||
For example, `12` is in between `1` and `2`
|
||||
which are equivalent to `10` and `20`,
|
||||
not above `9` but above `09`!
|
||||
|
||||
By default, only tasks with priority `35` and upward are shown
|
||||
so you can focus on what matters,
|
||||
but you can temporarily override that using `**PRIO`.
|
||||
|
||||
### Quick Access
|
||||
|
||||
Paper-based lists are often popular because you can quickly put down a bunch of items.
|
||||
Mostr offers three useful workflows depending on the use-case:
|
||||
If you want to TBC...
|
||||
|
||||
- temporary task with subtasks (especially handy for progression)
|
||||
- Filter by recently created
|
||||
- Pin to bookmarks
|
||||
- high priority
|
||||
|
||||
## Reference
|
||||
|
||||
|
|
53
src/kinds.rs
53
src/kinds.rs
|
@ -1,10 +1,11 @@
|
|||
use crate::task::{State, MARKER_PARENT};
|
||||
use crate::tasks::HIGH_PRIO;
|
||||
use itertools::Itertools;
|
||||
use log::info;
|
||||
use nostr_sdk::TagStandard::Hashtag;
|
||||
use nostr_sdk::{Alphabet, EventBuilder, EventId, Kind, Tag, TagStandard};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::task::{State, MARKER_PARENT};
|
||||
use nostr_sdk::{Alphabet, EventBuilder, EventId, Kind, Tag, TagKind, TagStandard};
|
||||
use std::borrow::Cow;
|
||||
use std::iter::once;
|
||||
|
||||
pub const TASK_KIND: Kind = Kind::GitIssue;
|
||||
pub const PROCEDURE_KIND_ID: u16 = 1639;
|
||||
|
@ -25,6 +26,8 @@ pub const PROP_KINDS: [Kind; 6] = [
|
|||
PROCEDURE_KIND,
|
||||
];
|
||||
|
||||
pub const PRIO: &str = "priority";
|
||||
|
||||
// TODO: use formatting - bold / heading / italics - and generate from code
|
||||
/// Helper for available properties.
|
||||
pub const PROPERTY_COLUMNS: &str =
|
||||
|
@ -95,16 +98,31 @@ pub(crate) fn extract_hashtags(input: &str) -> impl Iterator<Item=Tag> + '_ {
|
|||
/// as well as various embedded tags.
|
||||
///
|
||||
/// Expects sanitized input.
|
||||
pub(crate) fn extract_tags(input: &str) -> (&str, Vec<Tag>) {
|
||||
match input.split_once(" # ") {
|
||||
None => (input, extract_hashtags(input).collect_vec()),
|
||||
Some((name, tags)) => {
|
||||
let tags = extract_hashtags(name)
|
||||
.chain(tags.split_ascii_whitespace().map(to_hashtag))
|
||||
.collect();
|
||||
(name, tags)
|
||||
pub(crate) fn extract_tags(input: &str) -> (String, Vec<Tag>) {
|
||||
let words = input.split_ascii_whitespace();
|
||||
let mut prio = None;
|
||||
let result = words.filter(|s| {
|
||||
if s.starts_with('*') {
|
||||
if s.len() == 1 {
|
||||
prio = Some(HIGH_PRIO);
|
||||
return false
|
||||
}
|
||||
return match s[1..].parse::<u16>() {
|
||||
Ok(num) => {
|
||||
prio = Some(num * (if s.len() > 2 { 1 } else { 10 }));
|
||||
false
|
||||
},
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}).collect_vec();
|
||||
let mut split = result.split(|e| { e == &"#" });
|
||||
let main = split.next().unwrap().join(" ");
|
||||
let tags = extract_hashtags(&main)
|
||||
.chain(split.flatten().map(|s| to_hashtag(&s)))
|
||||
.chain(prio.map(|p| to_prio_tag(&p.to_string()))).collect();
|
||||
(main, tags)
|
||||
}
|
||||
|
||||
fn to_hashtag(tag: &str) -> Tag {
|
||||
|
@ -137,9 +155,14 @@ pub(crate) fn is_hashtag(tag: &Tag) -> bool {
|
|||
.is_some_and(|letter| letter.character == Alphabet::T)
|
||||
}
|
||||
|
||||
pub(crate) fn to_prio_tag(value: &str) -> Tag {
|
||||
Tag::custom(TagKind::Custom(Cow::from(PRIO)), [if value.len() < 2 { format!("{value}0") } else { value.to_string() }])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_tags() {
|
||||
assert_eq!(extract_tags("Hello from #mars with #greetings # yeah done-it"),
|
||||
("Hello from #mars with #greetings", ["mars", "greetings", "yeah", "done-it"].into_iter().map(to_hashtag).collect()))
|
||||
assert_eq!(extract_tags("Hello from #mars with #greetings *4 # yeah done-it"),
|
||||
("Hello from #mars with #greetings".to_string(),
|
||||
["mars", "greetings", "yeah", "done-it"].into_iter().map(to_hashtag)
|
||||
.chain(once(Tag::custom(TagKind::Custom(Cow::from(PRIO)), [40.to_string()]))).collect()))
|
||||
}
|
|
@ -19,6 +19,10 @@ use regex::bytes::Regex;
|
|||
use tokio::sync::mpsc::Sender;
|
||||
use TagStandard::Hashtag;
|
||||
|
||||
const DEFAULT_PRIO: u16 = 25;
|
||||
pub const HIGH_PRIO: u16 = 85;
|
||||
|
||||
/// Amount of seconds to treat as "now"
|
||||
const MAX_OFFSET: u64 = 9;
|
||||
fn now() -> Timestamp {
|
||||
Timestamp::now() + MAX_OFFSET
|
||||
|
@ -856,7 +860,7 @@ impl TasksRelay {
|
|||
pub(crate) fn make_task_with(&mut self, input: &str, tags: impl IntoIterator<Item=Tag>, set_state: bool) -> EventId {
|
||||
let (input, input_tags) = extract_tags(input.trim());
|
||||
let id = self.submit(
|
||||
build_task(input, input_tags, None)
|
||||
build_task(&input, input_tags, None)
|
||||
.add_tags(self.tags.iter().cloned())
|
||||
.add_tags(tags)
|
||||
);
|
||||
|
@ -1060,7 +1064,7 @@ impl TasksRelay {
|
|||
}
|
||||
let (input, tags) = extract_tags(note.trim());
|
||||
self.submit(
|
||||
build_task(input, tags, Some(("activity", Kind::TextNote)))
|
||||
build_task(&input, tags, Some(("activity", Kind::TextNote)))
|
||||
.add_tags(self.parent_tag())
|
||||
.add_tags(self.tags.iter().cloned())
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue