aboutsummaryrefslogtreecommitdiffstats
path: root/todolist
diff options
context:
space:
mode:
authorQuey-Liang Kao <s101062801@m101.nthu.edu.tw>2017-09-21 12:16:10 -0500
committerGitHub <noreply@github.com>2017-09-21 12:16:10 -0500
commit902d0f825abc3a18278aadc2a8c3cd45dd8d308d (patch)
treec08037986e9981ebd8e56fe8dd851fa99fcd4c32 /todolist
parent06211d84da190ab9a5e174db9f52672b69f9b3e4 (diff)
parenta716a04c831e4fb23cdd558756d8f393e4ef8d73 (diff)
Merge pull request #89 from NonerKao/note
Add new feature: notes for todos
Diffstat (limited to 'todolist')
-rw-r--r--todolist/app.go32
-rw-r--r--todolist/filter.go4
-rw-r--r--todolist/formatter.go8
-rw-r--r--todolist/parser.go71
-rw-r--r--todolist/parser_test.go90
-rw-r--r--todolist/todo_item.go1
-rw-r--r--todolist/todos.json2
7 files changed, 203 insertions, 5 deletions
diff --git a/todolist/app.go b/todolist/app.go
index f63c41b..92ee64d 100644
--- a/todolist/app.go
+++ b/todolist/app.go
@@ -137,6 +137,35 @@ func (a *App) ExpandTodo(input string) {
fmt.Println("Todo expanded.")
}
+func (a *App) HandleNotes(input string) {
+ a.Load()
+ id := a.getId(input)
+ if id == -1 {
+ return
+ }
+ todo := a.TodoList.FindById(id)
+ if todo == nil {
+ fmt.Println("No such id.")
+ return
+ }
+ parser := &Parser{}
+
+ if parser.ParseAddNote(todo, input) {
+ fmt.Println("Note added.")
+ } else if parser.ParseDeleteNote(todo, input) {
+ fmt.Println("Note deleted.")
+ } else if parser.ParseEditNote(todo, input) {
+ fmt.Println("Note edited.")
+ } else if parser.ParseShowNote(todo, input) {
+ groups := map[string][]*Todo{}
+ groups[""] = append(groups[""], todo)
+ formatter := NewFormatter(&GroupedTodos{Groups: groups})
+ formatter.Print(true)
+ return
+ }
+ a.Save()
+}
+
func (a *App) ArchiveCompleted() {
a.Load()
for _, todo := range a.TodoList.Todos() {
@@ -154,7 +183,8 @@ func (a *App) ListTodos(input string) {
grouped := a.getGroups(input, filtered)
formatter := NewFormatter(grouped)
- formatter.Print()
+ re, _ := regexp.Compile(`^ln`)
+ formatter.Print(re.MatchString(input))
}
func (a *App) PrioritizeTodo(input string) {
diff --git a/todolist/filter.go b/todolist/filter.go
index dd61d11..88b28a7 100644
--- a/todolist/filter.go
+++ b/todolist/filter.go
@@ -38,7 +38,7 @@ func (f *TodoFilter) filterArchived(input string) []*Todo {
return f.Todos
}
- r, _ := regexp.Compile(`l archived$`)
+ r, _ := regexp.Compile(`ln? archived$`)
if r.MatchString(input) {
return f.getArchived()
} else {
@@ -47,7 +47,7 @@ func (f *TodoFilter) filterArchived(input string) []*Todo {
}
func (f *TodoFilter) filterPrioritized(input string) []*Todo {
- r, _ := regexp.Compile(`l p`)
+ r, _ := regexp.Compile(`ln? p`)
if r.MatchString(input) {
return f.getPrioritized()
} else {
diff --git a/todolist/formatter.go b/todolist/formatter.go
index c0f3313..e7863db 100644
--- a/todolist/formatter.go
+++ b/todolist/formatter.go
@@ -25,7 +25,7 @@ func NewFormatter(todos *GroupedTodos) *Formatter {
return formatter
}
-func (f *Formatter) Print() {
+func (f *Formatter) Print(printNotes bool) {
cyan := color.New(color.FgCyan).SprintFunc()
var keys []string
@@ -38,6 +38,12 @@ func (f *Formatter) Print() {
fmt.Fprintf(f.Writer, "\n %s\n", cyan(key))
for _, todo := range f.GroupedTodos.Groups[key] {
f.printTodo(todo)
+ if printNotes {
+ for nid, note := range todo.Notes {
+ fmt.Fprintf(f.Writer, " %s\t%s\t\n",
+ cyan(strconv.Itoa(nid)), note)
+ }
+ }
}
}
f.Writer.Flush()
diff --git a/todolist/parser.go b/todolist/parser.go
index d62c77d..3f700af 100644
--- a/todolist/parser.go
+++ b/todolist/parser.go
@@ -83,6 +83,77 @@ func (p *Parser) Contexts(input string) []string {
return p.matchWords(input, r)
}
+func (p *Parser) ParseAddNote(todo *Todo, input string) bool {
+ r, _ := regexp.Compile(`^an\s+\d+\s+(.*)`)
+ matches := r.FindStringSubmatch(input)
+ if len(matches) != 2 {
+ return false
+ }
+
+ todo.Notes = append(todo.Notes, matches[1])
+ return true
+}
+
+func (p *Parser) ParseDeleteNote(todo *Todo, input string) bool {
+ r, _ := regexp.Compile(`^dn\s+\d+\s+(\d+)`)
+ matches := r.FindStringSubmatch(input)
+ if len(matches) != 2 {
+ return false
+ }
+
+ rmid, err := p.getNoteID(matches[1])
+ if err != nil {
+ return false
+ }
+
+ for id, _ := range todo.Notes {
+ if id == rmid {
+ todo.Notes = append(todo.Notes[:rmid], todo.Notes[rmid+1:]...)
+ return true
+ }
+ }
+ return false
+}
+
+func (p *Parser) ParseEditNote(todo *Todo, input string) bool {
+ r, _ := regexp.Compile(`^en\s+\d+\s+(\d+)\s+(.*)`)
+ matches := r.FindStringSubmatch(input)
+ if len(matches) != 3 {
+ return false
+ }
+
+ edid, err := p.getNoteID(matches[1])
+ if err != nil {
+ return false
+ }
+
+ for id, _ := range todo.Notes {
+ if id == edid {
+ todo.Notes[id] = matches[2]
+ return true
+ }
+ }
+ return false
+}
+
+func (p *Parser) ParseShowNote(todo *Todo, input string) bool {
+ r, _ := regexp.Compile(`^n\s+\d+`)
+ matches := r.FindStringSubmatch(input)
+ if len(matches) != 1 {
+ return false
+ }
+ return true
+}
+
+func (p *Parser) getNoteID(input string) (int, error) {
+ ret, err := strconv.Atoi(input)
+ if err != nil {
+ fmt.Println("wrong note id")
+ return -1, err
+ }
+ return ret, nil
+}
+
func (p *Parser) hasDue(input string) bool {
r1, _ := regexp.Compile(`due \w+$`)
r2, _ := regexp.Compile(`due \w+ \d+$`)
diff --git a/todolist/parser_test.go b/todolist/parser_test.go
index 476edaa..313ad9f 100644
--- a/todolist/parser_test.go
+++ b/todolist/parser_test.go
@@ -74,6 +74,96 @@ func TestParseContexts(t *testing.T) {
}
}
+func TestParseAddNote(t *testing.T) {
+ parser := &Parser{}
+ todo := parser.ParseNewTodo("add write the test functions")
+
+ b1 := parser.ParseAddNote(todo, "an 1 TestPasrseAddNote")
+ b2 := parser.ParseAddNote(todo, "an 1 TestPasrseDeleteNote")
+ b3 := parser.ParseAddNote(todo, "an 1 TestPasrseEditNote")
+
+ if !b1 || !b2 || !b3 {
+ t.Error("Fail adding notes, expected 3 notes but", len(todo.Notes))
+ }
+}
+
+func TestParseDeleteNote(t *testing.T) {
+ parser := &Parser{}
+ todo := parser.ParseNewTodo("add buy notebook")
+
+ todo.Notes = append(todo.Notes, "ASUStek")
+ todo.Notes = append(todo.Notes, "Apple")
+ todo.Notes = append(todo.Notes, "Dell")
+ todo.Notes = append(todo.Notes, "Acer")
+
+ b1 := parser.ParseDeleteNote(todo, "dn 1 1")
+ b2 := parser.ParseDeleteNote(todo, "dn 1 1")
+
+ if !b1 || !b2 {
+ t.Error("Fail deleting notes, expected 2 notes left but", len(todo.Notes))
+ }
+
+ if todo.Notes[0] != "ASUStek" || todo.Notes[1] != "Acer" {
+ t.Error("Fail deleting notes,", todo.Notes[0], "and", todo.Notes[1], "are left")
+ }
+}
+
+func TestParseEditNote(t *testing.T) {
+ parser := &Parser{}
+ todo := parser.ParseNewTodo("add record the weather")
+
+ todo.Notes = append(todo.Notes, "Aug 29 Wed")
+ todo.Notes = append(todo.Notes, "Cloudy")
+ todo.Notes = append(todo.Notes, "40°C")
+ todo.Notes = append(todo.Notes, "Tokyo")
+
+ parser.ParseEditNote(todo, "en 1 0 Aug 29 Tue")
+ if todo.Notes[0] != "Aug 29 Tue" {
+ t.Error("Fail editing notes, note 0 should be \"Aug 29 Tue\" but got", todo.Notes[0])
+ }
+
+ parser.ParseEditNote(todo, "en 1 1 Sunny")
+ if todo.Notes[1] != "Sunny" {
+ t.Error("Fail editing notes, note 1 should be \"Sunny\" but got", todo.Notes[1])
+ }
+
+ parser.ParseEditNote(todo, "en 1 2 22°C")
+ if todo.Notes[2] != "22°C" {
+ t.Error("Fail editing notes, note 2 should be \"22°C\" but got", todo.Notes[2])
+ }
+
+ parser.ParseEditNote(todo, "en 1 3 Seoul")
+ if todo.Notes[3] != "Seoul" {
+ t.Error("Fail editing notes, note 3 should be \"Seoul\" but got", todo.Notes[3])
+ }
+}
+
+func TestHandleNotes(t *testing.T) {
+ parser := &Parser{}
+ todo := parser.ParseNewTodo("add search engine survey")
+
+ if !parser.ParseAddNote(todo, "an 1 www.google.com") {
+ t.Error("Expected Notes to be added")
+ }
+ if todo.Notes[0] != "www.google.com" {
+ t.Error("Expected note 1 to be 'www.google.com' but got", todo.Notes[0])
+ }
+
+ if !parser.ParseEditNote(todo, "en 1 0 www.duckduckgo.com") {
+ t.Error("Expected Notes to be editted")
+ }
+ if todo.Notes[0] != "www.duckduckgo.com" {
+ t.Error("Expected note 1 to be 'www.duckduckgo.com' but got", todo.Notes[0])
+ }
+
+ if !parser.ParseDeleteNote(todo, "dn 1 0") {
+ t.Error("Expected Notes to be deleted")
+ }
+ if len(todo.Notes) != 0 {
+ t.Error("Expected no note")
+ }
+}
+
func TestDueToday(t *testing.T) {
assert := assert.New(t)
parser := &Parser{}
diff --git a/todolist/todo_item.go b/todolist/todo_item.go
index 0c30707..5b9bcbc 100644
--- a/todolist/todo_item.go
+++ b/todolist/todo_item.go
@@ -15,6 +15,7 @@ type Todo struct {
CompletedDate string `json:"completedDate"`
Archived bool `json:"archived"`
IsPriority bool `json:"isPriority"`
+ Notes []string `json:"notes"`
}
func NewTodo() *Todo {
diff --git a/todolist/todos.json b/todolist/todos.json
index 7f511ed..39593be 100644
--- a/todolist/todos.json
+++ b/todolist/todos.json
@@ -1 +1 @@
-[{"id":1,"subject":"this is the first subject","projects":["test1"],"contexts":["root"],"due":"2016-04-04","completed":false,"completedDate":"","archived":true,"isPriority":false},{"id":2,"subject":" audit userify for 2FA","projects":["test1"],"contexts":["root","more"],"due":"","completed":true,"completedDate":"","archived":false,"isPriority":false}] \ No newline at end of file
+[{"id":1,"subject":"this is the first subject","projects":["test1"],"contexts":["root"],"due":"2016-04-04","completed":false,"completedDate":"","archived":true,"isPriority":false,"notes":null},{"id":2,"subject":" audit userify for 2FA","projects":["test1"],"contexts":["root","more"],"due":"","completed":true,"completedDate":"","archived":false,"isPriority":false,"notes":null}] \ No newline at end of file