-
Notifications
You must be signed in to change notification settings - Fork 8
/
todotxt.go
204 lines (174 loc) · 5.59 KB
/
todotxt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package todotxt
import (
"bufio"
"errors"
"io/ioutil"
"os"
"strings"
ys "github.com/1set/gut/ystring"
)
// TaskList represents a list of todo.txt task entries.
// It is usually loaded from a whole todo.txt file.
type TaskList []Task
// IgnoreComments can be set to 'false', in order to revert to a more standard todo.txt behaviour.
// The todo.txt format does not define comments.
var (
// IgnoreComments is used to switch ignoring of comments (lines starting with "#").
// If this is set to 'false', then lines starting with "#" will be parsed as tasks.
IgnoreComments = true
// RemoveCompletedPriority is used to switch discarding priority on task completion like many todo.txt clients do.
// If this is set to 'false', then the priority of completed task will be kept as it is.
RemoveCompletedPriority = true
)
// NewTaskList creates a new empty TaskList.
func NewTaskList() TaskList {
return TaskList{}
}
// String returns a complete list of tasks in todo.txt format.
func (tasklist TaskList) String() string {
var sb strings.Builder
for _, task := range tasklist {
sb.WriteString(task.String())
sb.WriteString(ys.NewLine)
}
return sb.String()
}
// AddTask appends a Task to the current TaskList and takes care to set the Task.ID correctly, modifying the Task by the given pointer!
func (tasklist *TaskList) AddTask(task *Task) {
task.ID = 0
for _, t := range *tasklist {
if t.ID > task.ID {
task.ID = t.ID
}
}
task.ID++
*tasklist = append(*tasklist, *task)
}
// GetTask returns a Task by given task 'id' from the TaskList. The returned Task pointer can be used to update the Task inside the TaskList.
// Returns an error if Task could not be found.
func (tasklist *TaskList) GetTask(id int) (*Task, error) {
for i := range *tasklist {
if ([]Task(*tasklist))[i].ID == id {
return &([]Task(*tasklist))[i], nil
}
}
return nil, errors.New("task not found")
}
// RemoveTaskByID removes any Task with given Task 'id' from the TaskList.
// Returns an error if no Task was removed.
func (tasklist *TaskList) RemoveTaskByID(id int) error {
var newList TaskList
found := false
for _, t := range *tasklist {
if t.ID != id {
newList = append(newList, t)
} else {
found = true
}
}
if !found {
return errors.New("task not found")
}
*tasklist = newList
return nil
}
// RemoveTask removes any Task from the TaskList with the same String representation as the given Task.
// Returns an error if no Task was removed.
func (tasklist *TaskList) RemoveTask(task Task) error {
var newList TaskList
found := false
for _, t := range *tasklist {
if t.String() != task.String() {
newList = append(newList, t)
} else {
found = true
}
}
if !found {
return errors.New("task not found")
}
*tasklist = newList
return nil
}
// LoadFromFile loads a TaskList from *os.File.
//
// Using *os.File instead of a filename allows to also use os.Stdin.
//
// Note: This will clear the current TaskList and overwrite it's contents with whatever is in *os.File.
func (tasklist *TaskList) LoadFromFile(file *os.File) error {
*tasklist = []Task{} // Empty task list
taskID := 1
scanner := bufio.NewScanner(file)
for scanner.Scan() {
text := strings.Trim(scanner.Text(), whitespaces) // Read line
// Ignore blank or comment lines
if isEmpty(text) || (IgnoreComments && strings.HasPrefix(text, "#")) {
continue
}
task, err := ParseTask(text)
if err != nil {
return err
}
task.ID = taskID
*tasklist = append(*tasklist, *task)
taskID++
}
return scanner.Err()
}
// WriteToFile writes a TaskList to *os.File.
//
// Using *os.File instead of a filename allows to also use os.Stdout.
//
// Note: Comments from original file will be omitted and not written to target *os.File, if IgnoreComments is set to 'true'.
func (tasklist *TaskList) WriteToFile(file *os.File) error {
writer := bufio.NewWriter(file)
if _, err := writer.WriteString(tasklist.String()); err != nil {
return err
}
return writer.Flush()
}
// LoadFromPath loads a TaskList from a file (most likely called "todo.txt").
//
// Note: This will clear the current TaskList and overwrite it's contents with whatever is in the file.
func (tasklist *TaskList) LoadFromPath(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
return tasklist.LoadFromFile(file)
}
// WriteToPath writes a TaskList to the specified file (most likely called "todo.txt").
func (tasklist *TaskList) WriteToPath(filename string) error {
return ioutil.WriteFile(filename, []byte(tasklist.String()), 0640)
}
// LoadFromFile loads and returns a TaskList from *os.File.
//
// Using *os.File instead of a filename allows to also use os.Stdin.
func LoadFromFile(file *os.File) (TaskList, error) {
tasklist := TaskList{}
if err := tasklist.LoadFromFile(file); err != nil {
return nil, err
}
return tasklist, nil
}
// WriteToFile writes a TaskList to *os.File.
//
// Using *os.File instead of a filename allows to also use os.Stdout.
//
// Note: Comments from original file will be omitted and not written to target *os.File, if IgnoreComments is set to 'true'.
func WriteToFile(tasklist *TaskList, file *os.File) error {
return tasklist.WriteToFile(file)
}
// LoadFromPath loads and returns a TaskList from a file (most likely called "todo.txt").
func LoadFromPath(filename string) (TaskList, error) {
tasklist := TaskList{}
if err := tasklist.LoadFromPath(filename); err != nil {
return nil, err
}
return tasklist, nil
}
// WriteToPath writes a TaskList to the specified file (most likely called "todo.txt").
func WriteToPath(tasklist *TaskList, filename string) error {
return tasklist.WriteToPath(filename)
}