pttodo/pttodo/root.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
}