123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- package itashi
- import (
- "bytes"
- "log"
- "os"
- "strconv"
- "strings"
- "text/template"
- "time"
- tea "github.com/charmbracelet/bubbletea"
- )
- const SHELF_LINE_DELIM = "\n---- ---- ---- ----\n"
- const SHELF_COL_DELIM = " "
- const TIME_FORMAT = "2006-01-02T15:04:05 -07:00:00"
- const FS_SAVE_LOCATION = "./todo.ta"
- const SHELF_TEMPLATE = "{{.Id}} {{.Title}} {{.Desc}} {{.Due}} {{.Done}} {{.Priority}}"
- type Task struct {
- Id int
- Title string
- Desc string
- Due time.Time
- Done bool
- Priority int
- }
- // lets make Task implement the tea.Model interface
- func (t Task) Init() tea.Cmd {
- return nil
- }
- func (t Task) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- return t, nil
- }
- func (t Task) View() string {
- return ""
- }
- type TaskShelf interface {
- // Modify the due date of an existing task
- ModifyDue(id int, due time.Time)
- // Modify the description field of an existing task
- ModifyDesc(id int, desc string)
- // Modify the priority of an existing task
- ModifyPriority(id int, pri int)
- // modify the title of an existing task
- ModifyTitle(id int, title string)
- // delete an existing task from the shelf
- DeleteTask(id int)
- // Mark a task as complete
- MarkDone(id int)
- // hopefully you dont need to call this! ;)
- ResetDone(id int)
- // Add a task to the shelf
- AddTask(t Task)
- // Retrieve all tasks in the shelf
- GetAll() []Task
- // Render a task to a task template
- RenderTask(task Task) string
- }
- /*
- Retrieve all the tasks from the designated TaskShelf
- */
- func GetTaskList(taskio TaskShelf) []Task {
- return taskio.GetAll()
- }
- /*
- Grab all of the names of the tasks from the TaskShelf
- :param t: a list of Task structs
- :returns: A list of the task names
- */
- func GetTaskNames(t []Task) []string {
- var taskn []string
- for i := range t {
- taskn = append(taskn, t[i].Title)
- }
- return taskn
- }
- type FilesystemShelf struct {
- SaveLocation string
- Template *template.Template
- TaskTempl *template.Template
- Tasks []Task
- }
- func (t *FilesystemShelf) RenderTask(task Task) string {
- var bw bytes.Buffer
- err := t.TaskTempl.Execute(&bw, task)
- if err != nil {
- log.Fatal("Had a problem rendering this task.", task, err)
- }
- return bw.String()
- }
- /*
- Create a new filesystem shelf struct to reflect the filesystem shelf
- :param save: the save location to store the shelf in
- :returns: a pointer to a FilesystemShelf struct
- */
- func NewFilesystemShelf(save string) *FilesystemShelf {
- tmpl, err := template.New("task").Parse(SHELF_TEMPLATE)
- if err != nil {
- log.Fatal("Could not parse the shelf template! ", err)
- }
- tasktmpl, err := template.New("task").Parse(TASK_ITEM)
- if err != nil {
- log.Fatal("Couldnt parse task template. ", err)
- }
- shelf := &FilesystemShelf{
- SaveLocation: save,
- Template: tmpl,
- TaskTempl: tasktmpl,
- Tasks: []Task{},
- }
- shelf.Tasks = shelf.GetAll()
- return shelf
- }
- // Retrieve all the tasks from the filesystem shelf
- func (f *FilesystemShelf) GetAll() []Task {
- b, err := os.ReadFile(f.SaveLocation)
- if err != nil {
- log.Fatal(err)
- }
- return parseFilesystemShelf(b)
- }
- /*
- Add a task to the filesystem shelf
- :param t: the Task struct to add
- */
- func (f *FilesystemShelf) AddTask(t Task) {
- f.Tasks = append(f.Tasks, t)
- err := os.WriteFile(f.SaveLocation, marshalTaskToShelf(f.Tasks, f.Template), os.ModePerm)
- if err != nil {
- log.Fatal("Need to fix later, error writing to fs ", err)
- }
- }
- // Boiler plate so i can implement later
- func (f *FilesystemShelf) ModifyDue(id int, due time.Time) {}
- func (f *FilesystemShelf) ModifyDesc(id int, desc string) {}
- func (f *FilesystemShelf) ModifyPriority(id int, pri int) {}
- func (f *FilesystemShelf) ModifyTitle(id int, title string) {}
- func (f *FilesystemShelf) DeleteTask(id int) {}
- func (f *FilesystemShelf) MarkDone(id int) {}
- func (f *FilesystemShelf) ResetDone(id int) {}
- // private function for parsing the byte stream from the filesystem
- func parseFilesystemShelf(data []byte) []Task {
- var filestring string
- filestring = string(data)
- items := strings.Split(filestring, SHELF_LINE_DELIM)
- var shelf []Task
- for i := range items {
- sect := strings.Split(items[i], SHELF_COL_DELIM)
- if len(sect) < 6 {
- continue
- }
- var id int
- var due time.Time
- var done bool
- var pri int
- var err error
- id, err = strconv.Atoi(sect[0])
- due, err = time.Parse(TIME_FORMAT, sect[3])
- done, err = strconv.ParseBool(sect[4])
- pri, err = strconv.Atoi(sect[5])
- if err != nil {
- log.Fatal("Couldnt parse from filesystem shelf", err)
- }
- shelf = append(shelf, Task{
- Id: id,
- Title: sect[1],
- Desc: sect[2],
- Due: due,
- Done: done,
- Priority: pri,
- })
- }
- return shelf
- }
- /*
- Helper function to marshal the tasks to the custom format
- :param tasks: an array of Task structs
- :returns: a byte array
- */
- func marshalTaskToShelf(tasks []Task, templ *template.Template) []byte {
- var bw bytes.Buffer
- for i := range tasks {
- err := templ.Execute(&bw, tasks[i])
- if err != nil {
- log.Fatal("Error parsing data into template: ", err)
- }
- // dynamically allocating, no need for the read delim
- _, err = bw.Write([]byte(SHELF_LINE_DELIM))
- if err != nil {
- log.Fatal("Error parsing data into template: ", err)
- }
- }
- return bw.Bytes()
- }
|