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)
}