From b0397503c8bdcc98216bab220b661466c74a63e9 Mon Sep 17 00:00:00 2001 From: Raymaekers Luca Date: Sat, 12 Oct 2024 13:05:02 +0200 Subject: Create separate module for primitives - Added a converter tool to convert from an old version of gobdata to a new format - added ws sub directory for the command line tool --- main.go | 345 ---------------------------------------------------------------- 1 file changed, 345 deletions(-) delete mode 100644 main.go (limited to 'main.go') diff --git a/main.go b/main.go deleted file mode 100644 index bc6ac84..0000000 --- a/main.go +++ /dev/null @@ -1,345 +0,0 @@ -package main - -// Workstack or ws for short is a program that manages To-Do's in a stack-based fashion. It tries -// to guide your focus to your three most important tasks such that you do not get distracted by -// other tasks. -// Every task added starts as inactive "[ ]" and can be marked as done by changing the status to -// "[x]". -// When the programs exits Tasks are saved to a tasks.gob file, this will truncate (os.Create) the -// existing file. - -// TODO's -// - edit functionality -// - import: read multiple lines from stdin and import them as taks -// - parsing text as Tasks, maybe helper program? -// - clocking functionality with a 'task' command -// - testing: -// - [ ] add -// - [ ] done -// - [ ] undone -// - [ ] del -// - [ ] pc -// - [ ] -// - [ ] ls -// - [ ] list -// - [ ] tag -// - [ ] tagd -// - [ ] tagl - -import ( - "encoding/gob" - "errors" - "fmt" - "os" - "strconv" - "strings" - "time" -) - -type TaskDone struct { - Task Task - Date time.Time -} - -func (t TaskDone) String() string { - return fmt.Sprintf("(%s) %s", t.Date.Format(DateLayout), t.Task) -} - -type Task struct { - Text string - Tag string -} - -func (t Task) String() string { - if t.Tag != "" { - return fmt.Sprintf("%s {%s}", t.Text, t.Tag) - } else { - return fmt.Sprintf("%s", t.Text) - } -} - -var ( - // Stack of active tasks - Tags []string - // Active tasks - Tasks []Task - // Completed tasks - TasksDone []TaskDone - // Persistent storage for Tasks - Gobdata string = "tasks.gob" - DateLayout string = "15:04:05 02/01/2006" -) - -const ( - TASK_LIST_COUNT = 5 -) - -// Search for arg in Args and return the index at which it was found -// Returns -1 if it was not found -func ArgInArgs(args []string, arg string) int { - for i := 0; i < len(args); i++ { - if args[i] == arg { - return i - } - } - return -1 -} - -// Parse a number argument from os.Args where pos is the argument's position -// returns the int value for the string, if it fails the program will exit. -// def will be used as default value when there is no argument at the position. If you do not want -// to pass a default value, you can pass -1. -func ParseNArg(pos, def, max int) int { - if max == 0 { - fmt.Printf("Number out of range: %d\n", 0) - os.Exit(1) - } - - if len(os.Args) == pos { - if def == -1 { - fmt.Println("Argument required: N") - os.Exit(1) - } - return def - } - - n, err := strconv.Atoi(os.Args[pos]) - if errors.Is(err, strconv.ErrSyntax) { - fmt.Printf("'%s' is not a number.\n", os.Args[pos]) - os.Exit(1) - } else if err != nil { - panic(err) - } - - if n > max { - fmt.Printf("Number out of range: %d\n", n) - os.Exit(1) - } - return n -} - -func main() { - // create tasks.gob file - var dec *gob.Decoder - var f *os.File - var err error - - // Open/Create gob data file if not exist - { - p := os.Getenv("HOME") - if p == "" { - panic("HOME var not set.") - } - Gobdata = p + "/sync/share/" + Gobdata - - f, err = os.Open(Gobdata) - if errors.Is(err, os.ErrNotExist) { - // Do nothing - } else if err != nil { - panic(err) - } else { - dec = gob.NewDecoder(f) - err = dec.Decode(&Tasks) - if err != nil { - panic(err) - } - err = dec.Decode(&TasksDone) - if err != nil { - panic(err) - } - err = dec.Decode(&Tags) - if err != nil { - panic(err) - } - } - } - - // When no arguments are provided display the first task. - if len(os.Args) == 1 { - if len(Tasks) == 0 { - fmt.Println("No tasks.") - return - } - fmt.Printf("1. %s\n", Tasks[0]) - os.Exit(0) - } - - switch os.Args[1] { - // Add a new task - case "task": - var tagName, taskText string - var i, offset int - // offset of 2 because we are at the second arg - offset = 2 - i = ArgInArgs(os.Args[offset:], "-t") - - // tag argument was provided - if i != -1 { - if offset+i+1 >= len(os.Args) { - fmt.Println("-t requires an argument.") - os.Exit(1) - } - tagName = os.Args[offset+i+1] - if tagName == "" { - fmt.Println("-t requires an argument.") - os.Exit(1) - } - // this would mean that -t are the first and last two arguments - if len(os.Args) == offset+2 { - fmt.Println("Task text is required.") - os.Exit(1) - } - if i == 0 { - fmt.Println(1) - // tag is at the start - taskText = strings.Join(os.Args[offset+i+2:], " ") - } else if i+4 == len(os.Args) { - // tag is at the end - taskText = strings.Join(os.Args[offset:i+2], " ") - } else { - // tag is in the middle - taskText = strings.Join(append(os.Args[offset:i+2], os.Args[offset+i+2:]...), " ") - } - } else { - taskText = strings.Join(os.Args[offset:], " ") - } - - // taskText can be provided as "" which is an argument and will pass previous validation - // tests - if taskText == "" { - fmt.Println("Task text is required.") - os.Exit(1) - } - - if tagName == "" { - Tasks = append(Tasks, Task{Text: taskText}) - break - } - - // Validate tag - found := false - for _, v := range Tags { - if tagName == v { - found = true - break - } - } - if !found { - fmt.Printf("No tag '%s' found.\n", tagName) - os.Exit(1) - } - Tasks = append(Tasks, Task{Text: taskText, Tag: tagName}) - - // Delete an active task - case "del": - n := ParseNArg(2, 1, len(Tasks)) - Tasks = append(Tasks[:n-1], Tasks[n:]...) - - // Mark an active task as done - case "done": - n := ParseNArg(2, 1, len(Tasks)) - TasksDone = append(TasksDone, TaskDone{ - Task: Tasks[n-1], - Date: time.Now(), - }) - Tasks = append(Tasks[:n-1], Tasks[n:]...) - - // Undo a done task - case "undone": - n := ParseNArg(2, 1, len(TasksDone)) - Tasks = append(Tasks, TasksDone[n-1].Task) - TasksDone = append(TasksDone[:n-1], TasksDone[n:]...) - - // Procrastinate an active task - case "pc": - n := ParseNArg(2, 1, len(Tasks)) - if n == 1 { - Tasks = append(Tasks[n:], Tasks[n]) - break - } - // save, delete and append task - t := Tasks[n-1] - Tasks = append(Tasks[:n-1], Tasks[n:]...) - Tasks = append(Tasks, t) - - // Short list of active tasks - case "ls": - if len(Tasks) == 0 { - fmt.Println("No tasks.") - break - } - for i := 0; i < len(Tasks) && i < TASK_LIST_COUNT; i++ { - fmt.Printf("%d. %s\n", i+1, Tasks[i]) - } - - // List all active and done tasks - case "list": - if len(Tasks) > 0 { - fmt.Println("Active:") - for i, t := range Tasks { - fmt.Printf("% 2d. %s\n", i+1, t) - } - } - if len(TasksDone) > 0 { - fmt.Println("Done:") - for i, t := range TasksDone { - fmt.Printf("% 2d. %s\n", i+1, t) - } - } - - // create a new tag - case "tag": - tagName := strings.Join(os.Args[2:], " ") - for i := 0; i < len(Tags); i++ { - if tagName == Tags[i] { - fmt.Printf("Tag '%s' already exists.\n", tagName) - os.Exit(1) - } - } - Tags = append(Tags, tagName) - - // delete a tag - case "tagd": - n := ParseNArg(2, 1, len(Tags)) - Tags = append(Tags[:n-1], Tags[n:]...) - - // list tags - case "tagl": - for i := 0; i < len(Tags); i++ { - fmt.Printf("%2d. %s\n", i+1, Tags[i]) - } - default: - fmt.Println(`usage: ws -COMMANDS - task Add a new task - done Mark an active task as done - undone Undo a done task - del Delete an active task - pc Procrastinate an active task - ls Short list of active tasks - list List all active and done tasks - tag Add a new tag - tagd Delete a tag - tagl List tags`) - } - - // Save data to gobdata - f, err = os.Create(Gobdata) - if err != nil { - panic(err) - } - enc := gob.NewEncoder(f) - err = enc.Encode(Tasks) - if err != nil { - panic(err) - } - err = enc.Encode(TasksDone) - if err != nil { - panic(err) - } - err = enc.Encode(Tags) - if err != nil { - panic(err) - } - -} -- cgit v1.2.3