25
25
def __init__(self, taskList, categoryList):
26
26
self.__taskList = taskList
27
27
self.__tasksBySubject = self.__createSubjectCache(taskList)
28
self.__tasksById = self.__createIdCache(taskList)
28
29
self.__categoryList = categoryList
29
30
self.__categoriesBySubject = self.__createSubjectCache(categoryList)
31
33
def read(self, filename):
32
34
metaName = filename + '-meta'
35
37
todoTxtRE = self.compileTodoTxtRE()
36
38
keyValueRE = self.compileKeyValueRE()
37
39
with codecs.open(metaName, 'r', 'utf-8') as fp:
40
match = re.match(r'VERSION: (\d+)', fp.readline().strip())
42
self.__version = int(match.group(1))
39
47
line = line.strip()
41
subjects, priority, plannedStartDateTime, completionDateTime, dueDateTime, categories = \
49
taskId, subjects, priority, plannedStartDateTime, completionDateTime, dueDateTime, categories = \
42
50
self.__processLine(line, todoTxtRE, keyValueRE, date.Now, None)
45
metaLines['->'.join(subjects)] = line
53
metaLines['->'.join(subjects) if self.__version == 0 else taskId] = line
46
54
with codecs.open(filename, 'r', 'utf-8') as fp:
47
55
self.readFile(fp, metaLines=metaLines)
60
68
# defined by the todo.txt format at
61
69
# https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format
62
70
dueDateTime = date.DateTime()
63
72
for key, value in re.findall(keyValueRE, line):
65
74
dueDateTime = self.dateTime(value)
66
77
line = re.sub(keyValueRE, '', line) # Remove all key:value pairs
68
79
# Now, process the "official" todo.txt format using a RE that should
77
88
recursiveSubject = match.group('subject')
79
90
subjects = recursiveSubject.split('->')
80
return subjects, priority, plannedStartDateTime, completionDateTime, dueDateTime, categories
91
return taskId, subjects, priority, plannedStartDateTime, completionDateTime, dueDateTime, categories
82
93
def processLine(self, line, todoTxtRE, keyValueRE, now, event, metaLines):
83
subjects, priority, plannedStartDateTime, completionDateTime, dueDateTime, categories = \
94
taskId, subjects, priority, plannedStartDateTime, completionDateTime, dueDateTime, categories = \
84
95
self.__processLine(line, todoTxtRE, keyValueRE, now, event)
86
if metaLines and metaLines.get('->'.join(subjects), None) == line:
97
if (self.__version == 0 and metaLines and metaLines.get('->'.join(subjects), None) == line) or \
98
(self.__version == 1 and metaLines and taskId and metaLines.get(taskId, None) == line):
87
99
# Not modified. Don't read it or we'll overwrite local changes
88
100
# in case we're importing just before saving...
92
for subject in subjects:
93
newTask = self.findOrCreateTask(subject.strip(), newTask, event)
103
if taskId is not None and taskId not in self.__tasksById:
104
return # Deleted on desktop, changed on device. Keep deleted.
106
if self.__version == 0:
108
for subject in subjects:
109
newTask = self.findOrCreateTask(subject.strip(), newTask, event)
111
newTask = None if taskId is None else self.__tasksById.get(taskId, None)
113
newTask = task.Task(subject=subjects[-1])
114
self.__taskList.append(newTask)
116
newTask.setSubject(subjects[-1])
95
118
newTask.setPriority(priority)
96
119
newTask.setPlannedStartDateTime(plannedStartDateTime)
97
120
newTask.setCompletionDateTime(completionDateTime)