Compare commits

..

2 Commits

Author SHA1 Message Date
5ef3057d98 refactor(parser): simplify ParseLine logic for completed, priority, and date parsing
- Refactor ParseLine to use token-based parsing for completed status,
  priority, and dates.
- Improve handling of priority and creation date for both completed and
  incomplete tasks.
2025-11-25 00:41:36 +01:00
57ac41ff72 fix(parser): correct priority calculation for 'Z' to return 0
Previously, the priority calculation did not handle 'Z' correctly,
resulting in a non-zero value. Now, 'Z' returns 0 as intended, and the
step size is calculated for a linear scale.
2025-11-25 00:40:16 +01:00

View File

@@ -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, " "))