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