Poojan (Wagh) Blog

Requests for comment

GTD with Python, git, vim, and asciidoc

without comments

I recently detailed the high-level setup of my latest GTD roll out. This follow-up post has a high “geek factor” and contains the details of how I do this using computer automation (Python scripts).

When I process my inboxes, I write one line per task in one of two text files (gtd-work.txt, gtd-personal.txt—heretofore referred to as gtd-x). The format is:

[project] | task | @context

This format handles both individual tasks (not attached to a “project”) and multi-step projects. I wrote a small python script that parses these files and spits out one file called context.txt that has these tasks sorted by context.

Blog about python GTD setup | Find 1st version of python script & save on desktop | @HomeComputer
Do laundry | @Home

The context file would contain:

@HomeComputer
Blog about python GTD setup | Find 1st version of python script & save on desktop | @HomeComputer

@Home
Do laundry | @Home

You’ll notice that the context (@Home for example) is redundant. I didn’t care too much: the script organizes things the way I want it (by context) and gets things done.

Since I use the text editor vim, the python script also creates a tags file that links entries in the context.txt file back to my two gtd-x files.

Here’s the Python script:

import re
import hashlib

gtdfiles = ["gtd-personal.txt", "gtd-work.txt"]

def writeTags(dictTags, fout):
   keys = list(dictTags.keys())
   keys.sort()
   for k in keys:
      print(k + "\t" + dictTags[k]['file'] + "\t" + str(dictTags[k]['line']), file=fout)

def formatCtxLine(actionLine, lineHash):
   return line.strip() + "\n// " + lineHash

reContext = re.compile(r'@\w+')
dictContext = {}
dictTags = {}


for gtdf in gtdfiles:
   fin = open(gtdf, 'r')

   lineno = 0
   for line in fin:
      lineno += 1
      print(line)
      lContexts = reContext.findall(line)
      for sCtx in lContexts:                  
         lineHash = hashlib.md5(line.encode()).hexdigest()
         dictTags[lineHash] = dict(file=gtdf, line=lineno)
         if sCtx in dictContext:            
            dictContext[sCtx].append(formatCtxLine(line, lineHash))
         else:
            dictContext[sCtx] = [formatCtxLine(line, lineHash)]
            
   fin.close()

ftags = open("tags", 'w')
writeTags(dictTags, ftags)
ftags.close()

fout = open("context.txt", 'w')

for k,v in dictContext.items():
   print("", file=fout)
   #print("<<<", file=fout)
   print("", file=fout)
   print('*' + k + '*', file=fout)
   print('', file=fout)

   for na in v:
      print('-  ' + na, file=fout)

print("", file=fout)
print("", file=fout)
print("//    vim:set readonly", file=fout)
fout.close()

I sync the gtd-x, context, tags, and python files using git. (I started with Mercurial (Hg), switched to git, and recently am thinking of switching back due to better Windows support from Hg—except I’ve declared an indefinite moratorium on changing things.)

I also keep one big text file that logs what I’m up to (when I feel like logging what I’m up to). I have the python script search that file, too, so I can embed a to-do in the file wherever I want.

All files are in asciidoc format, so I can generate good-looking HTML without sacrificing the speed of editing with VIM. I have two key macros mapped in vim: \gt runs the python script above and \go runs ASCIIDOC to generate the HTML, so I don’t need to leave the editor to see updates to what I’m doing.

Written by PoojanWagh

June 1st, 2009 at 8:19 am

Leave a Reply