savestate.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. Tasks []Task
  66. }
  67. /*
  68. Create a new filesystem shelf struct to reflect the filesystem shelf
  69. :param save: the save location to store the shelf in
  70. :returns: a pointer to a FilesystemShelf struct
  71. */
  72. func NewFilesystemShelf(save string) *FilesystemShelf {
  73. tmpl, err := template.New("task").Parse(SHELF_TEMPLATE)
  74. if err != nil {
  75. log.Fatal("Could not parse the shelf template! ", err)
  76. }
  77. shelf := &FilesystemShelf{
  78. SaveLocation: save,
  79. Template: tmpl,
  80. Tasks: []Task{},
  81. }
  82. shelf.Tasks = shelf.GetAll()
  83. return shelf
  84. }
  85. // Retrieve all the tasks from the filesystem shelf
  86. func (f *FilesystemShelf) GetAll() []Task {
  87. b, err := os.ReadFile(f.SaveLocation)
  88. if err != nil {
  89. log.Fatal(err)
  90. }
  91. return parseFilesystemShelf(b)
  92. }
  93. /*
  94. Add a task to the filesystem shelf
  95. :param t: the Task struct to add
  96. */
  97. func (f *FilesystemShelf) AddTask(t Task) {
  98. f.Tasks = append(f.Tasks, t)
  99. err := os.WriteFile(f.SaveLocation, marshalTaskToShelf(f.Tasks, f.Template), os.ModePerm)
  100. if err != nil {
  101. log.Fatal("Need to fix later, error writing to fs ", err)
  102. }
  103. }
  104. // Boiler plate so i can implement later
  105. func (f *FilesystemShelf) ModifyDue(id int, due time.Time) {}
  106. func (f *FilesystemShelf) ModifyDesc(id int, desc string) {}
  107. func (f *FilesystemShelf) ModifyPriority(id int, pri int) {}
  108. func (f *FilesystemShelf) ModifyTitle(id int, title string) {}
  109. func (f *FilesystemShelf) DeleteTask(id int) {}
  110. func (f *FilesystemShelf) MarkDone(id int) {}
  111. func (f *FilesystemShelf) ResetDone(id int) {}
  112. // private function for parsing the byte stream from the filesystem
  113. func parseFilesystemShelf(data []byte) []Task {
  114. var filestring string
  115. filestring = string(data)
  116. items := strings.Split(filestring, SHELF_LINE_DELIM)
  117. var shelf []Task
  118. for i := range items {
  119. sect := strings.Split(items[i], SHELF_COL_DELIM)
  120. if len(sect) < 6 {
  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. }