/todo

To get this branch, use:
bzr branch http://bzr.ed.am/todo
1 by edam
init
1
#!/usr/bin/perl
2
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
3
use feature "state";
4
1 by edam
init
5
use strict;
6
use warnings;
7
use Getopt::Long;
8
use File::Basename;
9
10
# get app name
11
my $app_name = basename( $0 );
12
13
# option defaults
14
my $todo_dir = "~/.todo";
15
my $display_all = 0;
2 by edam
added default todo file content and changed main todo section name to "TODO"
16
my $display_section = "TODO";
1 by edam
init
17
my $display_headers = 0;
18
my $mode_edit = 0;
19
my $mode_help = 0;
20
my $mode_version = 0;
21
22
# parse command line opts
23
Getopt::Long::Configure( 'gnu_getopt' );
24
if( !GetOptions(
25
    'a|all' => \$display_all,
26
    'e|edit' => \$mode_edit,
27
    'h|headers' => \$display_headers,
7 by edam
made section selection case insensitive and added short option (-s) for it
28
    's|section=s' => \$display_section,
1 by edam
init
29
    'help' => \$mode_help,
30
    'version' => \$mode_version,
31
) ) {
32
    print "Try `$app_name --help' for more information.\n";
33
    exit( 1 );
34
}
35
36
# help mode
37
if( $mode_help ) {
38
    print "todo - display your todo file\n\n".
4 by edam
fixed spaces
39
    "Usage: $app_name [OPTIONS]\n\n".
40
    "Options:\n".
41
    "  -a, --all              display all sections\n".
42
    "  -e, --edit             edit your todo file\n".
43
    "  -h, --headers          show setion headers\n".
7 by edam
made section selection case insensitive and added short option (-s) for it
44
    "  -s, --section=SECTION  display this named section\n".
4 by edam
fixed spaces
45
    "      --help     display this help and exit\n".
46
    "      --version  output version information and exit\n";
1 by edam
init
47
    exit( 0 );
48
}
49
50
# version mode
51
if( $mode_version ) {
3 by edam
fixed version info and error about failing to start the editor
52
    print "todo 1.0\n".
4 by edam
fixed spaces
53
        "Copyright (C) 2011 Tim Marston.\n".
54
        "http://ed.am/software/todo\n";
1 by edam
init
55
    exit( 0 );
56
}
57
58
#_______________________________________________________________________________
59
60
61
# check we have bazaar installed
62
my $output = `which bzr`;
63
chomp $output;
64
$output eq "" and die "Bazaar is not installed";
65
66
# glob todo directory
67
$todo_dir = glob( $todo_dir );
68
( -f $todo_dir ) and die "$todo_dir exists and is a file";
69
70
# edit mode
71
if( $mode_edit )
72
{
73
    # create the todo directory, as necessary
4 by edam
fixed spaces
74
    if( ! -d $todo_dir ) {
75
        mkdir $todo_dir or die "couldn't create todo directory";
76
        `bzr init --no-aliases -q "$todo_dir"`;
77
        $? == 0 or die "couldn't init bzr repo";
78
    }
79
    
80
    # create a default todo file, as necessary
81
    if( ! -f "$todo_dir/todo" ) {
82
        open FILE, ">$todo_dir/todo" or die "couldn't create default todo file";
83
        my $content = <<"EOT";
2 by edam
added default todo file content and changed main todo section name to "TODO"
84
<!-- This file uses Markdown syntax. For more info about Markdown
85
     syntax, see http://daringfireball.net/projects/markdown/syntax.
86
87
     There should be a main H1 header called "TODO" for the main todo
88
     list section (one has been added for you below). You can also add
89
     as many more sections as you like for other lists. And feel free
90
     to delete this comment! -->
91
92
TODO
93
====
94
95
* make a list of things to do
96
97
EOT
98
        print FILE $content or die "couldn't write default todo file";
4 by edam
fixed spaces
99
        close FILE;
100
        `bzr add --no-aliases -q "$todo_dir/todo"`;
101
        $? == 0 or die "couldn't add todo file to bzr repo";
102
    }
1 by edam
init
103
104
    # determine editor from environment, default to "emacs -nw"
105
    my $editor = $ENV{ 'EDITOR' };
106
    defined $editor or $editor = 'emacs -nw';
107
    my @exec_array = split( / +/, $editor );
108
    push( @exec_array, "$todo_dir/todo" );
109
4 by edam
fixed spaces
110
    # detect emacs and try to use markdown-mode
111
    $exec_array[ 0 ] eq "emacs" and
112
        push( @exec_array, '--funcall=markdown-mode' );
1 by edam
init
113
114
    # edit todo file
115
    system( @exec_array );
4 by edam
fixed spaces
116
    $? == 0 or
117
        die "can't start editor, check EDITOR envionment variable";
118
119
    # check for changes and commit it
120
    $output = `bzr status --no-aliases "$todo_dir/todo"`;
121
    $? == 0 or die "couldn't check bzr rerpo status";
122
    chomp $output;
123
    if( $output ne "" ) {
124
        `bzr commit --no-aliases -q -m - "$todo_dir/todo"`;
125
        $? == 0 or die "couldn't commit to bzr repo";
126
    }
127
128
    # after editing, exit
129
    exit
1 by edam
init
130
}
131
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
132
# function to display a line
133
sub display_line
134
{
135
	my ( $line, $section ) = @_;
136
	state $old_section = '';
137
138
	# detect section change
139
	if( $section ne $old_section ) {
140
		$old_section = $section;
141
		
142
		# display section heading
143
		if( $display_headers || $display_all ) {
144
			print "$section\n".
145
				( "=" x length( $section ) )."\n";
146
		}
147
	}
148
149
	# replace tabs with 4 spaces
150
	$line =~ s/\t/    /g;
151
	
152
	# display the line
153
	print $line;
154
}
155
156
1 by edam
init
157
# scan through file
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
158
my $candidate_section = '';
1 by edam
init
159
my $section = '';
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
160
my $last_line = '';
1 by edam
init
161
open FILE, "<$todo_dir/todo" or die "can't open todo file";
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
162
while( <FILE> )
163
{
1 by edam
init
164
    # detect the line after section headings, and thus sections
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
165
    if( /^[-=]{2,}/ && $candidate_section ne '' ) {
166
        $section = $candidate_section;
167
        $candidate_section = '';
168
		$last_line = '';
169
		next;
1 by edam
init
170
    }
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
171
1 by edam
init
172
    # detect section headings
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
173
    if( /^[-_\.A-Za-z0-9 ]+$/ ) {
174
        $candidate_section = $_;
175
		chomp $candidate_section;
176
	}
1 by edam
init
177
    else {
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
178
        $candidate_section = '';
179
	}
180
181
	# display last line
182
	display_line( $last_line, $section ) if( $last_line ne '' );
183
184
    # display line
7 by edam
made section selection case insensitive and added short option (-s) for it
185
	if( ( lc( $section ) eq lc( $display_section ) ) ||
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
186
		( $section && $display_all ) )
187
	{
188
		$last_line = $_;
1 by edam
init
189
    }
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
190
	else {
191
		$last_line = '';
192
	}
1 by edam
init
193
}
6 by edam
rewrite file parsing to cache the last line and only display it when we know the current line is not a section heading "underline" line.
194
display_line( $last_line, $section ) if( $last_line ne '' );