A while back I created a TODO file to keep track of things I wanted to get done. This way I would not have to think about everything I wanted to do because it was noted somewhere. I had a cron job mail the file to me every morning at 7:00.

I thought about writing a tool to allow me to add and remove items. I realized that it would be easy to setup a shell alias to edit a file. I made it so I just had to type "todo" instead of "emacs ~/TODO". Eventually I shortened it to the single letter command "t".

After a while I noticed I wanted to be able to list the items without opening and exiting an editor. It would be reasonable to want to run "t -l" to list the file. That lead to the following script.

Update: Changed default editor and pager lines as Tanktalus suggested. "vi" and "more" are safer defaults. It is better to use well known environment variables than hard coded constants.

Update: Applied patch from idle to make the script run under Perl 5.005.

The usage message looks like:
[frink@truth:~]$ t -h usage: /home/frink/code/scripts/todo.pl [options] where [options] are: -e , --editor specify an alternate editor like "vi" -h , --help this usage message -l , --list list the file contents instead of editing -p , --pager specify an alternate pager program like "more" or "c +at" examples: todo.pl todo.pl -l todo.pl -e vi todo.pl -l -p head todo.pl -l -p cat todo.pl -l -p more todo.pl -l -p "mail -S \"TODO reminders\" me@domain.com"
#!/usr/bin/perl -w # # file: /home/frink/code/scripts/todo.pl # purpose: manage my TODO file. # # chad c d clark < email: frink-todo.pl *at* superfrink *dot* com > # created: 2005-03-26 # updated: 2006-01-24 added -e , -h , -l , -p # $Id$ use strict; use Getopt::Long; sub list_file($); sub usage_mesage(); # -- set the global settings -- my %G; $G{editor} = $ENV{EDITOR} || "vi"; # editor to use $G{list_only} = 0; # dump file contents $G{list_pager} = $ENV{PAGER} || "more"; # output pager program $G{todo_file} = "/home/chad/TODO"; # TODO file $G{usage_only} = 0; # display usage message # -- get the command line args -- GetOptions ("e|editor=s" => \$G{editor}, "h|help" => \$G{usage_only}, "l|list" => \$G{list_only}, "p|pager=s" => \$G{list_pager}) or die("Problem with command line options. $!\n"); # -- now take the requested action -- # if a usage message was requested print one and exit if($G{usage_only}) { usage_mesage(); exit(0); } # if a contents list was requested then list the file and exit if($G{list_only}) { list_file($G{todo_file}); exit(0); } # -- if we get here we need to open the file for editing -- # make sure the file exists. unless(-e $G{todo_file}) { `touch $G{todo_file}`; } # open the file for editing. my $cmd = "$G{editor} $G{todo_file}"; print $cmd, "\n"; exec $cmd; # -- we should never get here -- die("$0 : exec($cmd) failed. $!\n"); # -- subroutines ---------------------------------------------------- sub usage_mesage() { # try to get a shorter version of the current program name. # (some people might not have File::Basename.) my $me = $0; if ($0 =~ m/^(.*\/)(.*)$/) { $me = $2; } print qq{ usage: $0 [options] where [options] are: -e , --editor specify an alternate editor like "vi" -h , --help this usage message -l , --list list the file contents instead of editing -p , --pager specify an alternate pager program like "more" or "c +at" examples: $me $me -l $me -e vi $me -l -p head $me -l -p cat $me -l -p more $me -l -p "mail -S \\\"TODO reminders\\\" me\@domain.com" }; } sub list_file($) { # purpose: dump the file using an optional pager program # globals used: # $G{list_pager} - pager program, eg "less" or "cat" my $fname = shift; unless ($fname) { die ("No file specified.\n"); } unless (-e $fname) { die ("File does not exist '$fname'.\n"); } unless (-r $fname) { die ("File is not readable '$fname'.\n"); } # open the input file open FH , "<$fname" or die("Unable to open file '$fname'. $!\n"); # if there is a pager program then use it if($G{list_pager}) { open PAGER , "| $G{list_pager}" or die("Unable to open file '$G{list_pager}'. $!\n"); while(<FH>) { print PAGER; } close PAGER; # else there is no pager program so just print the file contents } else { while(<FH>) { print; } } # close the input file close FH; }

Replies are listed 'Best First'.
Re: Tool for editing / viewing a TODO file.
by Tanktalus (Canon) on Jan 25, 2006 at 15:05 UTC

    A couple minor points.

    $G{editor} = "emacs"; # editor to use $G{list_pager} = "less"; # output pager program
    Both of these have existing unixy conventions. I would suggest a minor change:
    $G{editor} = $ENV{EDITOR} || "vi"; # editor to use $G{list_pager} = $ENV{PAGER} || "more"; # output pager program
    These follow unixy convention. That is, if EDITOR is not set, vi is supposed to be the fallback default for editor, while if PAGER is not set, more is supposed to be the fallback default for the pager. Since you probably should have these variables set to emacs and less, respectively, in your own environment for use with other programs anyway, this shouldn't actually affect your program's operation on your machine.

    Further, you can completely get rid of the commandline options using a little shell trick:

    $ PAGER="mail -S \"TODO reminders\" me@domain.com" t -l
    or
    $ EDITOR= t -e
    to use vi. This trick just sets an environment variable (that is exported) but resets it back to what it was, after the command is finished, leaving it unchanged in the parent process.

    With these minor changes, your program feels more part of the unix world, making it operate just like everything else. For example, if you have sudo set up, try "sudo -e /etc/inittab" - it will use your current EDITOR environment variable to launch an editor to modify the inittab. Or "crontab -e" - launches the same editor to modify your crontab entries. So why not "t -e"? :-)

    To be honest, when I saw the CUFP on the Newest Nodes page, I thought there would be a "-a" (add) option and a "-r" option which would allow easy/fast ability to modify standard TODO files (such as one might find in module distributions). That would be really handy ;-)

      when I saw the CUFP on the Newest Nodes page, I thought there would be a "-a" (add) option and a "-r" option which would allow easy/fast ability to modify standard TODO files

      That would be useful! I did not add those two arguments simply because my own TODO file has several sections (ASAP, Work, Projects, etc). I have emacs lisp to renumber the lines in a section. I would have to give the Perl script -section and -number arguments.

      It could all be done but for now this seems to work well enough. :)

      Update: Or "crontab -e" - launches the same editor to modify your crontab entries. So why not "t -e"?
      I am more likely to be adding an item or keeping the editor open in a window while I remove things from the list than I am to be viewing the it.
Re: Tool for editing / viewing a TODO file.
by adrianh (Chancellor) on Jan 25, 2006 at 11:52 UTC

    Not quite the same thing, but you might find Andy's App::HWD of interest.

      Nice thingy, I would place it in my ~/.login script. The only note, its doesn't work with perl 5.005, because there is no open mode '|-' and open may have only one parameter. Here is the diff.
      < open FH , "<" , $fname or die("Unable to open file '$fname'. $! +\n"); > open FH , "<$fname" or die("Unable to open file '$fname'. $!\n" +); 102c101 < open PAGER , "|-" , $G{list_pager} > open PAGER , "| $G{list_pager}"