aboutsummaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
authorRaymaekers Luca <raymaekers.luca@gmail.com>2024-10-12 13:05:02 +0200
committerRaymaekers Luca <raymaekers.luca@gmail.com>2024-10-12 13:05:02 +0200
commitb0397503c8bdcc98216bab220b661466c74a63e9 (patch)
tree01e0fb2b1b80ff197d533a72708a00621f70e3ac /main.go
parent98dd9ae0629d58b16603d0188bd7e6f6f182e337 (diff)
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
Diffstat (limited to 'main.go')
-rw-r--r--main.go345
1 files changed, 0 insertions, 345 deletions
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
-// - [ ] <no arg>
-// - [ ] 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 <arg> 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 <command>
-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)
- }
-
-}