savestate.go 4.9 KB

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