Browse files

Initial commit of v2

  • Loading branch information...
1 parent 8b5a0f0 commit daf7ee4170db20a045c393aecc1768c94331dc26 @bevesce committed Feb 18, 2013
View
67 README.md
@@ -1,63 +1,10 @@
-# TodoFlow
+# Work in progress...
-[Alfred][] 2 (beta) workflow for interacting with plain text todo lists with [TaskPaper][] syntax.
+Upcoming major changes:
+* much more than alfred workflow
+* more complex searching syntax
+* converting lists to colored text, html, markdown (css included)
+* more editing options
+* shift of paradigm - work with one list, at least for now
-**[Download][]**
-
-## Basic usage
-
-
-### Keyword: *t*
-
-Set path to your master todo list in config.py (one_filepath). When you type **t** keyword Alfred will display all task from that list.
-
-![All tasks][basic]
-
-Typing query filters tasks. You can use it to show only tasks with given tag.
-
-![Querying tasks][query]
-
-It works with regular expressions too! (I'm not sure if it useful in any way).
-
-![Querying tasks with regexp][regexp]
-
-Pressing *return* tags task as done.
-Adding date value after tag can be configured.
-Pressing *cmd+return* opens file containing task.
-
-You can also add task to that list. There are 3 options: prepend, append and insert into Inbox project. That can be configured inside workflow in third script from the top.
-
-## Advanced usage
-
-Work with multiple files.
-
-### Keyword: *tt*
-
-Lists tasks from multiple lists.
-Paths of lists are stored in active_lists (path to that file can be configured).
-Paths to lists can be added to active_lists manually or by file action *Activate list aa* and removed by *Deactivate list dd*.
-Max number of tasks from one list can be configured.
-
-*Update 18.01.13:*
-
-More explonation:
-It's useful if you want to display limited number of tasks for multiple lists. For example I use it to list tasks for projects that I'm working at the moment that are kept in separate files.
-Workflow need to know paths to those lists, so it's stores them in file placed at *active_lists_path*. That path can be just 'active_lists' to store it in workflow folder. When you run *Activate list aa* file action path to that file is stored in file at *active_lists_path*.
-
-### Keyword: *ttt*
-
-Lists all tasks from list given be query - query is path to file with that list. Constant prefix and sufix of path can be configured.
-For example if you allways use one extension for lists you can
-set it as constant sufix so you won't need to type it. The same works with prefixes - useful for home directory or when you store all lists in one folder.
-
-## Configuration
-
-All configs (except one) are stored in config.py and are commented there. If you use only one file you probably should remove *tt* and *ttt* tags from workflow to not polute searches.
-
-[Alfred]: http://www.alfredapp.com
-[TaskPaper]: http://www.hogbaysoftware.com/products/taskpaper
-[basic]: http://bvsc.nazwa.pl/img/TodoFlow/basic.png
-[query]: http://bvsc.nazwa.pl/img/TodoFlow/query.png
-[regexp]: http://bvsc.nazwa.pl/img/TodoFlow/regexp.png
-[Download]: https://github.com/bevesce/TodoFlow/raw/master/TodoFlow.alfredworkflow
View
4 alfredlist.py
@@ -2,8 +2,8 @@
class AlfredItemsXML(object):
- def __init__(self):
- self.items = []
+ def __init__(self, items=None):
+ self.items = items or []
self.pattern = '<item arg="{0}" uid="nouid" valid="{3}"><title>{1}</title><subtitle>{2}</subtitle><icon>iconT.png</icon></item>'
def append(self, arg, title, subtitle, valid='yes'):
View
22 colors.py
@@ -0,0 +1,22 @@
+"""defines colors used in output"""
+defc = '\033[0m'
+
+red = '\033[1;31m'
+green = '\033[1;32m'
+gray = '\033[1;30m'
+blue = '\033[1;34m'
+
+yellow = '\033[1;33m'
+magenta = '\033[1;35m'
+cyan = '\033[1;36m'
+white = '\033[1;37m'
+crimson = '\033[1;38m'
+
+high_red = '\033[1;41m'
+high_green = '\033[1;42m'
+high_brown = '\033[1;43m'
+high_blue = '\033[1;44m'
+high_magenta = '\033[1;45m'
+high_cyan = '\033[1;46m'
+high_gray = '\033[1;47m'
+high_crimson = '\033[1;48m'
View
4 daily_todo.py
@@ -0,0 +1,4 @@
+import subprocess
+from topy import update_onhold, log_to_day_one, from_file
+update_onhold()
+log_to_day_one(from_file('/Users/bvsc/Dropbox/TODO/Projects.todo'))
View
976 filterpredicate.py
@@ -0,0 +1,976 @@
+import re
+
+"""
+Predicates for filtering todo list.
+Module defines lexer, parser and predicates themself.
+
+Predicate implements method test(text) that returns if
+predicate applies to given text.
+
+For example '@today and not @done' returns if text contains
+tag @today and not contains tag @done.
+
+Predicates joined by 'and' and 'or' are predicate,
+predicate negated with 'not' is a predicate.
+
+Operators (op) can work on project titles or variables of tags,
+variable of tag is defined in parenthesises after tag,
+for example @due(2013-02-09). Variables are compared as strings.
+
+Example:
+ @due < 2013-03-10 for '- buy milk @due(2013-02-09)' is true.
+
+grammar of predicates (SLR(1)):
+
+S -> E1 | E1 +d
+E1 -> E1 and E2
+ | E2.
+E2 -> E2 or E3
+ | E3.
+E3 -> not E3
+ | E4
+ | ( E1 ).
+E4 -> Argument op Words
+ | Words
+ | Tag .
+Words -> word Words
+ | .
+
+op -> = | != | < | <= | >= | > | matches | contains | $ .
+Tag -> @ word | EndTag.
+EndTag -> (Words) | epsilon.
+Argument -> project | line | uniqueid | content | type | level | parent | index | Tag.
+"""
+
+
+class Token(object):
+ operators = ['=', '!=', '<', '<=', '>', '>=', '$', 'matches', 'contains']
+ log_ops = ['and', 'or', 'not']
+ keywords = ['project', 'line', 'uniqueid', 'content', 'type', 'level', 'parent', 'index']
+ tag_prefix = '@'
+
+ def __init__(self, text=None):
+ self.text = text
+ # set type of token
+ if not text:
+ self.type = '$'
+ elif text in Token.operators:
+ self.type = 'op'
+ elif text == '+d':
+ self.type = 'plusD'
+ elif text in Token.log_ops:
+ self.type = text
+ elif text in Token.keywords:
+ self.type = 'arg'
+ elif text[0] == Token.tag_prefix:
+ self.type = 'tag'
+ elif text[0] == '"':
+ self.type = 'word'
+ self.text = text[1:-1]
+ elif text == '(':
+ self.type = 'lparen'
+ elif text == ')':
+ self.type = 'rparen'
+ else:
+ self.type = 'word'
+
+ def __str__(self):
+ return repr(self.text) + ' : ' + self.type
+
+
+class Lexer(object):
+ def __init__(self, input_text):
+ self.tokens = Lexer.tokenize(input_text)
+
+ @staticmethod
+ def tokenize(input_text):
+ """converts input text to list of tokens"""
+ tokens = []
+
+ def add_token(text=None):
+ if text != '' and text != ' ':
+ tokens.append(Token(text))
+
+ idx = 0
+ collected = ''
+ text_length = len(input_text)
+ while idx < text_length + 1:
+ if idx == text_length:
+ # finish tokenizing
+ add_token(collected) # add remaining collected text
+ add_token() # add end of input token
+ elif input_text[idx] == '+':
+ if idx + 1 < len(input_text):
+ if input_text[idx + 1] == 'd':
+ add_token(collected)
+ collected = ''
+ add_token('+d')
+ idx += 1
+ elif input_text[idx] == ' ':
+ # spaces separate but but don't have semantic meaning
+ add_token(collected)
+ collected = ''
+ elif input_text[idx] in ('(', ')'):
+ # parenthesises seperate and have semantic meaning
+ add_token(collected)
+ collected = ''
+ add_token(input_text[idx])
+ elif input_text[idx] in ('<', '>', '!'):
+ # operators or prefixes of operators
+ add_token(collected)
+ collected = input_text[idx]
+ elif input_text[idx] == '=':
+ if collected in ('<', '>', '!'):
+ # "="" preceded by any of this signs is an operator
+ collected += '='
+ add_token(collected)
+ else:
+ # "=" by itself is also an operator
+ add_token(collected)
+ add_token('=')
+ collected = ''
+ elif input_text[idx] == '$':
+ add_token(collected)
+ add_token('$')
+ collected = ''
+ elif input_text[idx] == '"':
+ # quoted part of input is allways a word
+ add_token(collected)
+ collected = ''
+ next_quotation_mark_idx = input_text.find('"', idx + 1)
+ if next_quotation_mark_idx == -1:
+ # when there is no matching quoatation mark
+ # end of the input is assumed
+ add_token(input_text[idx:] + '"')
+ idx = text_length - 1 # finish in next iteration of loop
+ else:
+ add_token(input_text[idx:next_quotation_mark_idx + 1])
+ idx = next_quotation_mark_idx
+
+ else:
+ if collected in ('<', '>'):
+ add_token(collected)
+ collected = ''
+ collected += input_text[idx]
+ idx += 1
+
+ return tokens[::-1]
+
+ def pop(self):
+ """pops and returns topmost token"""
+ try:
+ return self.tokens.pop()
+ except IndexError:
+ raise ParsingError
+
+ def top(self):
+ """returns topmost token"""
+ try:
+ return self.tokens[-1]
+ except IndexError:
+ raise ParsingError
+
+
+class ParsingError(Exception):
+ pass
+
+
+class Parser(object):
+ def __init__(self, lexer):
+ self.lexer = lexer
+ self.create_parsing_table()
+ self.stack = [0]
+
+ def goto(self, state):
+ self.parsing_table[self.stack[-2]][state]()
+
+ def create_parsing_table(self):
+ """long functions with declaration of parsing table and parser actions"""
+ def shift_gen(state_no):
+ def shift():
+ """puts lexem and state number on stack"""
+ self.stack.append(self.lexer.pop())
+ self.stack.append(state_no)
+ return shift
+
+ def goto_gen(state_no):
+ def goto():
+ """puts state number on stack"""
+ self.stack.append(state_no)
+ return goto
+
+ def err():
+ raise ParsingError
+
+ def acc():
+ """returns abstrac syntax tree"""
+ self.stack.pop()
+ return self.stack[-1]
+
+ # reductions, name of the functions contains information about production
+ # -> is changedd to __, terminals and nonterminals are separated by _
+
+ def rS__E1():
+ self.stack.pop()
+ self.goto('S')
+
+ def rS__E1_plusD():
+ self.stack.pop()
+ self.stack.pop() # +d
+
+ self.stack.pop()
+ e1 = self.stack.pop()
+ self.stack.append(PlusDescendants(e1))
+ self.goto('S')
+
+ def rE3__E4():
+ self.stack.pop()
+ self.goto('E3')
+
+ def rE1__E2():
+ self.stack.pop()
+ self.goto('E1')
+
+ def rE2__E3():
+ self.stack.pop()
+ self.goto('E2')
+
+ def rE3__lparen_E1_rparen():
+ self.stack.pop() # )
+ self.stack.pop()
+
+ self.stack.pop()
+ e1 = self.stack.pop()
+
+ self.stack.pop() # (
+ self.stack.pop()
+
+ self.stack.append(e1)
+ self.goto('E3')
+
+ def rE2__E2_or_E3():
+ self.stack.pop()
+ e3 = self.stack.pop()
+
+ self.stack.pop() # or
+ self.stack.pop()
+
+ self.stack.pop()
+ e2 = self.stack.pop()
+
+ self.stack.append(OrPredicate(e2, e3))
+ self.goto('E2')
+
+ def rE4__Words():
+ self.stack.pop()
+ self.goto('E4')
+
+ def rE1__E1_and_E2():
+ self.stack.pop()
+ e2 = self.stack.pop()
+
+ self.stack.pop() # and
+ self.stack.pop()
+
+ self.stack.pop()
+ e1 = self.stack.pop()
+
+ self.stack.append(AndPredicate(e1, e2))
+ self.goto('E1')
+
+ def rE3__not_E3():
+ self.stack.pop()
+ e3 = self.stack.pop()
+
+ self.stack.pop() # not
+ self.stack.pop()
+
+ self.stack.append(NotPredicate(e3))
+ self.goto('E3')
+
+ def rWords__epsilon():
+ self.stack.append(WordsPredicate())
+ self.goto('Words')
+
+ def rE4__tag_op_Words():
+ self.stack.pop()
+ words = self.stack.pop()
+
+ self.stack.pop()
+ op = self.stack.pop()
+
+ self.stack.pop()
+ arg = self.stack.pop()
+
+ self.stack.append(ArgOpPredicate(arg, words, op))
+ self.goto('E4')
+
+ def rE4__arg_op_Words():
+ self.stack.pop()
+ words = self.stack.pop()
+
+ self.stack.pop()
+ op = self.stack.pop()
+
+ self.stack.pop()
+ arg = self.stack.pop()
+
+ self.stack.append(ArgOpPredicate(arg, words, op))
+ self.goto('E4')
+
+ def rWords__word_Words():
+ self.stack.pop()
+ words = self.stack.pop()
+
+ self.stack.pop()
+ word = self.stack.pop()
+
+ self.stack.append(WordsPredicate(word) + words)
+ self.goto('Words')
+
+ def rE4__tag():
+ self.stack.pop()
+ tag = self.stack.pop()
+
+ self.stack.append(TagPredicate(tag))
+ self.goto('E4')
+
+ self.parsing_table = {
+ 0: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": shift_gen(10),
+ "op": err,
+ "arg": shift_gen(9),
+ "rparen": rWords__epsilon,
+ "lparen": shift_gen(8),
+ "not": shift_gen(7),
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": goto_gen(6),
+ "E2": goto_gen(5),
+ "E3": goto_gen(4),
+ "E1": goto_gen(3),
+ "E4": goto_gen(2),
+ "Words": goto_gen(1),
+ },
+ 1: {
+ "$": rE4__Words,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE4__Words,
+ "lparen": err,
+ "not": err,
+ "or": rE4__Words,
+ "and": rE4__Words,
+ "plusD": rE4__Words,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 2: {
+ "$": rE3__E4,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE3__E4,
+ "lparen": err,
+ "not": err,
+ "or": rE3__E4,
+ "and": rE3__E4,
+ "plusD": rE3__E4,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 3: {
+ "$": rS__E1,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": err,
+ "lparen": err,
+ "not": err,
+ "or": err,
+ "and": shift_gen(19),
+ "plusD": shift_gen(18),
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 4: {
+ "$": rE2__E3,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE2__E3,
+ "lparen": err,
+ "not": err,
+ "or": rE2__E3,
+ "and": rE2__E3,
+ "plusD": rE2__E3,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 5: {
+ "$": rE1__E2,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE1__E2,
+ "lparen": err,
+ "not": err,
+ "or": shift_gen(17),
+ "and": rE1__E2,
+ "plusD": rE1__E2,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 6: {
+ "$": acc,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": err,
+ "lparen": err,
+ "not": err,
+ "or": err,
+ "and": err,
+ "plusD": err,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 7: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": shift_gen(10),
+ "op": err,
+ "arg": shift_gen(9),
+ "rparen": rWords__epsilon,
+ "lparen": shift_gen(8),
+ "not": shift_gen(7),
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": err,
+ "E2": err,
+ "E3": goto_gen(16),
+ "E1": err,
+ "E4": goto_gen(2),
+ "Words": goto_gen(1),
+ },
+ 8: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": shift_gen(10),
+ "op": err,
+ "arg": shift_gen(9),
+ "rparen": rWords__epsilon,
+ "lparen": shift_gen(8),
+ "not": shift_gen(7),
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": err,
+ "E2": goto_gen(5),
+ "E3": goto_gen(4),
+ "E1": goto_gen(15),
+ "E4": goto_gen(2),
+ "Words": goto_gen(1),
+ },
+ 9: {
+ "$": err,
+ "word": err,
+ "tag": err,
+ "op": shift_gen(14),
+ "arg": err,
+ "rparen": err,
+ "lparen": err,
+ "not": err,
+ "or": err,
+ "and": err,
+ "plusD": err,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 10: {
+ "$": rE4__tag,
+ "word": err,
+ "tag": err,
+ "op": shift_gen(13),
+ "arg": err,
+ "rparen": rE4__tag,
+ "lparen": err,
+ "not": err,
+ "or": rE4__tag,
+ "and": rE4__tag,
+ "plusD": rE4__tag,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 11: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rWords__epsilon,
+ "lparen": err,
+ "not": err,
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": goto_gen(12),
+ },
+ 12: {
+ "$": rWords__word_Words,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rWords__word_Words,
+ "lparen": err,
+ "not": err,
+ "or": rWords__word_Words,
+ "and": rWords__word_Words,
+ "plusD": rWords__word_Words,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 13: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rWords__epsilon,
+ "lparen": err,
+ "not": err,
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": goto_gen(24),
+ },
+ 14: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rWords__epsilon,
+ "lparen": err,
+ "not": err,
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": goto_gen(23),
+ },
+ 15: {
+ "$": err,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": shift_gen(22),
+ "lparen": err,
+ "not": err,
+ "or": err,
+ "and": shift_gen(19),
+ "plusD": err,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 16: {
+ "$": rE3__not_E3,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE3__not_E3,
+ "lparen": err,
+ "not": err,
+ "or": rE3__not_E3,
+ "and": rE3__not_E3,
+ "plusD": rE3__not_E3,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 17: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": shift_gen(10),
+ "op": err,
+ "arg": shift_gen(9),
+ "rparen": rWords__epsilon,
+ "lparen": shift_gen(8),
+ "not": shift_gen(7),
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": err,
+ "E2": err,
+ "E3": goto_gen(21),
+ "E1": err,
+ "E4": goto_gen(2),
+ "Words": goto_gen(1),
+ },
+ 18: {
+ "$": rS__E1_plusD,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": err,
+ "lparen": err,
+ "not": err,
+ "or": err,
+ "and": err,
+ "plusD": err,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 19: {
+ "$": rWords__epsilon,
+ "word": shift_gen(11),
+ "tag": shift_gen(10),
+ "op": err,
+ "arg": shift_gen(9),
+ "rparen": rWords__epsilon,
+ "lparen": shift_gen(8),
+ "not": shift_gen(7),
+ "or": rWords__epsilon,
+ "and": rWords__epsilon,
+ "plusD": rWords__epsilon,
+ "S": err,
+ "E2": goto_gen(20),
+ "E3": goto_gen(4),
+ "E1": err,
+ "E4": goto_gen(2),
+ "Words": goto_gen(1),
+ },
+ 20: {
+ "$": rE1__E1_and_E2,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE1__E1_and_E2,
+ "lparen": err,
+ "not": err,
+ "or": shift_gen(17),
+ "and": rE1__E1_and_E2,
+ "plusD": rE1__E1_and_E2,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 21: {
+ "$": rE2__E2_or_E3,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE2__E2_or_E3,
+ "lparen": err,
+ "not": err,
+ "or": rE2__E2_or_E3,
+ "and": rE2__E2_or_E3,
+ "plusD": rE2__E2_or_E3,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 22: {
+ "$": rE3__lparen_E1_rparen,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE3__lparen_E1_rparen,
+ "lparen": err,
+ "not": err,
+ "or": rE3__lparen_E1_rparen,
+ "and": rE3__lparen_E1_rparen,
+ "plusD": rE3__lparen_E1_rparen,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 23: {
+ "$": rE4__arg_op_Words,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE4__arg_op_Words,
+ "lparen": err,
+ "not": err,
+ "or": rE4__arg_op_Words,
+ "and": rE4__arg_op_Words,
+ "plusD": rE4__arg_op_Words,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ 24: {
+ "$": rE4__tag_op_Words,
+ "word": err,
+ "tag": err,
+ "op": err,
+ "arg": err,
+ "rparen": rE4__tag_op_Words,
+ "lparen": err,
+ "not": err,
+ "or": rE4__tag_op_Words,
+ "and": rE4__tag_op_Words,
+ "plusD": rE4__tag_op_Words,
+ "S": err,
+ "E2": err,
+ "E3": err,
+ "E1": err,
+ "E4": err,
+ "Words": err,
+ },
+ }
+
+ def parse(self):
+ """returns parsed predicate, throws ParsingError"""
+ lex = self.lexer.top()
+ state = self.stack[-1]
+ parsed = self.parsing_table[state][lex.type]()
+ if parsed:
+ return parsed
+ else:
+ return self.parse()
+
+
+class OrPredicate(object):
+ def __init__(self, left_side, right_side):
+ self.left_side = left_side
+ self.right_side = right_side
+
+ def test(self, item):
+ return self.left_side.test(item) or self.right_side.test(item)
+
+ def __str__(self):
+ return "{0} or {1}".format(self.left_side, self.right_side)
+
+
+class AndPredicate(object):
+ def __init__(self, left_side, right_side):
+ self.left_side = left_side
+ self.right_side = right_side
+
+ def test(self, item):
+ return self.left_side.test(item) and self.right_side.test(item)
+
+ def __str__(self):
+ return "{0} and {1}".format(self.left_side, self.right_side)
+
+
+class NotPredicate(object):
+ def __init__(self, negated):
+ self.negated = negated
+
+ def test(self, item):
+ return not self.negated.test(item)
+
+ def __str__(self):
+ return "not {0}".format(self.negated)
+
+
+op_functions = {
+ '=': lambda x, y: x.lower() == y.lower(),
+ '!=': lambda x, y: x.lower() != y.lower(),
+ '<': lambda x, y: x.lower() < y.lower(),
+ '<=': lambda x, y: x.lower() <= y.lower(),
+ '>=': lambda x, y: x.lower() >= y.lower(),
+ '>': lambda x, y: x.lower() > y.lower(),
+ '$': lambda x, y: y.lower() in x.lower(),
+ 'matches': lambda x, y: bool(re.match(y, x))
+}
+
+op_functions['contains'] = op_functions['$']
+
+
+class ArgOpPredicate(object):
+ """Argument -> project | line | uniqueid | content | type | level | parent | index | Tag."""
+
+ def __init__(self, left_side, right_side, op):
+ self.left_side = left_side.text
+ self.right_side = right_side.words
+ self.op = op.text
+
+ def test(self, item):
+ if self.left_side[0] == '@': # tag
+ tag_search = ' ' + self.left_side + '\(([^\()]*)\)'
+ match = re.search(tag_search, item.title.text)
+ if match:
+ left_side = match.group(1)
+ elif self.left_side in item.title.text:
+ # no variable is equal to empty string
+ left_side = ''
+ else:
+ return False
+ # print item.text, left_side, self.right_side, op_functions[self.op](left_side, self.right_side)
+ r = op_functions[self.op](left_side, self.right_side)
+ return r
+
+ elif self.left_side == 'project':
+ while item.parent_item:
+ if op_functions[self.op](item.parent_item.title.content, self.right_side):
+ return True
+ else:
+ item = item.parent_item
+ elif self.left_side == 'line':
+ return op_functions[self.op](item.title.line, self.right_side)
+ elif self.left_side == 'uniqueid':
+ return op_functions[self.op](str(item.title._id), self.right_side)
+ elif self.left_side == 'content':
+ return op_functions[self.op](item.title.content, self.right_side)
+ elif self.left_side == 'type':
+ return op_functions[self.op](item.type, self.right_side)
+ elif self.left_side == 'level':
+ return op_functions[self.op](str(item.title.indent_level), self.right_side)
+ elif self.left_side == 'parent':
+ if item.parent_item:
+ return op_functions[self.op](item.parent_item.title.content, self.right_side)
+ return False
+ elif self.left_side == 'index':
+ return op_functions[self.op](str(item.index()), self.right_side)
+
+ def __str__(self):
+ return "{0} {2} {1}".format(self.left_side, self.right_side, self.op)
+
+
+class PlusDescendants(object):
+ def __init__(self, predicate):
+ self.predicate = predicate
+
+ def test(self, item):
+ while item:
+ if self.predicate.test(item):
+ return True
+ item = item.parent_item
+ return False
+
+ def str(self):
+ return str(self.predicate) + ' +d'
+
+
+class WordsPredicate(object):
+ """predicate if text contains some text as subtext"""
+ def __init__(self, words=None):
+ self.words = words.text if words else ''
+
+ def test(self, item):
+ return self.words.lower() in item.title.text.lower()
+
+ def __str__(self):
+ return self.words
+
+ def __add__(self, other):
+ new_word = WordsPredicate()
+ new_word.words = (self.words + ' ' + other.words).strip()
+ return new_word
+
+
+class TagPredicate(object):
+ def __init__(self, tag):
+ self.tag = tag.text
+
+ def test(self, item):
+ return bool(re.search("(^| )" + self.tag + "($| |\()", item.title.text))
+
+ def __str__(self):
+ return self.tag
+
+
+class Item(object):
+ def __init__(self, text, project=None):
+ self.text = text
+ self.project = project
+
+
+def predicate(text):
+ return Parser(Lexer(text)).parse()
View
142 filterpredicate_test.py
@@ -0,0 +1,142 @@
+import unittest
+from filterpredicate import Item, Lexer, Parser, ParsingError
+
+
+def test_predicate(predicate, text, project=None):
+ lexer = Lexer(predicate)
+ parser = Parser(lexer)
+ predicate = parser.parse()
+ return predicate.test(Item(text, project))
+
+
+def test_parse(predicate):
+ Parser(Lexer("@done @wone")).parse()
+
+
+class FilterPredicateTest(unittest.TestCase):
+ def test_parsing_error(self):
+ self.assertRaises(ParsingError, test_parse, "@done @wone")
+ self.assertRaises(ParsingError, test_parse, "not")
+
+ def test_word_search(self):
+ self.assertTrue(test_predicate("test", "dsftest fdsf"))
+ self.assertTrue(test_predicate("test test2", "dsftest test2fdsf"))
+
+ self.assertFalse(test_predicate("test", "dsf tet fdsf"))
+
+ def test_simple_tag_search(self):
+ self.assertTrue(test_predicate("@test", "dsf @test fdsf"))
+ self.assertTrue(test_predicate("@test", "@test fdsf"))
+ self.assertTrue(test_predicate("@test", " f f fdsf @test"))
+
+ self.assertFalse(test_predicate("@test", "dsf tet fdsf"))
+ self.assertFalse(test_predicate("@test", "dsf@test fdsf"))
+
+ def test_tag_search_with_parameters_eq(self):
+ self.assertTrue(test_predicate("@test=1", "dsf @test(1) fdsf"))
+
+ self.assertFalse(test_predicate("@test = 1", "dsf @test(2) fdsf"))
+ self.assertFalse(test_predicate("@test = 1", "- dsf @test fdsf"))
+ self.assertFalse(test_predicate("@test = 1", "- dsf @test(1)fdsf"))
+
+ def test_tag_search_with_parameters_neq(self):
+ self.assertTrue(test_predicate("@test!=1", "dsf @test(2) fdsf"))
+ self.assertTrue(test_predicate("@test != 1", "- dsf @test fdsf"))
+
+ self.assertFalse(test_predicate("@test != 1", "dsf @test(1) fdsf"))
+
+ def test_tag_search_with_parameters_lt(self):
+ self.assertTrue(test_predicate("@test<3", "dsf @test(2) fdsf"))
+ self.assertTrue(test_predicate("@test < 1", "- dsf @test fdsf"))
+
+ self.assertFalse(test_predicate("@test < 1", "dsf @test(3) fdsf"))
+
+ def test_tag_search_with_parameters_lte(self):
+ self.assertTrue(test_predicate("@test<=3", "dsf @test(3) fdsf"))
+ self.assertTrue(test_predicate("@test <= 1", "- dsf @test fdsf"))
+
+ self.assertFalse(test_predicate("@test <= 1", "dsf @test(2) fdsf"))
+
+ def test_tag_search_with_parameters_gt(self):
+ self.assertTrue(test_predicate("@test>1", "dsf @test(3) fdsf"))
+
+ self.assertFalse(test_predicate("@test > 3", "dsf @test(2) fdsf"))
+ self.assertFalse(test_predicate("@test > 1", "- dsf @test fdsf"))
+
+ def test_tag_search_with_parameters_gte(self):
+ self.assertTrue(test_predicate("@test>=1", "dsf @test(1) fdsf"))
+
+ self.assertFalse(test_predicate("@test >= 3", "dsf @test(2) fdsf"))
+ self.assertFalse(test_predicate("@test >= 1", "- dsf @test fdsf"))
+
+ def test_predicate_with_and(self):
+ self.assertTrue(test_predicate("test and unit", "dsf test fdsfunit"))
+ self.assertTrue(test_predicate("@test and unit", "dsf @test fdsfunit"))
+
+ self.assertFalse(test_predicate("test and unit", "dsf test fdsf"))
+ self.assertFalse(test_predicate("test and unit", "dsf fds unit f"))
+
+ def test_predicate_with_or(self):
+ self.assertTrue(test_predicate("test or unit", "dsf fdsfunit"))
+ self.assertTrue(test_predicate("@test or unit", "dsf @test fdsf"))
+
+ self.assertFalse(test_predicate("test and unit", "dsf rtrest fdsf"))
+
+ def test_predicate_with_not(self):
+ self.assertTrue(test_predicate("not test", "dsf fdsfunit"))
+ self.assertTrue(test_predicate("not @test", "dsf fdsfunit"))
+
+ self.assertFalse(test_predicate("not @test", "dsf @test rtrest fdsf"))
+
+ def test_project_search(self):
+ self.assertTrue(test_predicate(
+ "project = proj", "dsf fdsfunit", "proj")
+ )
+ self.assertTrue(test_predicate(
+ "project != proj2", "dsf fdsfunit", "proj")
+ )
+
+ self.assertFalse(test_predicate(
+ "project != proj", "dsf fdsfunit", "proj")
+ )
+
+ self.assertFalse(test_predicate(
+ "project = proj", "dsf fdsfunit", "proj2")
+ )
+
+ def test_complex_predicates(self):
+ self.assertTrue(test_predicate(
+ "(@test or kest) and @west", "kest @west asb")
+ )
+ self.assertTrue(test_predicate(
+ "(@test or kest) and @west", "@test @west asb")
+ )
+ self.assertTrue(test_predicate(
+ "@today and not @done", "- fm s,d @today")
+ )
+ self.assertTrue(test_predicate(
+ "(@test and kest) or not @west", "fsd asb")
+ )
+ self.assertTrue(test_predicate(
+ "(@test and kest) or @west", "@test kest asb")
+ )
+ self.assertFalse(test_predicate(
+ "@today and not @done", "- fm s,d @today @done(2013-11-01)")
+ )
+
+ def test_quoted_text_search(self):
+ self.assertTrue(test_predicate(
+ '"@test < 1"', "awefds@test < 1mfkld")
+ )
+ self.assertTrue(test_predicate(
+ '"@test < 1', "awefds@test < 1mfkld")
+ )
+ self.assertTrue(test_predicate(
+ '"@test < 1" and @d', "awefds@test < 1mfkld @d")
+ )
+
+ self.assertFalse(test_predicate(
+ '"@test < 1"', "@test(0)")
+ )
+# run
+unittest.main()
View
115 html/checkboxes.css
@@ -0,0 +1,115 @@
+body {
+ font-family: "Palatino" "Book Antiqua", serif;
+ font-size: 0.4cm;
+ background-color: #FFFFFC;
+ color: #262626;
+}
+
+.whole {
+
+}
+
+ul{
+ display: table;
+ padding: 0;
+ margin-left: 0;
+ list-style-type: none;
+}
+
+li {
+ display: inline-block;
+ width: 17cm;
+
+}
+
+.task0, .task1, .task2, .task3, .task4 {
+ display: inline-block;
+ margin-left: 0.5cm;
+ padding-right: 1cm;
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+}
+
+
+.note0, .note1, .note2, .note3, .note4{
+ display: table-cell;
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ font-style: italic;
+ padding-left: 0.2cm;
+
+}
+
+.project0, .project1, .project2, .project3, .project4 {
+ display: inline-block;
+ width: 5cm;
+ padding-right: 0.5cm;
+ padding-left: 0.5cm;
+ padding-top: 1em;
+ padding-bottom: 1em;
+ color: #262626;
+ font-family: "Futura" "Calibri" "Helvetica Neue" sans-serif;
+ font-weight: bold;
+}
+
+.project0 {
+ font-size: 1.0em;
+}
+
+.project1 {
+ font-size: 0.9em;
+}
+
+.project2 {
+ font-size: 0.8em;
+}
+
+.project3 {
+ font-size: 0.7em;
+}
+
+.project4 {
+ font-size: 0.6em;
+}
+
+
+.task1, .note1, .project1 {
+ padding-left: 0.5cm;
+}
+
+.task2, .note2, .project2 {
+ padding-left: 1.5cm;
+}
+
+.task3, .note3, .project3 {
+ padding-left: 2.5cm;
+}
+
+.task4, .note4, .project4 {
+ padding-left: 3.5cm;
+}
+
+.done {
+ /*color: #626262;*/
+ /*text-decoration: line-through;*/
+}
+
+.tag {
+ font-style: italic;
+ font-weight: normal;
+ color: #5F82FF;
+}
+
+.task0:before, .task1:before, .task2:before, .task3:before, .task4:before{
+ content:"";
+ font-size: 1.2em;
+ position:relative;
+ left:-5px;
+}
+
+.done:before{
+ content:"";
+ font-size: 1.2em;
+ position:relative;
+ left:-5px;
+}
View
102 html/index_card.css
@@ -0,0 +1,102 @@
+body {
+ width: 5.5cm;
+ border-left: 1px solid #D6D6D6;
+ color: black;
+ font-family: "Palatino" "Book Antiqua", serif;
+ font-size: 0.4cm;
+}
+
+.whole {
+ border-right: 0.5cm solid #D6D6D6;
+}
+
+ul{
+ display: table;
+ padding: 0;
+ margin-left: 0;
+ list-style-type: none;
+}
+
+li {
+ display: inline-block;
+ width: 5.5cm;
+ border-top: 1px dashed #838383;
+
+}
+
+.task0, .task1, .task2, .task3, .task4 {
+ display: inline-block;
+ margin-left: 0.2cm;
+ padding-right: 1cm;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
+}
+
+
+.note0, .note1, .note2, .note3, .note4{
+ display: table-cell;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
+ font-style: italic;
+ padding-left: 0.2cm;
+
+}
+
+
+.project0, .project1, .project2, .project3, .project4 {
+ display: table-cell;
+ width: 5cm;
+ padding-right: 0.5cm;
+ padding-left: 0.2cm;
+ color: #262626;
+ font-family: "Futura" "Calibri" "Helvetica Neue" sans-serif;
+ font-weight: bold;
+}
+
+.project0 {
+ font-size: 1.0em;
+}
+
+.project1 {
+ font-size: 0.9em;
+}
+
+.project2 {
+ font-size: 0.8em;
+}
+
+.project3 {
+ font-size: 0.7em;
+}
+
+.project4 {
+ font-size: 0.6em;
+}
+
+
+.task1, .note1 {
+ padding-left: 0;
+}
+
+.task2, .note2 {
+ padding-left: 0.2cm;
+}
+
+.task3, .note3 {
+ padding-left: 0.4cm;
+}
+
+.task4, .note4 {
+ padding-left: 0.6cm;
+}
+
+.done {
+ color: #626262;
+ text-decoration: line-through;
+}
+
+.tag {
+ font-style: italic;
+ font-weight: normal;
+ color: #5F82FF;
+}
View
269 html/qqtest.html
@@ -0,0 +1,269 @@
+
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link href="index_card.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<div class="whole">
+ <ul><li><span class="project0">Daily:</span>
+<ul><li><span class="task1">12 <span class="tag">@today</span></span></li>
+<li><span class="task1">23 <span class="tag">@today</span></span></li>
+<li><span class="task1">10% - Quantum Thife <span class="tag">@today</span></span></li>
+<li><span class="task1">podręcznik - Implementing responsive... <span class="tag">@today</span></span></li>
+<br></ul></li>
+<li><span class="project0">Single actions:</span>
+<ul><li><span class="task1">jedz mniej</span></li>
+<li><span class="task1">Projects.todo do gita? <span class="tag">@in(2013-02-16)</span> <span class="tag">@next</span></span></li>
+<li><span class="task1">Isoformat w image Inbox <span class="tag">@in(2013-02-16)</span> <span class="tag">@next</span></span></li>
+<li><span class="task1">po TodoFlow2 - IsingModel <span class="tag">@in(2013-02-16)</span></span></li>
+<li><span class="task1">@SzymonNowicki ma moje LA Noir</span></li>
+<li><span class="task1">oddać zabójce bestii <span class="tag">@ŁukaszZałuski</span></span></li>
+<li><span class="task1">oddać Matematykę konkretną <span class="tag">@ŁukaszZałuski</span></span></li>
+<li><span class="task1">czy nie zostawiłem pendrive u niego? <span class="tag">@ŁukaszZałuski</span></span></li>
+<li><span class="task1">szyba do drzwi w kuchni <span class="tag">@KubaPerkowski</span> <span class="tag">@IwonaPerkowska</span></span></li></ul></li>
+<li><span class="project0">Studia:</span>
+<ul><li><span class="project1">handel elektroniczny:</span></li>
+<li><span class="project1">interakcja człowiek-komputer:</span></li>
+<li><span class="project1">wstęp do optyki i fizyki materii skondensowanej:</span></li>
+<li><span class="project1">proseminarium licencjackie:</span></li>
+<li><span class="project1">pracownia3:</span>
+<ul><li><span class="task2">zapisać się na ćwiczenie z optyki</span>
+<ul><li><span class="note3">L1 &gt; L3 &gt; L6 &gt; L7 &gt; L8</span></li></ul></li>
+<li><span class="task2">pójść do asystenta</span>
+<ul><li><span class="task3">umówić się na termin</span></li></ul></li>
+<li><span class="task2">wypożyczyć książki?</span></li>
+<li><span class="task2">nauka do kolokwium wstępnego</span></li>
+<li><span class="task2">kolokwium wstępne</span></li>
+<li><span class="task2">przeprowadzić ćwiczenie</span></li>
+<li><span class="task2">napisać raport</span></li></ul></li>
+<li><span class="project1">licencjat FUW:</span>
+<ul><li><span class="task2">ustalić nowy termin spotkań</span></li>
+<li><span class="task2">nowa implementacja</span>
+<ul><li><span class="task3">IsingModel</span>
+<ul><li><span class="task4">zaprojektować <span class="tag">@next</span></span></li>
+<li><span class="task4">save</span></li>
+<li><span class="task4">load</span></li>
+<li><span class="task4">plot</span></li></ul></li>
+<li><span class="task3">refaktor all</span></li></ul></li></ul></li>
+<li><span class="project1">Erazmus: <span class="tag">@due(2013-02-20)</span> <span class="tag">@waiting(odpowiedź na maila)</span></span>
+<ul><li><span class="task2">Wybrać uczelnie</span></li>
+<li><span class="task2">napisać życiorys</span></li>
+<li><span class="task2">napisać aplikację</span></li>
+<li><span class="task2">email do JJ czy mi wypisze</span></li></ul></li>
+<li><span class="project1">IPS: <span class="tag">@waiting(możliwość spotkanie w Wojtkiewiczem)</span></span>
+<ul><li><span class="task2">podpis <span class="tag">@Wojtkiewicz</span></span></li>
+<li><span class="task2">odnieść IPS</span></li></ul></li>
+<li><span class="project1">egzamin końcowy FUW:</span>
+<ul><li><span class="task2">dowiedzieć się jak dokładnie wygląda <span class="tag">@PiotrDróżdż</span> <span class="tag">@next</span></span></li></ul></li>
+<li><span class="project1">egzamin wstępny MIM:</span>
+<ul><li><span class="task2">znaleźć egzaminy z poprzednich lat <span class="tag">@next</span></span></li></ul></li>
+<li><span class="project1">repodanie do wysmolka:</span>
+<ul><li><span class="task2">odnieść</span></li></ul></li>
+<li><span class="project1">summer job:</span>
+<ul><li><span class="task2">wysłać jeszcze raz</span>
+<ul><li><span class="task3">Amazon <span class="tag">@next</span></span></li>
+<li><span class="task3">EA</span></li>
+<li><span class="task3">Activision</span></li>
+<li><span class="task3">IBM</span></li></ul></li>
+<li><span class="task2">research</span>
+<ul><li><span class="task3">research programista pythona <span class="tag">@next</span></span>
+<ul><li><span class="task4">Polska</span></li>
+<li><span class="task4">Niemcy</span></li></ul></li>
+<li><span class="task3">Qualcomm <span class="tag">@next</span></span></li>
+<li><span class="task3">MTV Networks</span></li>
+<li><span class="task3">Intel</span></li>
+<li><span class="task3">Cisco</span></li>
+<li><span class="task3">NASA</span></li>
+<li><span class="task3">coś bioinfomartycznego</span></li></ul></li>
+<li><span class="task2">praktyki na tajwanie <span class="tag">@due(2013-03-04)</span></span>
+<ul><li><span class="task3">http://ccc.ntu.edu.tw/ <span class="tag">@next</span></span></li>
+<li><span class="task3">Machine to machine research</span></li>
+<li><span class="task3">Internet of Things research</span></li>
+<br></ul></li></ul></li></ul></li>
+<li><span class="project0">Fiddling:</span>
+<ul><li><span class="project1">TodoFlow2: <span class="tag">@today</span></span>
+<ul><li><span class="task2 done">find project id by title <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task2">add to project by title</span></li>
+<li><span class="task2 done">remove tags <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task2">remove from parents</span>
+<ul><li><span class="task3 done">+d filter <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">is_project ma problemy <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">wszystko może mieć subtask <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">subtasks of task <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">outputs: <span class="tag">@done(2013-02-16)</span></span>
+<ul><li><span class="task4 done">colored countdown <span class="tag">@done(2013-02-16)</span></span></li></ul></li>
+<li><span class="task3 done">wyszukiwanie po projektach <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">extract text <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">remove trailing tags <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">save to file <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task3 done">tag revisot <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task3 done">do revisit <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task3 done">remove revisit <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task3 done">rozne klasy projektow w zaleznosci od zagniezdzenia <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task3 done">add Task <span class="tag">@done(2013-02-17)</span></span>
+<ul><li><span class="task4 done">add as subtask <span class="tag">@done(2013-02-17)</span></span>
+<ul><li><span class="task4 done">prepend <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task4 done">append <span class="tag">@done(2013-02-17)</span></span></li></ul></li>
+<li><span class="task4 done">alfred xml <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task4 done">do from alfred <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task4 done">copy from alfred <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task4 done">remove from alfred <span class="tag">@done(2013-02-17)</span></span></li></ul></li>
+<li><span class="task3 done">z powodu item_by_id w klasie może być tylko jedna główna TodoList <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">countdown geektool <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">as_markdown <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task3 done">notatka traci kolor po tagu gdy jest w niej tag <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">zgubila się kreska <span class="tag">@done(2013-02-16)</span></span></li></ul></li>
+<li><span class="task2 done">atributes <span class="tag">@done(2013-02-16)</span></span>
+<ul><li><span class="task3 done">type <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">line <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">content <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">level <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">parent <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">project <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">index <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">uniqueid <span class="tag">@done(2013-02-16)</span></span></li></ul></li>
+<li><span class="task2 done">operators <span class="tag">@done(2013-02-16)</span></span>
+<ul><li><span class="task3 done">= <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">== <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">&gt; <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">&lt; <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">contains, $ <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task3 done">matches <span class="tag">@done(2013-02-16)</span></span></li></ul></li>
+<li><span class="task2 done">escapowanie i kodowanie znaków do html <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task2 done">span class="tag" dla tagów w as_html <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task2 done">pusta linia prawdopodobnie rozwala wcięcia <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task2 done">jak cos jest wciete w projekcie to nie wpisuje go sobie <span class="tag">@done(2013-02-16)</span></span></li>
+<li><span class="task2">archive</span></li>
+<li><span class="task2 done">day one log <span class="tag">@done(2013-02-17)</span></span>
+<ul><li><span class="task3 done">brak * * w done <span class="tag">@done(2013-02-17)</span></span></li></ul></li>
+<li><span class="task2">on hold</span></li>
+<li><span class="task2 done">css <span class="tag">@done(2013-02-17)</span></span></li>
+<li><span class="task2">lepszy kod do html/print</span></li>
+<li><span class="task2">add to project from alfred</span></li>
+<li><span class="task2">clean code</span></li>
+<li><span class="task2">publikacja</span></li>
+<br>
+<li><span class="note2">_________________</span></li>
+<li><span class="project2">refaktoryzacja:</span>
+<ul><li><span class="task3">każdy item nie potrzebuje własnego?</span></li>
+<li><span class="task3">programowanie defensywne w do, tag</span></li>
+<br></ul></li></ul></li>
+<li><span class="project1">Tags alfred:</span>
+<ul><li><span class="task2">tests</span></li>
+<li><span class="task2">ulepszyć</span></li>
+<li><span class="task2">push</span></li>
+<br></ul></li>
+<li><span class="project1">kurs iOS:</span>
+<ul><li><span class="task2">skończyć wykład 2 <span class="tag">@next</span></span></li>
+<li><span class="task2">wykład 3</span></li>
+<li><span class="task2">wykład 4</span></li>
+<li><span class="task2">wykład 5</span></li></ul></li>
+<li><span class="project1">game dev:</span>
+<ul><li><span class="task2">mindmap <span class="tag">@next</span></span></li></ul></li>
+<li><span class="project1">ProcrastinationLog:</span>
+<ul><li><span class="project2">nowy projekt:</span>
+<ul><li><span class="task3">poczytać o projektowaniu responsywnych stron <span class="tag">@next</span></span></li>
+<li><span class="task3">zacząć implementować</span></li></ul></li></ul></li>
+<li><span class="project1">sprawdzić biblioteki pythona:</span>
+<ul><li><span class="task2">SQLAlchemy</span></li>
+<li><span class="task2">Pylons</span></li>
+<li><span class="task2">Mako</span></li>
+<li><span class="task2">lxml</span></li>
+<li><span class="task2">pymongo</span></li>
+<li><span class="task2">Twisted</span></li>
+<br></ul></li></ul></li>
+<li><span class="project0">Life:</span>
+<ul><li><span class="project1">zakupy w stanach?:</span>
+<ul><li><span class="task2">Podjąć decyzje <span class="tag">@due(2013-02-19)</span> <span class="tag">@next</span></span></li></ul></li>
+<li><span class="project1">nowe oczy:</span>
+<ul><li><span class="task2">poszukać sklepów internetowych z oprawkami <span class="tag">@next</span></span></li></ul></li>
+<li><span class="project1">wolniejszy internet:</span>
+<ul><li><span class="task2">przypmnieć o tym Matce <span class="tag">@next</span></span></li>
+<br>
+<br></ul></li></ul></li>
+<li><span class="note0">______________</span></li>
+<br>
+<li><span class="project0">Archive: <span class="tag">@done</span></span>
+<ul><li><span class="task1 done">wprowadzić plan nowego semestru do kalendarza <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">wybrać podręcznik -&gt; podręcznik - Implementing responsive… <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">http://www.tumblr.com/tagged/lumo%20suicide <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">kupic LaunchControl <span class="tag">@in(2013-02-14)</span> <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">wsadzić do plecaka podkladki na kibel <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="project1 done">uginające się półka: <span class="tag">@done</span> <span class="tag">@project(Life / uginające się półka)</span></span>
+<ul><li><span class="task2 done">obejrzeć ją, zobaczyć co da się zrobić - nic się nie da <span class="tag">@done(2013-02-15)</span></span></li></ul></li>
+<li><span class="project1 done">puderniczka dla Grażyny: <span class="tag">@done</span> <span class="tag">@project(Life / puderniczka dla Grażyny)</span></span>
+<ul><li><span class="task2 done">Są w rożnych cenach, matka sama musi wybrać cos <span class="tag">@done(2013-02-15)</span></span></li></ul></li>
+<li><span class="task1 done">znaleźć IPS do wypełnienia <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Studia / IPS)</span></span></li>
+<li><span class="task1 done">wypełnić IPS <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Studia / IPS)</span></span></li>
+<li><span class="task1 done">dodać ECTS za poprzedni semstr <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Studia / IPS)</span></span></li>
+<li><span class="task1 done">wydrukować <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Studia / IPS)</span></span></li>
+<li><span class="task1 done">znaleźć poprzednią wersję <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Studia / repodanie do wysmolka)</span></span></li>
+<li><span class="task1 done">połączyć w nową wersję <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Studia / repodanie do wysmolka)</span></span></li>
+<li><span class="task1 done">Research korpo z listy na papierze <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Studia / summer job)</span></span></li>
+<li><span class="project1 done">uporządkowanie rysunków: <span class="tag">@done(2013-02-15)</span> <span class="tag">@project(Life / uporządkowanie rysunków)</span></span>
+<ul><li><span class="task2 done">Skanowanie i tagowanie <span class="tag">@done(2013-02-15)</span></span></li>
+<li><span class="task2 done">Skanowac 5 kartek dziennie? <span class="tag">@done(2013-02-15)</span></span></li></ul></li>
+<li><span class="project1 done">nienawidzę stołu: <span class="tag">@done</span> <span class="tag">@project(Life / nienawidzę stołu)</span></span>
+<ul><li><span class="note2">nic nie da się z tym zrobić <span class="tag">@done</span></span></li>
+<li><span class="task2 done">pogadać z <span class="tag">@Matka</span> <span class="tag">@done(2013-02-15)</span></span></li>
+<li><span class="task2 done">pozbyć się kosza z rogu <span class="tag">@done(2013-02-15)</span></span></li>
+<li><span class="task2 done">pozbyć się leków ojca <span class="tag">@done(2013-02-15)</span></span></li></ul></li>
+<li><span class="project1 done">nienawidzę wieszaka na ubrania: <span class="tag">@done</span> <span class="tag">@project(Life / nienawidzę wieszaka na ubrania)</span></span>
+<ul><li><span class="note2">nic nie da się z tym zrobić <span class="tag">@done</span></span></li>
+<li><span class="task2 done">pogadać z <span class="tag">@Matka</span> <span class="tag">@done(2013-02-15)</span></span></li>
+<li><span class="task2 done">wywalić zbędne ciuchy <span class="tag">@done(2013-02-15)</span></span></li>
+<li><span class="task2 done">skonstruować ultimate wieszak <span class="tag">@done(2013-02-15)</span></span></li></ul></li>
+<li><span class="task1 done">dowiedzieć się jak ma na nazwisko przedstawiciel <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Life / openfinances)</span></span></li>
+<li><span class="task1 done">znaleźć numer telefonu <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Life / openfinances)</span></span></li>
+<li><span class="task1 done">Toggle next i today z done w sublime <span class="tag">@done(2013-02-14)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">Napisać do M$ <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">mindmap <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Studia / licencjat FUW)</span></span></li>
+<li><span class="task1 done">email to Agnieszka Bojanowska z pytaniem czy mogę <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Studia / Erazmus)</span></span></li>
+<li><span class="task1 done">wymyślić nastepny krok <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Studia / summer job)</span></span></li>
+<li><span class="task1 done">porysować <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Fiddling / ProcrastinationLog / nowy projekt)</span></span></li>
+<li><span class="task1 done">popatrzeć na ceny iPada i Maców <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Life / zakupy w stanach?)</span></span></li>
+<li><span class="task1 done">wymyślić jakiś system <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Life / uporządkowanie rysunków)</span></span></li>
+<li><span class="task1 done">zastanowić sie co z nim zrobić @next <span class="tag">@szpital</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Life / nienawidzę stołu)</span></span></li>
+<li><span class="task1 done">zastanowić sie co z tym zrobić <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Life / nienawidzę wieszaka na ubrania)</span></span></li>
+<li><span class="task1 done">allegro search <span class="tag">@szpital</span> <span class="tag">@next</span> <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Life / puderniczka dla Grażyny)</span></span></li>
+<li><span class="task1 done">obciąć pazury <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Szpital)</span></span></li>
+<li><span class="task1 done">spakować ubrania <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Szpital)</span></span>
+<ul><li><span class="task2 done">3 koszulki <span class="tag">@done(2013-02-10)</span></span></li>
+<li><span class="task2 done">3 boxerki <span class="tag">@done(2013-02-10)</span></span></li>
+<li><span class="task2 done">3 skarpetki <span class="tag">@done(2013-02-10)</span></span></li>
+<li><span class="task2 done">spodnie <span class="tag">@done(2013-02-10)</span></span></li></ul></li>
+<li><span class="task1 done">spakować kosmetyki <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Szpital)</span></span></li>
+<li><span class="task1 done">spkować krople <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Szpital)</span></span></li>
+<li><span class="task1 done">kubek i sztucce <span class="tag">@done(2013-02-11)</span> <span class="tag">@project(Szpital)</span></span></li>
+<li><span class="task1 done">spakować Servenon <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Szpital)</span></span></li>
+<li><span class="task1 done">spakować książki <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Szpital)</span></span></li>
+<li><span class="task1 done">spakować starego iPhone'a <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Szpital)</span></span>
+<ul><li><span class="task2 done">spakować słuchawki <span class="tag">@done(2013-02-10)</span></span></li>
+<li><span class="task2 done">spakować ładowarkę <span class="tag">@done(2013-02-10)</span></span></li></ul></li>
+<li><span class="project1 done">prezent dla ojca: <span class="tag">@due(2013-02-06)</span> <span class="tag">@done</span> <span class="tag">@project(Life / prezent dla ojca)</span></span></li>
+<li><span class="task1 done">tabletki <span class="tag">@today</span> <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Daily)</span></span></li>
+<li><span class="task1 done">10% <span class="tag">@today</span> <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Daily)</span></span></li>
+<li><span class="task1 done">Porządek w evernote <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">czy antydepresanty oglupiaja? <span class="tag">@today</span> <span class="tag">@ihit</span> <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">Czy mogę pic alkohol <span class="tag">@today</span> <span class="tag">@ihit</span> <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">IHiT <span class="tag">@today</span> <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">modern family s04e14 <span class="tag">@today</span> <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">laryngolog na Stępińskiej <span class="tag">@today</span> <span class="tag">@done(2013-02-07)</span> <span class="tag">@project(Single actions)</span></span></li>
+<li><span class="task1 done">mindmap <span class="tag">@next</span> <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">todo list moze sie konczyc koncem wejscia, nie tylko dedent <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">poprawne robienie Task, Note, Project <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">filtering <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span>
+<ul><li><span class="task2 done">project <span class="tag">@done(2013-02-10)</span></span></li></ul></li>
+<li><span class="task1 done">shallow copy <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">item by id <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">tagowanie <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span>
+<ul><li><span class="task2 done">tag done <span class="tag">@done(2013-02-10)</span></span></li></ul></li>
+<li><span class="task1 done">expand shortcuts <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">alfred xml <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">plain text <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">colored plain text <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">plain text with ids <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">countdown <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li>
+<li><span class="task1 done">task musi w podpisie miec projekt <span class="tag">@done(2013-02-10)</span> <span class="tag">@project(Fiddling / TodoFlow2)</span></span></li></ul></li></ul>
+</div>
+</body>
View
23 html/temp.html
@@ -0,0 +1,23 @@
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link href="index_card.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<div class="whole">
+ <ul><li><span class="project0">Daily:</span>
+<ul><li><span class="task1">12 <span class="tag">@today</span></span></li>
+<li><span class="task1">23 <span class="tag">@today</span></span></li>
+<li><span class="task1">podręcznik - Imp... responsive... <span class="tag">@today</span> <span class="tag">@blocker</span></span></li>
+<li><span class="task1">ulepszać fragment TodoFlow2 <span class="tag">@today</span></span></li>
+<li><span class="task1">nexts <span class="tag">@today</span></span></li></ul></li>
+<li><span class="project0">Single actions:</span>
+<ul><li><span class="task1">powrócić do today workflow <span class="tag">@today</span></span></li></ul></li>
+<li><span class="project0">Studia:</span>
+<ul><li><span class="project1">licencjat FUW:</span>
+<ul><li><span class="task2">nowa implementacja <span class="tag">@blocker</span></span>
+<ul><li><span class="task3">IsingModel <span class="tag">@today</span></span></li></ul></li></ul></li></ul></li>
+<li><span class="project0">Fiddling:</span>
+<ul><li><span class="project1">TodoFlow2: <span class="tag">@today</span></span>
+<ul><li><span class="task2">push na nowy branch w gitcie <span class="tag">@next</span> <span class="tag">@today</span></span></li></ul></li></ul></li></ul>
+</div>
+</body>
View
104 html/wider_card.css
@@ -0,0 +1,104 @@
+body {
+ width: 17cm;
+ border-left: 1px solid #D6D6D6;
+ color: black;
+ font-family: "Palatino" "Book Antiqua", serif;
+ font-size: 0.4cm;
+}
+
+.whole {
+ border-right: 0.5cm solid #D6D6D6;
+}
+
+ul{
+ display: table;
+ padding: 0;
+ margin-left: 0;
+ list-style-type: none;
+}
+
+li {
+ display: inline-block;
+ width: 17cm;
+ border-top: 1px dashed #838383;
+
+}
+
+.task0, .task1, .task2, .task3, .task4 {
+ display: inline-block;
+ margin-left: 0.5cm;
+ padding-right: 1cm;
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+}
+
+
+.note0, .note1, .note2, .note3, .note4{
+ display: table-cell;
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ font-style: italic;
+ padding-left: 0.2cm;
+
+}
+
+
+.project0, .project1, .project2, .project3, .project4 {
+ display: inline-block;
+ width: 5cm;
+ padding-right: 0.5cm;
+ padding-left: 0.5cm;
+ padding-top: 1em;
+ padding-bottom: 1em;
+ color: #262626;
+ font-family: "Futura" "Calibri" "Helvetica Neue" sans-serif;
+ font-weight: bold;
+}
+
+.project0 {
+ font-size: 1.0em;
+}
+
+.project1 {
+ font-size: 0.9em;
+}
+
+.project2 {
+ font-size: 0.8em;
+}
+
+.project3 {
+ font-size: 0.7em;
+}
+
+.project4 {
+ font-size: 0.6em;
+}
+
+
+.task1, .note1, .project1 {
+ padding-left: 0.5cm;
+}
+
+.task2, .note2, .project2 {
+ padding-left: 1.5cm;
+}
+
+.task3, .note3, .project3 {
+ padding-left: 2.5cm;
+}
+
+.task4, .note4, .project4 {
+ padding-left: 3.5cm;
+}
+
+.done {
+ color: #626262;
+ text-decoration: line-through;
+}
+
+.tag {
+ font-style: italic;
+ font-weight: normal;
+ color: #5F82FF;
+}
View
5 print_deadlines.py
@@ -0,0 +1,5 @@
+from todolist_parser import Parser
+
+t = Parser.from_file('/Users/bvsc/Dropbox/TODO/Projects.todo')
+s = t.as_countdown(colored=True).split('\n')[0:5]
+print '\n'.join(s)
View
9 print_today.py
@@ -0,0 +1,9 @@
+from todolist_parser import Parser
+
+t = Parser.from_file('/Users/bvsc/Dropbox/TODO/Projects.todo')
+today_not_done = t.filter('@today and not @done')
+today_not_done.remove_tag('today')
+print today_not_done.as_plain_text(colored=True, indent=False)
+# print ''
+# due = t.filter('@due and not @done')
+# print due.as_plain_text(colored=True, indent=False)
View
560 todolist.py
@@ -0,0 +1,560 @@
+import re
+from alfredlist import AlfredItemsXML
+from datetime import date
+from filterpredicate import predicate as compile_predicate
+
+
+class TodoList(object):
+ items_by_id = {}
+ current_id = 0
+
+ def __init__(self, items=None, set_new_parent=True):
+ self.items = items if items else []
+ if set_new_parent:
+ for item in self.items:
+ item.parent_list = self
+ self.surce = None
+
+ def to_file(self, path):
+ with open(path, 'w') as f:
+ f.write(self.as_plain_text(
+ colored=False,
+ with_ids=False,
+ indent=True
+ )
+ )
+
+ @classmethod
+ def assign_id(cls, item):
+ cls.items_by_id[cls.current_id] = item
+ cls.current_id += 1
+ return cls.current_id - 1
+
+ @staticmethod
+ def get_tag_param(text, tag):
+ match = re.search(' @' + tag + r"(\(([^\(\s]*)\)){0,1}(\s|$|\n)", text)
+ if match:
+ return match.group(2)
+ return None
+
+ @classmethod
+ def tag(cls, id_no, tag, param=None):
+ cls.items_by_id[id_no].tag(tag, param)
+
+ @classmethod
+ def do(cls, id_no):
+ date_after_done = True
+ cls.items_by_id[id_no].tag(
+ 'done',
+ date.today().isoformat() if date_after_done else None
+ )
+
+ @classmethod
+ def get_content(cls, id_no):
+ return cls.items_by_id[id_no].title.content
+
+ @classmethod
+ def remove(cls, id_no):
+ cls.items_by_id[id_no].remove_self_from_parent()
+
+ def filter(self, predicate):
+ if isinstance(predicate, str):
+ predicate = compile_predicate(predicate)
+ filtered_items = []
+ for item in self.items:
+ filtered_item = item.filter(predicate)
+ if filtered_item:
+ filtered_items.append(filtered_item)
+ new_list = TodoList(filtered_items)
+ return new_list
+
+ def as_plain_text(self, colored=False, with_ids=False, indent=True):
+ return "\n".join(item.as_plain_text(colored, with_ids, indent) for item in self.items)
+
+ def as_alfred_xml(self, include_projects=False, additional_arg=None):
+ al = AlfredItemsXML()
+ for item in self.items:
+ al_item = item.as_alfred_xml(include_projects, additional_arg)
+ if al_item:
+ al += al_item
+ return al
+
+ def as_countdown(self, colored=False):
+ today = date.today().isoformat()
+ only_due = self.filter('(@due and not @done) or (@due >=' + today + ')')
+ items = [item.as_countdown(colored) for item in only_due.items if item.as_countdown()]
+ items.sort()
+ return '\n'.join([item for item in items if item])
+
+ def as_markdown(self, done_emphasis=True):
+ items_md = "\n".join([item.as_markdown(done_emphasis) for item in self.items])
+ return items_md
+
+ def as_html(self):
+ items_html = "\n".join([item.as_html() for item in self.items])
+ return "<ul>" + items_html + "</ul>"
+
+ def as_full_html(self, css_style=None):
+ return """<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ {1}
+</head>
+<body>
+<div class="whole">
+ {0}
+</div>
+</body>""".format(
+ self.as_html(),
+ """<link href="{0}.css" rel="stylesheet" type="text/css" />""".format(css_style) if css_style else ''
+ )
+
+ def remove_item(self, item):
+ self.items.remove(item)
+
+ def add_parent(self, parent):
+ for item in self.items:
+ item.add_parent(parent)
+
+ def find_project_id_by_title(self, title):
+ filtered = self.filter('content = ' + title + ' and type ="project"')
+ for item in filtered.items:
+ if item.title.content == title:
+ return item.title._id
+ else:
+ if item.sub_tasks:
+ q = item.sub_tasks.find_project_id_by_title(title)
+ if q:
+ return q
+ return None
+
+ def remove_tag(self, tag):
+ for item in self.items:
+ item.remove_tag(tag)
+
+ def remove_done_from_parents(self):
+ for item in self.items:
+ if item.is_done():
+ print item.parent_list.as_plain_text()
+ item.remove_self_from_parent()
+ if item.sub_tasks: