savestate.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package itashi
  2. import (
  3. "bytes"
  4. "fmt"
  5. "log"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "text/template"
  10. "time"
  11. )
  12. const SHELF_LINE_DELIM = "\n---- ---- ---- ----\n"
  13. const SHELF_COL_DELIM = " "
  14. const TIME_FORMAT = "2006-01-02T15:04:05 -07:00:00"
  15. const FS_SAVE_LOCATION = "./todo.ta"
  16. const SHELF_TEMPLATE = "{{.Id}} {{.Title}} {{.Desc}} {{.Due}} {{.Done}} {{.Priority}}"
  17. type Task struct {
  18. Id int
  19. Title string
  20. Desc string
  21. Due time.Time
  22. Done bool
  23. Priority int
  24. }
  25. type TaskShelf interface {
  26. // Modify the due date of an existing task
  27. ModifyDue(id int, due time.Time)
  28. // Modify the description field of an existing task
  29. ModifyDesc(id int, desc string)
  30. // Modify the priority of an existing task
  31. ModifyPriority(id int, pri int)
  32. // modify the title of an existing task
  33. ModifyTitle(id int, title string)
  34. // delete an existing task from the shelf
  35. DeleteTask(id int)
  36. // Mark a task as complete
  37. MarkDone(id int)
  38. // hopefully you dont need to call this! ;)
  39. ResetDone(id int)
  40. // Add a task to the shelf
  41. AddTask(t Task)
  42. // Retrieve all tasks in the shelf
  43. GetAll() []Task
  44. }
  45. /*
  46. Retrieve all the tasks from the designated TaskShelf
  47. */
  48. func GetTaskList(taskio TaskShelf) []Task {
  49. return taskio.GetAll()
  50. }
  51. /*
  52. Grab all of the names of the tasks from the TaskShelf
  53. :param t: a list of Task structs
  54. :returns: A list of the task names
  55. */
  56. func GetTaskNames(t []Task) []string {
  57. var taskn []string
  58. for i := range t {
  59. taskn = append(taskn, t[i].Title)
  60. }
  61. return taskn
  62. }
  63. type FilesystemShelf struct {
  64. SaveLocation string
  65. Template *template.Template
  66. Tasks []Task
  67. }
  68. /*
  69. Create a new filesystem shelf struct to reflect the filesystem shelf
  70. :param save: the save location to store the shelf in
  71. :returns: a pointer to a FilesystemShelf struct
  72. */
  73. func NewFilesystemShelf(save string) *FilesystemShelf {
  74. tmpl, err := template.New("task").Parse(SHELF_TEMPLATE)
  75. if err != nil {
  76. log.Fatal("Could not parse the shelf template! ", err)
  77. }
  78. return &FilesystemShelf{
  79. SaveLocation: save,
  80. Template: tmpl,
  81. Tasks: []Task{},
  82. }
  83. }
  84. // Retrieve all the tasks from the filesystem shelf
  85. func (f *FilesystemShelf) GetAll() []Task {
  86. b, err := os.ReadFile(f.SaveLocation)
  87. if err != nil {
  88. log.Fatal(err)
  89. }
  90. return parseFilesystemShelf(b)
  91. }
  92. /*
  93. Add a task to the filesystem shelf
  94. :param t: the Task struct to add
  95. */
  96. func (f *FilesystemShelf) AddTask(t Task) {
  97. f.Tasks = append(f.Tasks, t)
  98. err := os.WriteFile(f.SaveLocation, marshalTaskToShelf(f.Tasks, f.Template), os.ModePerm)
  99. if err != nil {
  100. log.Fatal("Need to fix later, error writing to fs ", err)
  101. }
  102. }
  103. // Boiler plate so i can implement later
  104. func (f *FilesystemShelf) ModifyDue(id int, due time.Time) {}
  105. func (f *FilesystemShelf) ModifyDesc(id int, desc string) {}
  106. func (f *FilesystemShelf) ModifyPriority(id int, pri int) {}
  107. func (f *FilesystemShelf) ModifyTitle(id int, title string) {}
  108. func (f *FilesystemShelf) DeleteTask(id int) {}
  109. func (f *FilesystemShelf) MarkDone(id int) {}
  110. func (f *FilesystemShelf) ResetDone(id int) {}
  111. // private function for parsing the byte stream from the filesystem
  112. func parseFilesystemShelf(data []byte) []Task {
  113. var filestring string
  114. filestring = string(data)
  115. items := strings.Split(filestring, SHELF_LINE_DELIM)
  116. var shelf []Task
  117. for i := range items {
  118. sect := strings.Split(items[i], SHELF_COL_DELIM)
  119. if len(sect) < 6 {
  120. fmt.Printf("Length of item is not to spec.... length: %v. Item: %v\n", len(sect), sect)
  121. continue
  122. }
  123. var id int
  124. var due time.Time
  125. var done bool
  126. var pri int
  127. var err error
  128. id, err = strconv.Atoi(sect[0])
  129. due, err = time.Parse(TIME_FORMAT, sect[3])
  130. done, err = strconv.ParseBool(sect[4])
  131. pri, err = strconv.Atoi(sect[5])
  132. if err != nil {
  133. log.Fatal("Couldnt parse from filesystem shelf", err)
  134. }
  135. shelf = append(shelf, Task{
  136. Id: id,
  137. Title: sect[1],
  138. Desc: sect[2],
  139. Due: due,
  140. Done: done,
  141. Priority: pri,
  142. })
  143. }
  144. return shelf
  145. }
  146. /*
  147. Helper function to marshal the tasks to the custom format
  148. :param tasks: an array of Task structs
  149. :returns: a byte array
  150. */
  151. func marshalTaskToShelf(tasks []Task, templ *template.Template) []byte {
  152. var bw bytes.Buffer
  153. for i := range tasks {
  154. err := templ.Execute(&bw, tasks[i])
  155. if err != nil {
  156. log.Fatal("Error parsing data into template: ", err)
  157. }
  158. // dynamically allocating, no need for the read delim
  159. _, err = bw.Write([]byte(SHELF_LINE_DELIM))
  160. if err != nil {
  161. log.Fatal("Error parsing data into template: ", err)
  162. }
  163. }
  164. return bw.Bytes()
  165. }