132 lines
2.6 KiB
Go
132 lines
2.6 KiB
Go
package pttodo
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
)
|
|
|
|
type Root struct {
|
|
Todo []Todo
|
|
Scheduled []Todo
|
|
Done []Todo
|
|
}
|
|
|
|
func NewRootFromFiles(p ...string) (Root, error) {
|
|
var result Root
|
|
for _, p := range p {
|
|
subroot, err := NewRootFromFile(p)
|
|
if err != nil {
|
|
return Root{}, err
|
|
}
|
|
result.MergeIn(subroot)
|
|
}
|
|
result.AutoMove()
|
|
return result, nil
|
|
}
|
|
|
|
func NewRootFromFile(p string) (Root, error) {
|
|
if b, err := os.ReadFile(p); err == nil && len(bytes.TrimSpace(b)) == 0 {
|
|
return Root{}, nil
|
|
}
|
|
|
|
f, err := os.Open(p)
|
|
if os.IsNotExist(err) {
|
|
return Root{}, nil
|
|
}
|
|
if err != nil {
|
|
return Root{}, err
|
|
}
|
|
defer f.Close()
|
|
|
|
var result Root
|
|
if err := yaml.NewDecoder(f).Decode(&result); err != nil {
|
|
todos, err2 := NewTodosFromFile(p)
|
|
if err2 != nil {
|
|
return Root{}, err
|
|
}
|
|
result.Todo = todos
|
|
}
|
|
|
|
result.AutoMove()
|
|
return result, nil
|
|
}
|
|
|
|
func (root Root) Equals(other Root) bool {
|
|
for i, slice := range [][2][]Todo{
|
|
[2][]Todo{root.Todo, other.Todo},
|
|
[2][]Todo{root.Scheduled, other.Scheduled},
|
|
[2][]Todo{root.Done, other.Done},
|
|
} {
|
|
_ = i
|
|
if !equalTodoSlices(slice[0], slice[1]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (root *Root) AutoMove() {
|
|
root.MoveScheduledToTodo()
|
|
root.MoveTodoToScheduled()
|
|
}
|
|
|
|
func (root *Root) MoveTodoToScheduled() {
|
|
for i := len(root.Todo) - 1; i >= 0; i-- {
|
|
if !root.Todo[i].Schedule.isFixedFuture() {
|
|
continue
|
|
}
|
|
root.Scheduled = append(root.Scheduled, root.Todo[i])
|
|
for j := i; j < len(root.Todo)-1; j++ {
|
|
root.Todo[j] = root.Todo[j+1]
|
|
}
|
|
root.Todo = root.Todo[:len(root.Todo)-1]
|
|
}
|
|
}
|
|
|
|
func (root *Root) MoveScheduledToTodo() {
|
|
for i := len(root.Scheduled) - 1; i >= 0; i-- {
|
|
if root.Scheduled[i].Triggered() {
|
|
root.Todo = append(root.Todo, root.Scheduled[i])
|
|
root.Scheduled[i] = root.Scheduled[len(root.Scheduled)-1]
|
|
root.Scheduled = root.Scheduled[:len(root.Scheduled)-1]
|
|
if i < len(root.Scheduled)-1 {
|
|
i += 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (root *Root) MergeIn(root2 Root) {
|
|
for _, listPair := range [][2]*[]Todo{
|
|
[2]*[]Todo{&root.Todo, &root2.Todo},
|
|
[2]*[]Todo{&root.Scheduled, &root2.Scheduled},
|
|
[2]*[]Todo{&root.Done, &root2.Done},
|
|
} {
|
|
for _, candidate := range *listPair[1] {
|
|
found := false
|
|
for i := range *listPair[0] {
|
|
found = found || ((*listPair[0])[i].Todo == candidate.Todo)
|
|
}
|
|
if !found {
|
|
*listPair[0] = append(*listPair[0], candidate)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (root Root) MarshalYAML() (interface{}, error) {
|
|
for i := range root.Todo {
|
|
root.Todo[i].writeTS = false
|
|
}
|
|
for i := range root.Scheduled {
|
|
root.Scheduled[i].writeTS = true
|
|
}
|
|
for i := range root.Done {
|
|
root.Done[i].writeTS = true
|
|
}
|
|
type Alt Root
|
|
return (Alt)(root), nil
|
|
}
|