vendredi 29 mai 2015

Sorting todo.txt lines by its properties

I'm after a simple code to organize my todo.txt that has Gina Trapani's syntax, that is contexts are preceded by @, projects by +, priorities are marked by (A), (B) etc.. A task can have multiple contexts and projects.

What I would like to achieve is to first sort the lines by context and in the block of a contexts lines should be ordered by projects and lines with priorities comes first in the project.

My code until now:

import os
import sys
import re

# Configuration
todo_path = notepad.getCurrentFilename()

def ordered_set(inlist):
    out_list = []
    for val in inlist:
        if not val in out_list:
            out_list.append(val)
    return out_list

class Todo:
    def __init__(self, priority, context, project, due, task, cdate):
        self.__priority = priority
        self.__context = context
        self.__project = project
        self.__due = due
        self.__task = task
        self.__cdate = cdate

    def __len__(self):
     return len(str(re.sub(' +',' ',str(self.__priority) +' '+' '.join(self.__context) + ' ' + ' '.join(self.__project) + ' ' + str(self.__due) + ' ' + str(self.__task) + ' ' + str(self.__cdate) + '\n')))

    def priority(self):
        return self.__priority

    def context(self):
        return self.__context

    def project(self):
        return self.__project

    def due(self):
        return self.__due

    def task(self):
        return self.__task

    def cdate(self):
        return self.__cdate

def BuildTodos():
 global todos
 todo_file = open(todo_path, 'r')
 raw_todos = todo_file.readlines()
 todo_file.close()
 todos = []

 for item in raw_todos:
  item = item.strip("\n")
  todos.append(item)
 console.write("Loaded Todos\n")
 for idx, item in enumerate(todos):  
  words = item.split(' ')  
  priority = [word for word in words if re.match('^\([A-Z]\)',word)]
  context = [word for word in words if word.startswith('@')]  
  project = [word for word in words if word.startswith('+')]  
  due = [word for word in words if word.startswith('due:')]  
  task = [word for word in words if not re.match('^\([A-Z]\)',word) and not word.startswith('@') and not word.startswith('+') and not word.startswith('due:') and not re.match('[0-9]{4}-[0-9]{2}-[0-9]{2}',word)]  
  cdate = [word for word in words if re.match('[0-9]{4}-[0-9]{2}-[0-9]{2}',word)]
  todos[idx] = Todo(priority, context, project, due, task, cdate)
 console.write("Built Todos\n")
 todos.sort(key=lambda t: t.context())
# ----------------
# HELP NEEDED HERE
# sort the lines by context and within the block of contexts lines  should be
# ordered by projects and lines with priorities comes first in the project.
# ---------------- 

def OutTodos():
 for t in todos:
    console.write(re.sub(' +',' ',' '.join(t.priority()) + ' ' + ' '.join(t.context()) + ' ' + ' '.join(t.project()) + ' ' + ' '.join(t.due()) + ' ' + ' '.join(t.task()) + ' ' + ' '.join(t.cdate()) + '\n'))

console.clear()
BuildTodos()
OutTodos()

Example todo.txt file, contains utf-8 characters (!):

(A) @personal +study +python organize todo.txt áőúíéá
(A) Schedule annual checkup +Health áőúíéá
(B) Outline chapter 5 +Novel @Computer áőúíéá
(C) Add cover sheets @Office +TPSReports áőúíéá
Plan backyard herb garden @Home áőúíéá
Pick up milk @GroceryStore áőúíéá
Research self-publishing services +Novel @Computer áőúíéá
Download Todo.txt mobile app @Phone áőúíéá

I'm squeezing my mind on how to construct this sorting so to not end up with a monster. My guess would be to iterate on the todos list and have cascading ifs but not having any experience in sorting/list manipulations in python I'm out for advices.

Aucun commentaire:

Enregistrer un commentaire