From 08deecf1954f6cf748812057ba5cdd9a0425bfc9 Mon Sep 17 00:00:00 2001 From: Grant Ammons Date: Tue, 3 Oct 2017 07:20:02 -0400 Subject: Refactor the formatter to an interface and rename it This change refactors the formatter to be an interface called Printer. `NewApp` will use the functionality of `ScreenPrinter`, which is what I refactored the old `Formatter` class into. There is a new class the implements the `Printer` interface called `MemoryPrinter`, which will simply store the `groups` as they were passed to it. This will allow tests in `app_test.go` to become much more powerful, since `App` no longer needs to be tightly coupled to printing to the screen. --- todolist/screen_printer.go | 131 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 todolist/screen_printer.go (limited to 'todolist/screen_printer.go') diff --git a/todolist/screen_printer.go b/todolist/screen_printer.go new file mode 100644 index 0000000..eab0c39 --- /dev/null +++ b/todolist/screen_printer.go @@ -0,0 +1,131 @@ +package todolist + +import ( + "fmt" + "os" + "regexp" + "sort" + "strconv" + "strings" + "text/tabwriter" + "time" + + "github.com/fatih/color" +) + +type ScreenPrinter struct { + Writer *tabwriter.Writer +} + +func NewScreenPrinter() *ScreenPrinter { + w := new(tabwriter.Writer) + w.Init(os.Stdout, 0, 8, 0, '\t', 0) + formatter := &ScreenPrinter{Writer: w} + return formatter +} + +func (f *ScreenPrinter) Print(groupedTodos *GroupedTodos, printNotes bool) { + cyan := color.New(color.FgCyan).SprintFunc() + + var keys []string + for key := range groupedTodos.Groups { + keys = append(keys, key) + } + sort.Strings(keys) + + for _, key := range keys { + fmt.Fprintf(f.Writer, "\n %s\n", cyan(key)) + for _, todo := range 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() +} + +func (f *ScreenPrinter) printTodo(todo *Todo) { + 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.SprintFunc()(strconv.Itoa(todo.Id)), + f.formatCompleted(todo.Completed), + f.formatDue(todo.Due, todo.IsPriority), + f.formatSubject(todo.Subject, todo.IsPriority)) +} + +func (f *ScreenPrinter) 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.SprintFunc()(" ") + } + dueTime, err := time.Parse("2006-01-02", due) + + if err != nil { + fmt.Println(err) + fmt.Println("This may due to the corruption of .todos.json file.") + os.Exit(-1) + } + + if isToday(dueTime) { + return blue.SprintFunc()("today") + } else if isTomorrow(dueTime) { + return blue.SprintFunc()("tomorrow") + } else if isPastDue(dueTime) { + return red.SprintFunc()(dueTime.Format("Mon Jan 2")) + } else { + return blue.SprintFunc()(dueTime.Format("Mon Jan 2")) + } +} + +func (f *ScreenPrinter) 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_]+`) + contextRegex, _ := regexp.Compile(`\@[\p{L}\d_]+`) + + coloredWords := []string{} + + for _, word := range splitted { + if projectRegex.MatchString(word) { + coloredWords = append(coloredWords, magenta.SprintFunc()(word)) + } else if contextRegex.MatchString(word) { + coloredWords = append(coloredWords, red.SprintFunc()(word)) + } else { + coloredWords = append(coloredWords, white.SprintFunc()(word)) + } + } + return strings.Join(coloredWords, " ") + +} + +func (f *ScreenPrinter) formatCompleted(completed bool) string { + if completed { + return "[x]" + } else { + return "[ ]" + } +} -- cgit v1.3