hlfw.ca

todo2

Download patch

ref: b598415a8e4d0921edd95d5c93f18bec803ee74c
parent: 1ad684ce6fd54c822abe63014e31b18b19d4aa6a
author: Michael Misch <michaelmisch1985@gmail.com>
date: Mon Oct 28 06:07:59 PDT 2019

Add in some of the task logic

--- a/README.md
+++ b/README.md
@@ -74,16 +74,14 @@
 The following commands modify the state of a given entry's task:
 
  - `todo task toggle <entry> <index|string>`
- - `todo task do <entry> <index|string>`
- - `todo task undo <entry> <index|string>`
  - `todo task rm <entry> <index|string>`
 
 For example, to toggle the completion of MyType implementing ReaderAt:
 
-`todo task do 'BUG #92930' 'MyType should implement ReaderAt'`
+`todo task toggle 'BUG #92930' 'MyType should implement ReaderAt'`
 
-You'll notice the file name is elided, for brevity a partial string match is all that is required. `todo task do 'BUG #92930' MyType would suffice in our example.
-By index, it's similar: `todo task do 'BUG #92930' 1` would update the .todo file to read `[x] polygon.go: MyType should implement ReaderAt`.
+You'll notice the file name is elided, for brevity a partial string match is all that is required. `todo task toggle 'BUG #92930' MyType` would suffice in our example.
+By index, it's similar: `todo task toggle 'BUG #92930' 1` would update the .todo file to read `[x] polygon.go: MyType should implement ReaderAt`.
 
 ## Automatically generate .todo files
 
--- a/command.go
+++ b/command.go
@@ -21,7 +21,7 @@
 
 func newCommand(arg string) (*command, error) {
 	c := &command{}
-
+	
 	if arg == "task" {
 		c.args = flag.Args()[1:]
 		c.runner = task
@@ -55,13 +55,13 @@
 		if flag.NArg() < 2 {
 			return errors.New("No arguments supplied to rm")
 		}
-		c.args = flag.Args()[1:]
+		c.args = flag.Args()[:1]
 		c.runner = rm
 	case "add":
 		if flag.NArg() < 2 {
 			return errors.New("No arguments supplied to add")
 		}
-		c.args = flag.Args()[1:]
+		c.args = flag.Args()[:1]
 		c.runner = add
 	case "generate":
 		c.runner = generate
--- a/task.go
+++ b/task.go
@@ -1,21 +1,150 @@
 package main
 
-import "fmt"
+import (
+	"fmt"
+	"log"
+	"os"
+	"text/template"
+)
 
+const tmplt = `{{range .tasklist .}}
+{{if and .list .title}}
+{{.title}}
+{{range .list .}}{{if .done}}[*]{{else}}[ ]{{end}} {{.desc}}{{end}}
+
+{{end}}
+{{end}}
+`
+
+/* Example:
+My entry title
+[ ] an entry
+[*] a done entry
+
+My other entry
+[ ] an entry
+[*] a done entry
+*/
+
+type layout struct {
+	tasklist []entries
+}
+
+type entries struct {
+	title string
+	list  []entry
+}
+
+type entry struct {
+	desc string
+	done bool
+}
+
 func task(c *command) error {
-	// Open file
-	// Parse in
-	// Add/rm/etc
-	// Write out
-	switch c.args[1] {
+	l, err := parse("test")
+	if err != nil {
+		return err
+	}
+	switch c.args[0] {
 	case "add":
-
+		if len(c.args) < 3 || l.exists(c.args[1], c.args[2]) {
+			return fmt.Errorf("Entry exists")
+		}
+		defer l.write()
+		return l.add(c.args[1], c.args[2])
 	case "rm":
-	case "do":
-	case "undo":
+		if len(c.args) < 3 || !l.exists(c.args[1], c.args[2]) {
+			return fmt.Errorf("No entry found")
+		}
+		defer l.write()
+		return l.rm(c.args[1], c.args[2])
 	case "toggle":
+		if len(c.args) < 3 || !l.exists(c.args[1], c.args[2]) {
+			return fmt.Errorf("No such task/entry")
+		}
+		defer l.write()
+		return l.toggle(c.args[1], c.args[2])
 	default:
-		return fmt.Errorf("Command not supported: %v", c.args[1])
+		return fmt.Errorf("Command not supported: %v", c.args[0])
 	}
+}
+
+func (l *layout) write() {
+	wr, err := os.Create("tmp")
+	defer wr.Close()
+	if err != nil {
+		log.Fatal(err)
+	}
+	t := template.Must(template.New(".todo").Parse(tmplt))
+	t.Execute(wr, l)
+}
+
+func (l *layout) exists(title, item string) bool {
+	for _, e := range l.tasklist {
+		if e.title != title {
+			continue
+		}
+		for _, t := range e.list {
+			if t.desc == item {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func (l *layout) add(title, item string) error {
+	for _, e := range l.tasklist {
+		if e.title != title {
+			continue
+		}
+		e.list = append(e.list, entry{
+			desc: item,
+			done: false,
+		})
+		return nil
+	}
+	line := entry{
+		desc: item,
+		done: false,
+	}
+	l.tasklist = append(l.tasklist, entries{
+		title: title,
+		list:  []entry{line},
+	})
 	return nil
+}
+
+func (l *layout) rm(title, item string) error {
+	for _, e := range l.tasklist {
+		if e.title != title {
+			continue
+		}
+		for i, t := range e.list {
+			if t.desc != item {
+				continue
+			}
+			if i < len(e.list)-1 {
+				copy(e.list[i:], e.list[i+1:])
+			}
+			e.list = e.list[:len(e.list)-1]
+			return nil
+		}
+	}
+	return fmt.Errorf("No such task/entry")
+}
+func (l *layout) toggle(title, item string) error {
+	for _, e := range l.tasklist {
+		if e.title != title {
+			continue
+		}
+		for _, t := range e.list {
+			if t.desc != item {
+				continue
+			}
+			t.done = !t.done
+			return nil
+		}
+	}
+	return fmt.Errorf("No such task/entry")
 }
--- /dev/null
+++ b/test
@@ -1,0 +1,3 @@
+Here is a task
+[ ] and done
+[*] and not
--- a/todo.go
+++ b/todo.go
@@ -16,7 +16,7 @@
 		flag.Usage()
 		os.Exit(0)
 	}
-	cmd, err := newCommand(flag.Arg(1))
+	cmd, err := newCommand(flag.Arg(0))
 	if err != nil {
 		log.Fatal(err)
 	}