Compare commits
2 Commits
20e327d9dd
...
5ef3057d98
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ef3057d98 | |||
| 57ac41ff72 |
@@ -35,8 +35,12 @@ func (t Task) PriorityAsRemind() int {
|
|||||||
if p < 'A' || p > 'Z' {
|
if p < 'A' || p > 'Z' {
|
||||||
return 5000
|
return 5000
|
||||||
}
|
}
|
||||||
// A=9999, Z=0, linear scale
|
step := 9999 / 25 // 399
|
||||||
return 9999 - int(p-'A')*400
|
val := 9999 - int(p-'A')*step
|
||||||
|
if p == 'Z' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Task) MarshalJSON() ([]byte, error) {
|
func (t Task) MarshalJSON() ([]byte, error) {
|
||||||
@@ -60,11 +64,9 @@ func (t Task) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dateRe = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
|
dateRe = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
|
||||||
priorityHead = regexp.MustCompile(`^\([A-Z]\)\s+`)
|
spaceRe = regexp.MustCompile(`\s+`)
|
||||||
completedHead = regexp.MustCompile(`^x\s+`)
|
dateLayout = "2006-01-02"
|
||||||
spaceRe = regexp.MustCompile(`\s+`)
|
|
||||||
dateLayout = "2006-01-02"
|
|
||||||
// Protocols to exclude as metadata keys
|
// Protocols to exclude as metadata keys
|
||||||
protocols = map[string]struct{}{
|
protocols = map[string]struct{}{
|
||||||
"http": {},
|
"http": {},
|
||||||
@@ -115,48 +117,56 @@ func ParseLine(line string) (Task, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
working := strings.TrimSpace(line)
|
working := strings.TrimSpace(line)
|
||||||
|
toks := splitTokens(working)
|
||||||
|
i := 0
|
||||||
|
|
||||||
// 1) Completed?
|
// 1) Completed?
|
||||||
if completedHead.MatchString(working) {
|
if i < len(toks) && toks[i] == "x" {
|
||||||
t.Completed = true
|
t.Completed = true
|
||||||
working = completedHead.ReplaceAllString(working, "")
|
i++
|
||||||
toks := splitTokens(working)
|
// 2) Completion date
|
||||||
consumed := 0
|
if i < len(toks) && dateRe.MatchString(toks[i]) {
|
||||||
if len(toks) > 0 && dateRe.MatchString(toks[0]) {
|
if dt, err := time.Parse(dateLayout, toks[i]); err == nil {
|
||||||
if dt, err := time.Parse(dateLayout, toks[0]); err == nil {
|
|
||||||
t.CompletionDate = &dt
|
t.CompletionDate = &dt
|
||||||
consumed = 1
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if consumed < len(toks) && dateRe.MatchString(toks[consumed]) {
|
// 3) Creation date
|
||||||
if dt, err := time.Parse(dateLayout, toks[consumed]); err == nil {
|
if i < len(toks) && dateRe.MatchString(toks[i]) {
|
||||||
|
if dt, err := time.Parse(dateLayout, toks[i]); err == nil {
|
||||||
t.CreationDate = &dt
|
t.CreationDate = &dt
|
||||||
consumed++
|
i++
|
||||||
}
|
|
||||||
}
|
|
||||||
if consumed > 0 {
|
|
||||||
working = strings.TrimSpace(strings.Join(toks[consumed:], " "))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if priorityHead.MatchString(working) {
|
|
||||||
if len(working) >= 3 {
|
|
||||||
r := rune(working[1])
|
|
||||||
t.Priority = &r
|
|
||||||
}
|
|
||||||
working = priorityHead.ReplaceAllString(working, "")
|
|
||||||
}
|
|
||||||
toks := splitTokens(working)
|
|
||||||
if len(toks) > 0 && dateRe.MatchString(toks[0]) {
|
|
||||||
if dt, err := time.Parse(dateLayout, toks[0]); err == nil {
|
|
||||||
t.CreationDate = &dt
|
|
||||||
working = strings.TrimSpace(strings.Join(toks[1:], " "))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens := splitTokens(working)
|
// 4) Priority (can appear after x, dates)
|
||||||
descParts := make([]string, 0, len(tokens))
|
if i < len(toks) && len(toks[i]) == 3 && toks[i][0] == '(' && toks[i][2] == ')' && toks[i][1] >= 'A' && toks[i][1] <= 'Z' {
|
||||||
for _, tok := range tokens {
|
r := rune(toks[i][1])
|
||||||
|
t.Priority = &r
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) If not completed, check for priority at start
|
||||||
|
if !t.Completed {
|
||||||
|
if i < len(toks) && len(toks[i]) == 3 && toks[i][0] == '(' && toks[i][2] == ')' && toks[i][1] >= 'A' && toks[i][1] <= 'Z' {
|
||||||
|
r := rune(toks[i][1])
|
||||||
|
t.Priority = &r
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
// Creation date for incomplete tasks
|
||||||
|
if i < len(toks) && dateRe.MatchString(toks[i]) {
|
||||||
|
if dt, err := time.Parse(dateLayout, toks[i]); err == nil {
|
||||||
|
t.CreationDate = &dt
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6) Parse remaining tokens
|
||||||
|
descParts := make([]string, 0)
|
||||||
|
for ; i < len(toks); i++ {
|
||||||
|
tok := toks[i]
|
||||||
if strings.HasPrefix(tok, "+") && len(tok) > 1 {
|
if strings.HasPrefix(tok, "+") && len(tok) > 1 {
|
||||||
t.Projects = append(t.Projects, tok[1:])
|
t.Projects = append(t.Projects, tok[1:])
|
||||||
continue
|
continue
|
||||||
@@ -170,7 +180,6 @@ func ParseLine(line string) (Task, error) {
|
|||||||
k, v := parts[0], parts[1]
|
k, v := parts[0], parts[1]
|
||||||
if k != "" && v != "" && !isProtocolKey(k) {
|
if k != "" && v != "" && !isProtocolKey(k) {
|
||||||
t.Metadata[k] = v
|
t.Metadata[k] = v
|
||||||
// If the field is due:YYYY-MM-DD, also parse it as DueDate
|
|
||||||
if k == "due" && dateRe.MatchString(v) {
|
if k == "due" && dateRe.MatchString(v) {
|
||||||
if dt, err := time.Parse(dateLayout, v); err == nil {
|
if dt, err := time.Parse(dateLayout, v); err == nil {
|
||||||
t.DueDate = &dt
|
t.DueDate = &dt
|
||||||
@@ -179,7 +188,6 @@ func ParseLine(line string) (Task, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else part of description
|
|
||||||
descParts = append(descParts, tok)
|
descParts = append(descParts, tok)
|
||||||
}
|
}
|
||||||
t.Description = strings.TrimSpace(strings.Join(descParts, " "))
|
t.Description = strings.TrimSpace(strings.Join(descParts, " "))
|
||||||
|
|||||||
Reference in New Issue
Block a user