Compare commits
10 Commits
92e8e14c08
...
b2a51e65b0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2a51e65b0 | ||
|
|
f75dcb3f7a | ||
|
|
d4466598b4 | ||
|
|
3ba3b78afc | ||
|
|
f2e3e6f505 | ||
|
|
1ce120a647 | ||
|
|
bfdeebb7a2 | ||
|
|
39345e5e2a | ||
|
|
bfcec9d1c5 | ||
|
|
3e1f58c7b9 |
@@ -24,7 +24,7 @@ func TestConfigTargets(t *testing.T) {
|
||||
},
|
||||
"one file": {
|
||||
setup: func(t *testing.T, d string) {
|
||||
touch(t, "x")
|
||||
touch(t, path.Join(d, "x"))
|
||||
},
|
||||
given: "x",
|
||||
want: []string{"x"},
|
||||
|
||||
104
cmd/dump.go
104
cmd/dump.go
@@ -1,13 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gogs.inhome.blapointe.com/bel/pttodo/pttodo"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -18,103 +13,32 @@ func dump(config config) error {
|
||||
}
|
||||
|
||||
func _dump(writer io.Writer, filepaths []string, tags []string, search, rootDisplay string) error {
|
||||
var root pttodo.Root
|
||||
|
||||
for _, p := range filepaths {
|
||||
results, err := filepath.Glob(p + ".*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, result := range results {
|
||||
if result == p {
|
||||
continue
|
||||
}
|
||||
filepaths = append(filepaths, result)
|
||||
}
|
||||
root, err := pttodo.NewRootFromFiles(filepaths...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, filepath := range filepaths {
|
||||
reader, err := filePathReader(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var root2, root2post pttodo.Root
|
||||
if err := yaml.Unmarshal(b, &root2); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := yaml.Unmarshal(b, &root2post); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
root2.MoveScheduledToTodo()
|
||||
|
||||
if !root2.Equals(root2post) {
|
||||
log.Printf("refreshing %s", filepath)
|
||||
b3, err := yaml.Marshal(root2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(filepath, b3, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
//log.Printf("not refreshing %s", filepath)
|
||||
}
|
||||
|
||||
root.MergeIn(root2)
|
||||
for _, x := range []*[]pttodo.Todo{
|
||||
&root.Todo,
|
||||
&root.Scheduled,
|
||||
&root.Done,
|
||||
} {
|
||||
y := pttodo.Todos(*x)
|
||||
y = y.LikeTags(tags)
|
||||
y = y.LikeSearch(search)
|
||||
*x = y
|
||||
}
|
||||
|
||||
root.MoveScheduledToTodo()
|
||||
|
||||
var v interface{} = root
|
||||
switch rootDisplay {
|
||||
case DUMP_ALL:
|
||||
case DUMP_TODO:
|
||||
v = root.Todo
|
||||
case DUMP_SCHEDULED:
|
||||
v = root.Scheduled
|
||||
case DUMP_DONE:
|
||||
v = root.Done
|
||||
}
|
||||
if todos, ok := v.([]pttodo.Todo); ok {
|
||||
if len(tags) > 0 {
|
||||
result := make([]pttodo.Todo, 0, len(todos))
|
||||
for _, todo := range todos {
|
||||
skip := false
|
||||
for _, tag := range tags {
|
||||
positiveTag := strings.TrimLeft(tag, "-")
|
||||
hasTag := strings.Contains(todo.Tags, positiveTag)
|
||||
wantToHaveTag := !strings.HasPrefix(tag, "-")
|
||||
skip = skip || !(hasTag == wantToHaveTag)
|
||||
}
|
||||
if !skip {
|
||||
result = append(result, todo)
|
||||
}
|
||||
}
|
||||
todos = result
|
||||
}
|
||||
if len(search) > 0 {
|
||||
result := make([]pttodo.Todo, 0, len(todos))
|
||||
for _, todo := range todos {
|
||||
if strings.Contains(strings.ToLower(fmt.Sprint(todo)), strings.ToLower(search)) {
|
||||
result = append(result, todo)
|
||||
}
|
||||
}
|
||||
todos = result
|
||||
}
|
||||
v = todos
|
||||
default:
|
||||
}
|
||||
|
||||
b2, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(writer, "%s\n", b2)
|
||||
return nil
|
||||
return yaml.NewEncoder(writer).Encode(v)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pttodo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
@@ -12,7 +13,24 @@ type Root struct {
|
||||
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
|
||||
@@ -24,7 +42,11 @@ func NewRootFromFile(p string) (Root, error) {
|
||||
|
||||
var result Root
|
||||
if err := yaml.NewDecoder(f).Decode(&result); err != nil {
|
||||
return Root{}, err
|
||||
todos, err2 := NewTodosFromFile(p)
|
||||
if err2 != nil {
|
||||
return Root{}, err
|
||||
}
|
||||
result.Todo = todos
|
||||
}
|
||||
|
||||
result.AutoMove()
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -180,3 +182,78 @@ done:
|
||||
t.Fatalf("want\n\t%q, got\n\t%q", want, string(got))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootFromFile(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
given string
|
||||
want Root
|
||||
}{
|
||||
"empty": {},
|
||||
"happy": {
|
||||
given: `{"todo":["a", "b"],"scheduled":["c"], "done":[{"todo": "d"}]}`,
|
||||
want: Root{
|
||||
Todo: []Todo{
|
||||
Todo{Todo: "a"},
|
||||
Todo{Todo: "b"},
|
||||
},
|
||||
Scheduled: []Todo{
|
||||
Todo{Todo: "c"},
|
||||
},
|
||||
Done: []Todo{
|
||||
Todo{Todo: "d"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"todos": {
|
||||
given: `["a", {"todo": "b"}]`,
|
||||
want: Root{
|
||||
Todo: []Todo{
|
||||
{Todo: "a"},
|
||||
{Todo: "b"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
d := t.TempDir()
|
||||
p := path.Join(d, "input.yaml")
|
||||
if err := os.WriteFile(p, []byte(c.given), os.ModePerm); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := NewRootFromFile(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fmt.Sprintf("%+v", got) != fmt.Sprintf("%+v", c.want) {
|
||||
t.Errorf("want\n\t%+v, got\n\t%+v", c.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootFromFiles(t *testing.T) {
|
||||
d := t.TempDir()
|
||||
ps := []string{
|
||||
path.Join(d, "a"),
|
||||
path.Join(d, "b"),
|
||||
}
|
||||
os.WriteFile(ps[0], []byte(`["a"]`), os.ModePerm)
|
||||
os.WriteFile(ps[1], []byte(`["b"]`), os.ModePerm)
|
||||
|
||||
got, err := NewRootFromFiles(ps...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := Root{
|
||||
Todo: []Todo{
|
||||
{Todo: "a"},
|
||||
{Todo: "b"},
|
||||
},
|
||||
}
|
||||
if fmt.Sprintf("%+v", got) != fmt.Sprintf("%+v", want) {
|
||||
t.Errorf("want\n\t%+v, got \n\t%+v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
36
pttodo/todos.go
Normal file
36
pttodo/todos.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package pttodo
|
||||
|
||||
import "strings"
|
||||
|
||||
type Todos []Todo
|
||||
|
||||
func (todos Todos) LikeSearch(search string) Todos {
|
||||
return todos.Like(func(todo Todo) bool {
|
||||
return strings.Contains(
|
||||
strings.ToLower(todo.Todo),
|
||||
strings.ToLower(search),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
func (todos Todos) LikeTags(tags []string) Todos {
|
||||
return todos.Like(func(todo Todo) bool {
|
||||
matches := true
|
||||
for _, tag := range tags {
|
||||
str := strings.TrimLeft(tag, "-")
|
||||
want := !strings.HasPrefix(tag, "-")
|
||||
matches = matches && strings.Contains(todo.Tags, str) == want
|
||||
}
|
||||
return matches
|
||||
})
|
||||
}
|
||||
|
||||
func (todos Todos) Like(like func(Todo) bool) Todos {
|
||||
result := make(Todos, 0)
|
||||
for i := range todos {
|
||||
if like(todos[i]) {
|
||||
result = append(result, todos[i])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
17
pttodo/todos_test.go
Normal file
17
pttodo/todos_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package pttodo
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTodosLikeTags(t *testing.T) {
|
||||
todos := Todos{
|
||||
{Todo: "a", Tags: "x"},
|
||||
{Todo: "b", Tags: "x,y"},
|
||||
}
|
||||
|
||||
result := todos.LikeTags([]string{"x", "-y"})
|
||||
if len(result) != 1 {
|
||||
t.Error(result)
|
||||
} else if result[0].Todo != "a" {
|
||||
t.Error(result[0].Todo)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user