From 08bfbb5ba4be9bf936c86c8cfd38cfe9835a13d4 Mon Sep 17 00:00:00 2001 From: Quey-Liang Kao Date: Sat, 4 Feb 2017 20:58:16 +0800 Subject: Global repo file as the default This patch implments the new workflow mentioned in #31, in which the program still tries to find a repo file in the working directory first, and it tries the global one in the home directory if no one is found. In this patch, the condition check of the existence of the repo file is done in `todolist/file_store.go` at the very early step before the input routing. --- todo.go | 4 ++++ todolist/app.go | 5 +++++ todolist/file_store.go | 22 +++++++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/todo.go b/todo.go index 2a45f28..f7d994d 100644 --- a/todo.go +++ b/todo.go @@ -110,6 +110,10 @@ func usage() { func routeInput(command string, input string) { app := todolist.NewApp() + if app == nil { + return + } + switch command { case "l", "list", "agenda": app.ListTodos(input) diff --git a/todolist/app.go b/todolist/app.go index 1ab6b20..e3d8cc7 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -15,6 +15,11 @@ type App struct { func NewApp() *App { app := &App{TodoList: &TodoList{}, TodoStore: NewFileStore()} + if app.TodoStore.FileLocation == "" { + fmt.Println("No todo file found!") + fmt.Println("You may run 'todo init' to initialize an empty repo in current directory.") + return nil + } return app } diff --git a/todolist/file_store.go b/todolist/file_store.go index 5413295..63738b2 100644 --- a/todolist/file_store.go +++ b/todolist/file_store.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "os" + "os/user" ) type FileStore struct { @@ -13,22 +14,33 @@ type FileStore struct { } func NewFileStore() *FileStore { - return &FileStore{FileLocation: ".todos.json", Loaded: false} + localrepo := ".todos.json" + usr, _ := user.Current() + homerepo := fmt.Sprintf("%s/.todos.json", usr.HomeDir) + _, err1 := os.Stat(localrepo) + _, err2 := os.Stat(homerepo) + + if err1 == nil { + return &FileStore{FileLocation: localrepo, Loaded: false} + } else if err2 == nil { + return &FileStore{FileLocation: homerepo, Loaded: false} + } else { + return &FileStore{FileLocation: "", Loaded: false} + } } func (f *FileStore) Load() ([]*Todo, error) { data, err := ioutil.ReadFile(f.FileLocation) if err != nil { - fmt.Println("No todo file found!") - fmt.Println("Initialize a new todo repo by running 'todo init'") + fmt.Println("Error reading", f.FileLocation, "by", err) return nil, err - os.Exit(0) + os.Exit(1) } var todos []*Todo jerr := json.Unmarshal(data, &todos) if jerr != nil { - fmt.Println("Error reading json data", jerr) + fmt.Println("Error reading", f.FileLocation, "by", jerr) return nil, jerr os.Exit(1) } -- cgit v1.3 From 89b73b0df1a5c06cf2399bfb0d46a83e053c6561 Mon Sep 17 00:00:00 2001 From: Quey-Liang Kao Date: Sun, 19 Feb 2017 22:12:39 +0800 Subject: Refine previous commit --- todolist/app.go | 5 ----- todolist/file_store.go | 5 ++++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/todolist/app.go b/todolist/app.go index e3d8cc7..1ab6b20 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -15,11 +15,6 @@ type App struct { func NewApp() *App { app := &App{TodoList: &TodoList{}, TodoStore: NewFileStore()} - if app.TodoStore.FileLocation == "" { - fmt.Println("No todo file found!") - fmt.Println("You may run 'todo init' to initialize an empty repo in current directory.") - return nil - } return app } diff --git a/todolist/file_store.go b/todolist/file_store.go index 63738b2..4a7f0e0 100644 --- a/todolist/file_store.go +++ b/todolist/file_store.go @@ -25,7 +25,10 @@ func NewFileStore() *FileStore { } else if err2 == nil { return &FileStore{FileLocation: homerepo, Loaded: false} } else { - return &FileStore{FileLocation: "", Loaded: false} + fmt.Println("No todo file found!") + fmt.Println("You may run 'todo init' to initialize an empty repo in working directory.") + os.Exit(1) + return nil } } -- cgit v1.3 From 369097a97856c70ab213428957c86abc9937a069 Mon Sep 17 00:00:00 2001 From: Quey-Liang Kao Date: Mon, 20 Feb 2017 02:16:31 +0800 Subject: Refine the commits --- todo.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/todo.go b/todo.go index f7d994d..2a45f28 100644 --- a/todo.go +++ b/todo.go @@ -110,10 +110,6 @@ func usage() { func routeInput(command string, input string) { app := todolist.NewApp() - if app == nil { - return - } - switch command { case "l", "list", "agenda": app.ListTodos(input) -- cgit v1.3 From c2114f083afeb1ac2cc28e9a83f3a9c591b59a1f Mon Sep 17 00:00:00 2001 From: Grant Ammons Date: Fri, 3 Mar 2017 18:30:06 -0500 Subject: Add priority feature Now, todos have a priority flag. When listed, these todos will be bolded and italic. You can list todos by priority by running `todolist l p`. --- todo.go | 13 ++++++++++++ todolist/app.go | 22 ++++++++++++++++++++ todolist/filter.go | 22 +++++++++++++++++++- todolist/formatter.go | 52 ++++++++++++++++++++++++++++++---------------- todolist/todo_item.go | 17 ++++++++------- todolist/todo_list.go | 14 +++++++++++++ todolist/todo_list_test.go | 20 ++++++++++++++++++ todolist/todos.json | 2 +- 8 files changed, 134 insertions(+), 28 deletions(-) diff --git a/todo.go b/todo.go index 2a45f28..f8a2d70 100644 --- a/todo.go +++ b/todo.go @@ -81,6 +81,15 @@ func usage() { yellow.Println("\ttodo uc 33") fmt.Println("\tUncompletes a todo with id 33\n") + blueBold.Println("\nPrioritizing") + fmt.Println("Todos have a priority flag, which will make them bold when listed.\n") + yellow.Println("\ttodo p 33") + fmt.Println("\tPrioritizes a todo with id 33\n") + yellow.Println("\ttodo up 33") + fmt.Println("\tUn-prioritizes a todo with id 33\n") + yellow.Println("\ttodo l p") + fmt.Println("\tlist all priority todos\n") + blueBold.Println("\nArchiving") fmt.Println("You can archive todos once they are done, or if you might come back to them.") fmt.Println("By default, todo will only show unarchived todos.\n") @@ -131,6 +140,10 @@ func routeInput(command string, input string) { app.EditTodoDue(input) case "ex", "expand": app.ExpandTodo(input) + case "p", "prioritize": + app.PrioritizeTodo(input) + case "up", "unprioritize": + app.UnprioritizeTodo(input) case "init": app.InitializeRepo() case "web": diff --git a/todolist/app.go b/todolist/app.go index 1ab6b20..495d087 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -150,6 +150,28 @@ func (a *App) ListTodos(input string) { formatter.Print() } +func (a *App) PrioritizeTodo(input string) { + a.Load() + id, _ := a.getId(input) + if id == -1 { + return + } + a.TodoList.Prioritize(id) + a.Save() + fmt.Println("Todo prioritized.") +} + +func (a *App) UnprioritizeTodo(input string) { + a.Load() + id, _ := a.getId(input) + if id == -1 { + return + } + a.TodoList.Unprioritize(id) + a.Save() + fmt.Println("Todo un-prioritized.") +} + func (a *App) getId(input string) (int, *Todo) { re, _ := regexp.Compile("\\d+") if re.MatchString(input) { diff --git a/todolist/filter.go b/todolist/filter.go index 2b25109..b577e60 100644 --- a/todolist/filter.go +++ b/todolist/filter.go @@ -12,6 +12,7 @@ func NewFilter(todos []*Todo) *TodoFilter { func (f *TodoFilter) Filter(input string) []*Todo { f.Todos = f.filterArchived(input) + f.Todos = f.filterPrioritized(input) f.Todos = f.filterProjects(input) f.Todos = f.filterContexts(input) f.Todos = NewDateFilter(f.Todos).FilterDate(input) @@ -38,6 +39,15 @@ func (f *TodoFilter) filterArchived(input string) []*Todo { } } +func (f *TodoFilter) filterPrioritized(input string) []*Todo { + r, _ := regexp.Compile(`l p`) + if r.MatchString(input) { + return f.getPrioritized() + } else { + return f.Todos + } +} + func (f *TodoFilter) filterProjects(input string) []*Todo { if !f.isFilteringByProjects(input) { return f.Todos @@ -81,7 +91,17 @@ func (f *TodoFilter) filterContexts(input string) []*Todo { func (f *TodoFilter) getArchived() []*Todo { var ret []*Todo for _, todo := range f.Todos { - if todo.Archived == true { + if todo.Archived { + ret = append(ret, todo) + } + } + return ret +} + +func (f *TodoFilter) getPrioritized() []*Todo { + var ret []*Todo + for _, todo := range f.Todos { + if todo.IsPriority { ret = append(ret, todo) } } diff --git a/todolist/formatter.go b/todolist/formatter.go index 43d9b1e..c0f3313 100644 --- a/todolist/formatter.go +++ b/todolist/formatter.go @@ -44,20 +44,28 @@ func (f *Formatter) Print() { } func (f *Formatter) printTodo(todo *Todo) { - yellow := color.New(color.FgYellow).SprintFunc() + yellow := color.New(color.FgYellow) + if todo.IsPriority { + yellow.Add(color.Bold, color.Italic) + } fmt.Fprintf(f.Writer, " %s\t%s\t%s\t%s\t\n", - yellow(strconv.Itoa(todo.Id)), + yellow.SprintFunc()(strconv.Itoa(todo.Id)), f.formatCompleted(todo.Completed), - f.formatDue(todo.Due), - f.formatSubject(todo.Subject)) + f.formatDue(todo.Due, todo.IsPriority), + f.formatSubject(todo.Subject, todo.IsPriority)) } -func (f *Formatter) formatDue(due string) string { - blue := color.New(color.FgBlue).SprintFunc() - red := color.New(color.FgRed).SprintFunc() +func (f *Formatter) formatDue(due string, isPriority bool) string { + blue := color.New(color.FgBlue) + red := color.New(color.FgRed) + + if isPriority { + blue.Add(color.Bold, color.Italic) + red.Add(color.Bold, color.Italic) + } if due == "" { - return blue(" ") + return blue.SprintFunc()(" ") } dueTime, err := time.Parse("2006-01-02", due) @@ -68,13 +76,13 @@ func (f *Formatter) formatDue(due string) string { } if isToday(dueTime) { - return blue("today") + return blue.SprintFunc()("today") } else if isTomorrow(dueTime) { - return blue("tomorrow") + return blue.SprintFunc()("tomorrow") } else if isPastDue(dueTime) { - return red(dueTime.Format("Mon Jan 2")) + return red.SprintFunc()(dueTime.Format("Mon Jan 2")) } else { - return blue(dueTime.Format("Mon Jan 2")) + return blue.SprintFunc()(dueTime.Format("Mon Jan 2")) } } @@ -98,9 +106,17 @@ func isPastDue(t time.Time) bool { return time.Now().After(t) } -func (f *Formatter) formatSubject(subject string) string { - red := color.New(color.FgRed).SprintFunc() - magenta := color.New(color.FgMagenta).SprintFunc() +func (f *Formatter) formatSubject(subject string, isPriority bool) string { + + red := color.New(color.FgRed) + magenta := color.New(color.FgMagenta) + white := color.New(color.FgWhite) + + if isPriority { + red.Add(color.Bold, color.Italic) + magenta.Add(color.Bold, color.Italic) + white.Add(color.Bold, color.Italic) + } splitted := strings.Split(subject, " ") projectRegex, _ := regexp.Compile(`\+[\p{L}\d_]+`) @@ -110,11 +126,11 @@ func (f *Formatter) formatSubject(subject string) string { for _, word := range splitted { if projectRegex.MatchString(word) { - coloredWords = append(coloredWords, magenta(word)) + coloredWords = append(coloredWords, magenta.SprintFunc()(word)) } else if contextRegex.MatchString(word) { - coloredWords = append(coloredWords, red(word)) + coloredWords = append(coloredWords, red.SprintFunc()(word)) } else { - coloredWords = append(coloredWords, word) + coloredWords = append(coloredWords, white.SprintFunc()(word)) } } return strings.Join(coloredWords, " ") diff --git a/todolist/todo_item.go b/todolist/todo_item.go index 6b820b1..273df8d 100644 --- a/todolist/todo_item.go +++ b/todolist/todo_item.go @@ -3,17 +3,18 @@ package todolist import "time" type Todo struct { - Id int `json:"id"` - Subject string `json:"subject"` - Projects []string `json:"projects"` - Contexts []string `json:"contexts"` - Due string `json:"due"` - Completed bool `json:"completed"` - Archived bool `json:"archived"` + Id int `json:"id"` + Subject string `json:"subject"` + Projects []string `json:"projects"` + Contexts []string `json:"contexts"` + Due string `json:"due"` + Completed bool `json:"completed"` + Archived bool `json:"archived"` + IsPriority bool `json:"isPriority"` } func NewTodo() *Todo { - return &Todo{Completed: false, Archived: false} + return &Todo{Completed: false, Archived: false, IsPriority: false} } func (t Todo) Valid() bool { diff --git a/todolist/todo_list.go b/todolist/todo_list.go index d7e1f83..71484c6 100644 --- a/todolist/todo_list.go +++ b/todolist/todo_list.go @@ -63,6 +63,20 @@ func (t *TodoList) IndexOf(todoToFind *Todo) int { return -1 } +func (t *TodoList) Prioritize(id int) { + todo := t.FindById(id) + todo.IsPriority = true + t.Delete(id) + t.Data = append(t.Data, todo) +} + +func (t *TodoList) Unprioritize(id int) { + todo := t.FindById(id) + todo.IsPriority = false + t.Delete(id) + t.Data = append(t.Data, todo) +} + type ByDate []*Todo func (a ByDate) Len() int { return len(a) } diff --git a/todolist/todo_list_test.go b/todolist/todo_list_test.go index 8a40b14..bd0f926 100644 --- a/todolist/todo_list_test.go +++ b/todolist/todo_list_test.go @@ -77,3 +77,23 @@ func TestUncomplete(t *testing.T) { list.Uncomplete(2) assert.Equal(false, list.FindById(2).Completed) } + +func TestPrioritizeNotInTodosJson(t *testing.T) { + assert := assert.New(t) + store := &FileStore{FileLocation: "todos.json"} + list := &TodoList{} + todos, _ := store.Load() + list.Load(todos) + assert.Equal(false, list.FindById(2).IsPriority) +} + +func TestPrioritizeTodo(t *testing.T) { + assert := assert.New(t) + list := &TodoList{} + todo := &Todo{Archived: false, Completed: false, Subject: "testing", IsPriority: false} + list.Add(todo) + list.Prioritize(1) + assert.Equal(true, list.FindById(1).IsPriority) + list.Unprioritize(1) + assert.Equal(false, list.FindById(1).IsPriority) +} diff --git a/todolist/todos.json b/todolist/todos.json index 5e44228..bc147d1 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,"archived":true},{"id":2,"subject":" audit userify for 2FA","projects":["test1"],"contexts":["root","more"],"due":"","completed":true,"archived":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,"archived":true,"isPriority":false},{"id":2,"subject":" audit userify for 2FA","projects":["test1"],"contexts":["root","more"],"due":"","completed":true,"archived":false,"isPriority":false}] \ No newline at end of file -- cgit v1.3 From ee5353cf832a2fec57eacb77396a443e6d6a5b9e Mon Sep 17 00:00:00 2001 From: DmitriyMV Date: Thu, 2 Mar 2017 14:11:09 +0300 Subject: This commit removes all usages of github.com/jinzhu/now. github.com/jinzhu/now has numerous errors handling date and time. The example's of them are: 1. Incorrect handling of DST (https://github.com/jinzhu/now/issues/13). 2. 24 Hour long days (https://stackoverflow.com/questions/25254443/return-local-beginning-of-day-time-object-in-go) Chicago has 23, 24, or 25 hours in a day. 3. Incorrect usage of time.Truncate which can return time with a non-zero minute, depending on the time's Location. (https://github.com/golang/go/issues/16647). There are other issues as well, including getting incorrect beginning and end of the month. --- todolist/date_filter.go | 32 +++--- todolist/date_filter_test.go | 5 +- todolist/parser.go | 24 ++--- todolist/parser_test.go | 9 +- todolist/util.go | 17 +++ vendor/github.com/jinzhu/now/Guardfile | 3 - vendor/github.com/jinzhu/now/README.md | 104 ------------------- vendor/github.com/jinzhu/now/main.go | 103 ------------------- vendor/github.com/jinzhu/now/now.go | 182 --------------------------------- 9 files changed, 49 insertions(+), 430 deletions(-) delete mode 100644 vendor/github.com/jinzhu/now/Guardfile delete mode 100644 vendor/github.com/jinzhu/now/README.md delete mode 100644 vendor/github.com/jinzhu/now/main.go delete mode 100644 vendor/github.com/jinzhu/now/now.go diff --git a/todolist/date_filter.go b/todolist/date_filter.go index 2bf51e2..7895000 100644 --- a/todolist/date_filter.go +++ b/todolist/date_filter.go @@ -3,8 +3,6 @@ package todolist import ( "regexp" "time" - - "github.com/jinzhu/now" ) type DateFilter struct { @@ -19,36 +17,36 @@ func NewDateFilter(todos []*Todo) *DateFilter { func (f *DateFilter) FilterDate(input string) []*Todo { agendaRegex, _ := regexp.Compile(`agenda .*$`) if agendaRegex.MatchString(input) { - return f.filterAgenda(now.BeginningOfDay()) + return f.filterAgenda(bod(time.Now())) } r, _ := regexp.Compile(`due .*$`) match := r.FindString(input) switch { case match == "due tod" || match == "due today": - return f.filterToday(now.BeginningOfDay()) + return f.filterToday(bod(time.Now())) case match == "due tom" || match == "due tomorrow": - return f.filterTomorrow(now.BeginningOfDay()) + return f.filterTomorrow(bod(time.Now())) case match == "due sun" || match == "due sunday": - return f.filterDay(now.BeginningOfDay(), time.Sunday) + return f.filterDay(bod(time.Now()), time.Sunday) case match == "due mon" || match == "due monday": - return f.filterDay(now.BeginningOfDay(), time.Monday) + return f.filterDay(bod(time.Now()), time.Monday) case match == "due tue" || match == "due tuesday": - return f.filterDay(now.BeginningOfDay(), time.Tuesday) + return f.filterDay(bod(time.Now()), time.Tuesday) case match == "due wed" || match == "due wednesday": - return f.filterDay(now.BeginningOfDay(), time.Wednesday) + return f.filterDay(bod(time.Now()), time.Wednesday) case match == "due thu" || match == "due thursday": - return f.filterDay(now.BeginningOfDay(), time.Thursday) + return f.filterDay(bod(time.Now()), time.Thursday) case match == "due fri" || match == "due friday": - return f.filterDay(now.BeginningOfDay(), time.Friday) + return f.filterDay(bod(time.Now()), time.Friday) case match == "due sat" || match == "due saturday": - return f.filterDay(now.BeginningOfDay(), time.Saturday) + return f.filterDay(bod(time.Now()), time.Saturday) case match == "due this week": - return f.filterThisWeek(now.BeginningOfDay()) + return f.filterThisWeek(bod(time.Now())) case match == "due next week": - return f.filterNextWeek(now.BeginningOfDay()) + return f.filterNextWeek(bod(time.Now())) case match == "overdue": - return f.filterOverdue(now.BeginningOfDay()) + return f.filterOverdue(bod(time.Now())) } return f.Todos } @@ -102,7 +100,7 @@ func (f *DateFilter) filterTomorrow(pivot time.Time) []*Todo { func (f *DateFilter) filterThisWeek(pivot time.Time) []*Todo { var ret []*Todo - begin := now.New(f.FindSunday(pivot)).BeginningOfDay() + begin := bod(f.FindSunday(pivot)) end := begin.AddDate(0, 0, 7) for _, todo := range f.Todos { @@ -144,7 +142,7 @@ func (f *DateFilter) filterOverdue(pivot time.Time) []*Todo { } func (f *DateFilter) FindSunday(pivot time.Time) time.Time { - switch now.New(pivot).Weekday() { + switch pivot.Weekday() { case time.Sunday: return pivot case time.Monday: diff --git a/todolist/date_filter_test.go b/todolist/date_filter_test.go index 8ee8db5..444b4ac 100644 --- a/todolist/date_filter_test.go +++ b/todolist/date_filter_test.go @@ -4,7 +4,6 @@ import ( "testing" "time" - "github.com/jinzhu/now" "github.com/stretchr/testify/assert" ) @@ -63,7 +62,7 @@ func TestFilterOverdue(t *testing.T) { var todos []*Todo lastWeekTodo := &Todo{Id: 1, Subject: "one", Due: time.Now().AddDate(0, 0, -7).Format("2006-01-02")} - todayTodo := &Todo{Id: 2, Subject: "two", Due: now.BeginningOfDay().Format("2006-01-02")} + todayTodo := &Todo{Id: 2, Subject: "two", Due: bod(time.Now()).Format("2006-01-02")} tomorrowTodo := &Todo{Id: 3, Subject: "three", Due: time.Now().AddDate(0, 0, 1).Format("2006-01-02")} todos = append(todos, lastWeekTodo) @@ -71,7 +70,7 @@ func TestFilterOverdue(t *testing.T) { todos = append(todos, tomorrowTodo) filter := NewDateFilter(todos) - filtered := filter.filterOverdue(now.BeginningOfDay()) + filtered := filter.filterOverdue(bod(time.Now())) assert.Equal(1, len(filtered)) assert.Equal(1, filtered[0].Id) diff --git a/todolist/parser.go b/todolist/parser.go index 6cf1967..24a4016 100644 --- a/todolist/parser.go +++ b/todolist/parser.go @@ -7,8 +7,6 @@ import ( "strconv" "strings" "time" - - "github.com/jinzhu/now" ) type Parser struct{} @@ -79,9 +77,9 @@ func (p *Parser) Due(input string, day time.Time) string { case "none": return "" case "today", "tod": - return now.BeginningOfDay().Format("2006-01-02") + return bod(time.Now()).Format("2006-01-02") case "tomorrow", "tom": - return now.BeginningOfDay().AddDate(0, 0, 1).Format("2006-01-02") + return bod(time.Now()).AddDate(0, 0, 1).Format("2006-01-02") case "monday", "mon": return p.monday(day) case "tuesday", "tue": @@ -97,8 +95,8 @@ func (p *Parser) Due(input string, day time.Time) string { case "sunday", "sun": return p.sunday(day) case "next week": - n := now.BeginningOfDay() - return now.New(n).Monday().AddDate(0, 0, 7).Format("2006-01-02") + n := bod(time.Now()) + return getNearestMonday(n).AddDate(0, 0, 7).Format("2006-01-02") } return p.parseArbitraryDate(res, time.Now()) } @@ -137,37 +135,37 @@ func (p *Parser) parseArbitraryDateWithYear(_date string, year int) time.Time { } func (p *Parser) monday(day time.Time) string { - mon := now.New(day).Monday() + mon := getNearestMonday(day) return p.thisOrNextWeek(mon, day) } func (p *Parser) tuesday(day time.Time) string { - tue := now.New(day).Monday().AddDate(0, 0, 1) + tue := getNearestMonday(day).AddDate(0, 0, 1) return p.thisOrNextWeek(tue, day) } func (p *Parser) wednesday(day time.Time) string { - tue := now.New(day).Monday().AddDate(0, 0, 2) + tue := getNearestMonday(day).AddDate(0, 0, 2) return p.thisOrNextWeek(tue, day) } func (p *Parser) thursday(day time.Time) string { - tue := now.New(day).Monday().AddDate(0, 0, 3) + tue := getNearestMonday(day).AddDate(0, 0, 3) return p.thisOrNextWeek(tue, day) } func (p *Parser) friday(day time.Time) string { - tue := now.New(day).Monday().AddDate(0, 0, 4) + tue := getNearestMonday(day).AddDate(0, 0, 4) return p.thisOrNextWeek(tue, day) } func (p *Parser) saturday(day time.Time) string { - tue := now.New(day).Monday().AddDate(0, 0, 5) + tue := getNearestMonday(day).AddDate(0, 0, 5) return p.thisOrNextWeek(tue, day) } func (p *Parser) sunday(day time.Time) string { - tue := now.New(day).Monday().AddDate(0, 0, 6) + tue := getNearestMonday(day).AddDate(0, 0, 6) return p.thisOrNextWeek(tue, day) } diff --git a/todolist/parser_test.go b/todolist/parser_test.go index 791958c..cbb94e8 100644 --- a/todolist/parser_test.go +++ b/todolist/parser_test.go @@ -6,7 +6,6 @@ import ( "testing" "time" - "github.com/jinzhu/now" "github.com/stretchr/testify/assert" ) @@ -75,11 +74,11 @@ func TestParseContexts(t *testing.T) { func TestDueToday(t *testing.T) { parser := &Parser{} todo := parser.ParseNewTodo("do this thing with @bob and @mary due today") - if todo.Due != now.BeginningOfDay().Format("2006-01-02") { + if todo.Due != bod(time.Now()).Format("2006-01-02") { fmt.Println("Date is different", todo.Due, time.Now()) } todo = parser.ParseNewTodo("do this thing with @bob and @mary due tod") - if todo.Due != now.BeginningOfDay().Format("2006-01-02") { + if todo.Due != bod(time.Now()).Format("2006-01-02") { fmt.Println("Date is different", todo.Due, time.Now()) } } @@ -87,11 +86,11 @@ func TestDueToday(t *testing.T) { func TestDueTomorrow(t *testing.T) { parser := &Parser{} todo := parser.ParseNewTodo("do this thing with @bob and @mary due tomorrow") - if todo.Due != now.BeginningOfDay().AddDate(0, 0, 1).Format("2006-01-02") { + if todo.Due != bod(time.Now()).AddDate(0, 0, 1).Format("2006-01-02") { fmt.Println("Date is different", todo.Due, time.Now()) } todo = parser.ParseNewTodo("do this thing with @bob and @mary due tom") - if todo.Due != now.BeginningOfDay().AddDate(0, 0, 1).Format("2006-01-02") { + if todo.Due != bod(time.Now()).AddDate(0, 0, 1).Format("2006-01-02") { fmt.Println("Date is different", todo.Due, time.Now()) } } diff --git a/todolist/util.go b/todolist/util.go index bbed216..72d475f 100644 --- a/todolist/util.go +++ b/todolist/util.go @@ -1,5 +1,7 @@ package todolist +import "time" + func AddIfNotThere(arr []string, items []string) []string { for _, item := range items { there := false @@ -27,3 +29,18 @@ func AddTodoIfNotThere(arr []*Todo, item *Todo) []*Todo { } return arr } + +func bod(t time.Time) time.Time { + year, month, day := t.Date() + return time.Date(year, month, day, 0, 0, 0, 0, t.Location()) +} + +func getNearestMonday(t time.Time) time.Time { + for { + if t.Weekday() != time.Monday { + t = t.AddDate(0, 0, -1) + } else { + return t + } + } +} diff --git a/vendor/github.com/jinzhu/now/Guardfile b/vendor/github.com/jinzhu/now/Guardfile deleted file mode 100644 index 0b860b0..0000000 --- a/vendor/github.com/jinzhu/now/Guardfile +++ /dev/null @@ -1,3 +0,0 @@ -guard 'gotest' do - watch(%r{\.go$}) -end diff --git a/vendor/github.com/jinzhu/now/README.md b/vendor/github.com/jinzhu/now/README.md deleted file mode 100644 index 073c1c6..0000000 --- a/vendor/github.com/jinzhu/now/README.md +++ /dev/null @@ -1,104 +0,0 @@ -## Now - -Now is a time toolkit for golang - -#### Why the project named `Now`? - -```go -now.BeginningOfDay() -``` -`now` is quite readable, aha? - -#### But `now` is so common I can't search the project with my favorite search engine - -* Star it in github [https://github.com/jinzhu/now](https://github.com/jinzhu/now) -* Search it with [http://godoc.org](http://godoc.org) - -## Install - -``` -go get -u github.com/jinzhu/now -``` - -### Usage - -```go -import "github.com/jinzhu/now" - -time.Now() // 2013-11-18 17:51:49.123456789 Mon - -now.BeginningOfMinute() // 2013-11-18 17:51:00 Mon -now.BeginningOfHour() // 2013-11-18 17:00:00 Mon -now.BeginningOfDay() // 2013-11-18 00:00:00 Mon -now.BeginningOfWeek() // 2013-11-17 00:00:00 Sun -now.FirstDayMonday = true // Set Monday as first day, default is Sunday -now.BeginningOfWeek() // 2013-11-18 00:00:00 Mon -now.BeginningOfMonth() // 2013-11-01 00:00:00 Fri -now.BeginningOfQuarter() // 2013-10-01 00:00:00 Tue -now.BeginningOfYear() // 2013-01-01 00:00:00 Tue - -now.EndOfMinute() // 2013-11-18 17:51:59.999999999 Mon -now.EndOfHour() // 2013-11-18 17:59:59.999999999 Mon -now.EndOfDay() // 2013-11-18 23:59:59.999999999 Mon -now.EndOfWeek() // 2013-11-23 23:59:59.999999999 Sat -now.FirstDayMonday = true // Set Monday as first day, default is Sunday -now.EndOfWeek() // 2013-11-24 23:59:59.999999999 Sun -now.EndOfMonth() // 2013-11-30 23:59:59.999999999 Sat -now.EndOfQuarter() // 2013-12-31 23:59:59.999999999 Tue -now.EndOfYear() // 2013-12-31 23:59:59.999999999 Tue - - -// Use another time -t := time.Date(2013, 02, 18, 17, 51, 49, 123456789, time.Now().Location()) -now.New(t).EndOfMonth() // 2013-02-28 23:59:59.999999999 Thu - - -// Don't want be bothered with the First Day setting, Use Monday, Sunday -now.Monday() // 2013-11-18 00:00:00 Mon -now.Sunday() // 2013-11-24 00:00:00 Sun (Next Sunday) -now.EndOfSunday() // 2013-11-24 23:59:59.999999999 Sun (End of next Sunday) - -t := time.Date(2013, 11, 24, 17, 51, 49, 123456789, time.Now().Location()) // 2013-11-24 17:51:49.123456789 Sun -now.New(t).Monday() // 2013-11-18 00:00:00 Sun (Last Monday if today is Sunday) -now.New(t).Sunday() // 2013-11-24 00:00:00 Sun (Beginning Of Today if today is Sunday) -now.New(t).EndOfSunday() // 2013-11-24 23:59:59.999999999 Sun (End of Today if today is Sunday) -``` - -#### Parse String - -```go -time.Now() // 2013-11-18 17:51:49.123456789 Mon - -// Parse(string) (time.Time, error) -t, err := now.Parse("12:20") // 2013-11-18 12:20:00, nil -t, err := now.Parse("1999-12-12 12:20") // 1999-12-12 12:20:00, nil -t, err := now.Parse("99:99") // 2013-11-18 12:20:00, Can't parse string as time: 99:99 - -// MustParse(string) time.Time -now.MustParse("2013-01-13") // 2013-01-13 00:00:00 -now.MustParse("02-17") // 2013-02-17 00:00:00 -now.MustParse("2-17") // 2013-02-17 00:00:00 -now.MustParse("8") // 2013-11-18 08:00:00 -now.MustParse("2002-10-12 22:14") // 2002-10-12 22:14:00 -now.MustParse("99:99") // panic: Can't parse string as time: 99:99 -``` - -Extend `now` to support more formats is quite easy, just update `TimeFormats` variable with `time.Format` like time layout - -```go -now.TimeFormats = append(now.TimeFormats, "02 Jan 2006 15:04") -``` - -Please send me pull requests if you want a format to be supported officially - -# Author - -**jinzhu** - -* -* -* - -## License - -Released under the [MIT License](http://www.opensource.org/licenses/MIT). diff --git a/vendor/github.com/jinzhu/now/main.go b/vendor/github.com/jinzhu/now/main.go deleted file mode 100644 index 5210ba2..0000000 --- a/vendor/github.com/jinzhu/now/main.go +++ /dev/null @@ -1,103 +0,0 @@ -// Package now is a time toolkit for golang. -// -// More details README here: https://github.com/jinzhu/now -// -// import "github.com/jinzhu/now" -// -// now.BeginningOfMinute() // 2013-11-18 17:51:00 Mon -// now.BeginningOfDay() // 2013-11-18 00:00:00 Mon -// now.EndOfDay() // 2013-11-18 23:59:59.999999999 Mon -package now - -import "time" - -var FirstDayMonday bool -var TimeFormats = []string{"1/2/2006", "1/2/2006 15:4:5", "2006-1-2 15:4:5", "2006-1-2 15:4", "2006-1-2", "1-2", "15:4:5", "15:4", "15", "15:4:5 Jan 2, 2006 MST"} - -type Now struct { - time.Time -} - -func New(t time.Time) *Now { - return &Now{t} -} - -func BeginningOfMinute() time.Time { - return New(time.Now()).BeginningOfMinute() -} - -func BeginningOfHour() time.Time { - return New(time.Now()).BeginningOfHour() -} - -func BeginningOfDay() time.Time { - return New(time.Now()).BeginningOfDay() -} - -func BeginningOfWeek() time.Time { - return New(time.Now()).BeginningOfWeek() -} - -func BeginningOfMonth() time.Time { - return New(time.Now()).BeginningOfMonth() -} - -func BeginningOfQuarter() time.Time { - return New(time.Now()).BeginningOfQuarter() -} - -func BeginningOfYear() time.Time { - return New(time.Now()).BeginningOfYear() -} - -func EndOfMinute() time.Time { - return New(time.Now()).EndOfMinute() -} - -func EndOfHour() time.Time { - return New(time.Now()).EndOfHour() -} - -func EndOfDay() time.Time { - return New(time.Now()).EndOfDay() -} - -func EndOfWeek() time.Time { - return New(time.Now()).EndOfWeek() -} - -func EndOfMonth() time.Time { - return New(time.Now()).EndOfMonth() -} - -func EndOfQuarter() time.Time { - return New(time.Now()).EndOfQuarter() -} - -func EndOfYear() time.Time { - return New(time.Now()).EndOfYear() -} - -func Monday() time.Time { - return New(time.Now()).Monday() -} - -func Sunday() time.Time { - return New(time.Now()).Sunday() -} - -func EndOfSunday() time.Time { - return New(time.Now()).EndOfSunday() -} - -func Parse(strs ...string) (time.Time, error) { - return New(time.Now()).Parse(strs...) -} - -func MustParse(strs ...string) time.Time { - return New(time.Now()).MustParse(strs...) -} - -func Between(time1, time2 string) bool { - return New(time.Now()).Between(time1, time2) -} diff --git a/vendor/github.com/jinzhu/now/now.go b/vendor/github.com/jinzhu/now/now.go deleted file mode 100644 index 97208d5..0000000 --- a/vendor/github.com/jinzhu/now/now.go +++ /dev/null @@ -1,182 +0,0 @@ -package now - -import ( - "errors" - "regexp" - "time" -) - -func (now *Now) BeginningOfMinute() time.Time { - return now.Truncate(time.Minute) -} - -func (now *Now) BeginningOfHour() time.Time { - return now.Truncate(time.Hour) -} - -func (now *Now) BeginningOfDay() time.Time { - d := time.Duration(-now.Hour()) * time.Hour - return now.BeginningOfHour().Add(d) -} - -func (now *Now) BeginningOfWeek() time.Time { - t := now.BeginningOfDay() - weekday := int(t.Weekday()) - if FirstDayMonday { - if weekday == 0 { - weekday = 7 - } - weekday = weekday - 1 - } - - d := time.Duration(-weekday) * 24 * time.Hour - return t.Add(d) -} - -func (now *Now) BeginningOfMonth() time.Time { - t := now.BeginningOfDay() - d := time.Duration(-int(t.Day())+1) * 24 * time.Hour - return t.Add(d) -} - -func (now *Now) BeginningOfQuarter() time.Time { - month := now.BeginningOfMonth() - offset := (int(month.Month()) - 1) % 3 - return month.AddDate(0, -offset, 0) -} - -func (now *Now) BeginningOfYear() time.Time { - t := now.BeginningOfDay() - d := time.Duration(-int(t.YearDay())+1) * 24 * time.Hour - return t.Truncate(time.Hour).Add(d) -} - -func (now *Now) EndOfMinute() time.Time { - return now.BeginningOfMinute().Add(time.Minute - time.Nanosecond) -} - -func (now *Now) EndOfHour() time.Time { - return now.BeginningOfHour().Add(time.Hour - time.Nanosecond) -} - -func (now *Now) EndOfDay() time.Time { - return now.BeginningOfDay().Add(24*time.Hour - time.Nanosecond) -} - -func (now *Now) EndOfWeek() time.Time { - return now.BeginningOfWeek().AddDate(0, 0, 7).Add(-time.Nanosecond) -} - -func (now *Now) EndOfMonth() time.Time { - return now.BeginningOfMonth().AddDate(0, 1, 0).Add(-time.Nanosecond) -} - -func (now *Now) EndOfQuarter() time.Time { - return now.BeginningOfQuarter().AddDate(0, 3, 0).Add(-time.Nanosecond) -} - -func (now *Now) EndOfYear() time.Time { - return now.BeginningOfYear().AddDate(1, 0, 0).Add(-time.Nanosecond) -} - -func (now *Now) Monday() time.Time { - t := now.BeginningOfDay() - weekday := int(t.Weekday()) - if weekday == 0 { - weekday = 7 - } - d := time.Duration(-weekday+1) * 24 * time.Hour - return t.Truncate(time.Hour).Add(d) -} - -func (now *Now) Sunday() time.Time { - t := now.BeginningOfDay() - weekday := int(t.Weekday()) - if weekday == 0 { - return t - } else { - d := time.Duration(7-weekday) * 24 * time.Hour - return t.Truncate(time.Hour).Add(d) - } -} - -func (now *Now) EndOfSunday() time.Time { - return now.Sunday().Add(24*time.Hour - time.Nanosecond) -} - -func parseWithFormat(str string) (t time.Time, err error) { - for _, format := range TimeFormats { - t, err = time.Parse(format, str) - if err == nil { - return - } - } - err = errors.New("Can't parse string as time: " + str) - return -} - -func (now *Now) Parse(strs ...string) (t time.Time, err error) { - var setCurrentTime bool - parseTime := []int{} - currentTime := []int{now.Second(), now.Minute(), now.Hour(), now.Day(), int(now.Month()), now.Year()} - currentLocation := now.Location() - - for _, str := range strs { - onlyTime := regexp.MustCompile(`^\s*\d+(:\d+)*\s*$`).MatchString(str) // match 15:04:05, 15 - - t, err = parseWithFormat(str) - location := t.Location() - if location.String() == "UTC" { - location = currentLocation - } - - if err == nil { - parseTime = []int{t.Second(), t.Minute(), t.Hour(), t.Day(), int(t.Month()), t.Year()} - onlyTime = onlyTime && (parseTime[3] == 1) && (parseTime[4] == 1) - - for i, v := range parseTime { - // Don't reset hour, minute, second if it is a time only string - if onlyTime && i <= 2 { - continue - } - - // Fill up missed information with current time - if v == 0 { - if setCurrentTime { - parseTime[i] = currentTime[i] - } - } else { - setCurrentTime = true - } - - // Default day and month is 1, fill up it if missing it - if onlyTime { - if i == 3 || i == 4 { - parseTime[i] = currentTime[i] - continue - } - } - } - } - - if len(parseTime) > 0 { - t = time.Date(parseTime[5], time.Month(parseTime[4]), parseTime[3], parseTime[2], parseTime[1], parseTime[0], 0, location) - currentTime = []int{t.Second(), t.Minute(), t.Hour(), t.Day(), int(t.Month()), t.Year()} - } - } - return -} - -func (now *Now) MustParse(strs ...string) (t time.Time) { - t, err := now.Parse(strs...) - if err != nil { - panic(err) - } - return t -} - -func (now *Now) Between(time1, time2 string) bool { - restime := now.MustParse(time1) - restime2 := now.MustParse(time2) - return now.After(restime) && now.Before(restime2) -} -- cgit v1.3 From f4fe01543efcf33b86d22eb34736b54fbf2da3c3 Mon Sep 17 00:00:00 2001 From: Grant Ammons Date: Fri, 3 Mar 2017 18:40:42 -0500 Subject: Fix agenda bug Previously, running `todo agenda` was also listing todos with no due date. Now, it won't do that. --- todolist/date_filter.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/todolist/date_filter.go b/todolist/date_filter.go index 2bf51e2..0575e6a 100644 --- a/todolist/date_filter.go +++ b/todolist/date_filter.go @@ -17,7 +17,7 @@ func NewDateFilter(todos []*Todo) *DateFilter { } func (f *DateFilter) FilterDate(input string) []*Todo { - agendaRegex, _ := regexp.Compile(`agenda .*$`) + agendaRegex, _ := regexp.Compile(`agenda.*$`) if agendaRegex.MatchString(input) { return f.filterAgenda(now.BeginningOfDay()) } @@ -57,6 +57,9 @@ func (f *DateFilter) filterAgenda(pivot time.Time) []*Todo { var ret []*Todo for _, todo := range f.Todos { + if todo.Due == "" { + continue + } dueTime, _ := time.ParseInLocation("2006-01-02", todo.Due, f.Location) if dueTime.Before(pivot) || todo.Due == pivot.Format("2006-01-02") { ret = append(ret, todo) -- cgit v1.3