/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,
9 by edam
detect extra arguments and extend --help message
31
) || @ARGV > 0 ) {
1 by edam
init
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".
9 by edam
detect extra arguments and extend --help message
39
	#01234567890123456789012345678901234567890123456789012345678901234567890123456789
4 by edam
fixed spaces
40
    "Usage: $app_name [OPTIONS]\n\n".
41
    "Options:\n".
42
    "  -a, --all              display all sections\n".
43
    "  -e, --edit             edit your todo file\n".
44
    "  -h, --headers          show setion headers\n".
9 by edam
detect extra arguments and extend --help message
45
    "  -s, --section=SECTION  display sections matching the regular expression\n".
4 by edam
fixed spaces
46
    "      --help     display this help and exit\n".
8 by edam
added --list
47
    "      --version  output version information and exit\n".
48
	"\n".
9 by edam
detect extra arguments and extend --help message
49
	"Running without any options is the same as running with --section=TODO and\n".
50
	"lists the default section of the todo file.\n".
51
	"\n".
10 by edam
removed --list option because it was confusing and unnecessary
52
	"The environment variables EDITOR is used.\n".
8 by edam
added --list
53
	"\n".
54
	"Please report bugs to Tim Marston <tim\@ed.am>.\n";
1 by edam
init
55
    exit( 0 );
56
}
57
58
# version mode
59
if( $mode_version ) {
3 by edam
fixed version info and error about failing to start the editor
60
    print "todo 1.0\n".
8 by edam
added --list
61
        "Copyright (C) 2011, 2012 Tim Marston.\n".
4 by edam
fixed spaces
62
        "http://ed.am/software/todo\n";
1 by edam
init
63
    exit( 0 );
64
}
65
66
#_______________________________________________________________________________
67
68
69
# check we have bazaar installed
70
my $output = `which bzr`;
71
chomp $output;
72
$output eq "" and die "Bazaar is not installed";
73
74
# glob todo directory
75
$todo_dir = glob( $todo_dir );
76
( -f $todo_dir ) and die "$todo_dir exists and is a file";
77
78
# edit mode
79
if( $mode_edit )
80
{
81
    # create the todo directory, as necessary
4 by edam
fixed spaces
82
    if( ! -d $todo_dir ) {
83
        mkdir $todo_dir or die "couldn't create todo directory";
84
        `bzr init --no-aliases -q "$todo_dir"`;
85
        $? == 0 or die "couldn't init bzr repo";
86
    }
87
    
88
    # create a default todo file, as necessary
89
    if( ! -f "$todo_dir/todo" ) {
90
        open FILE, ">$todo_dir/todo" or die "couldn't create default todo file";
91
        my $content = <<"EOT";
2 by edam
added default todo file content and changed main todo section name to "TODO"
92
<!-- This file uses Markdown syntax. For more info about Markdown
93
     syntax, see http://daringfireball.net/projects/markdown/syntax.
94
95
     There should be a main H1 header called "TODO" for the main todo
96
     list section (one has been added for you below). You can also add
97
     as many more sections as you like for other lists. And feel free
98
     to delete this comment! -->
99
100
TODO
101
====
102
103
* make a list of things to do
104
105
EOT
106
        print FILE $content or die "couldn't write default todo file";
4 by edam
fixed spaces
107
        close FILE;
108
        `bzr add --no-aliases -q "$todo_dir/todo"`;
109
        $? == 0 or die "couldn't add todo file to bzr repo";
110
    }
1 by edam
init
111
112
    # determine editor from environment, default to "emacs -nw"
8 by edam
added --list
113
	my $editor;
10 by edam
removed --list option because it was confusing and unnecessary
114
	$editor = $ENV{ 'EDITOR' };
115
	defined $editor or $editor = 'emacs -nw';
1 by edam
init
116
    my @exec_array = split( / +/, $editor );
117
    push( @exec_array, "$todo_dir/todo" );
118
4 by edam
fixed spaces
119
    # detect emacs and try to use markdown-mode
120
    $exec_array[ 0 ] eq "emacs" and
121
        push( @exec_array, '--funcall=markdown-mode' );
1 by edam
init
122
123
    # edit todo file
124
    system( @exec_array );
4 by edam
fixed spaces
125
    $? == 0 or
126
        die "can't start editor, check EDITOR envionment variable";
127
128
    # check for changes and commit it
129
    $output = `bzr status --no-aliases "$todo_dir/todo"`;
130
    $? == 0 or die "couldn't check bzr rerpo status";
131
    chomp $output;
132
    if( $output ne "" ) {
133
        `bzr commit --no-aliases -q -m - "$todo_dir/todo"`;
134
        $? == 0 or die "couldn't commit to bzr repo";
135
    }
136
137
    # after editing, exit
138
    exit
1 by edam
init
139
}
140
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.
141
# function to display a line
142
sub display_line
143
{
144
	my ( $line, $section ) = @_;
145
	state $old_section = '';
146
147
	# detect section change
148
	if( $section ne $old_section ) {
149
		$old_section = $section;
150
		
151
		# display section heading
152
		if( $display_headers || $display_all ) {
153
			print "$section\n".
154
				( "=" x length( $section ) )."\n";
155
		}
156
	}
157
158
	# replace tabs with 4 spaces
159
	$line =~ s/\t/    /g;
160
	
161
	# display the line
162
	print $line;
163
}
164
165
1 by edam
init
166
# 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.
167
my $candidate_section = '';
1 by edam
init
168
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.
169
my $last_line = '';
1 by edam
init
170
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.
171
while( <FILE> )
172
{
1 by edam
init
173
    # 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.
174
    if( /^[-=]{2,}/ && $candidate_section ne '' ) {
175
        $section = $candidate_section;
176
        $candidate_section = '';
177
		$last_line = '';
178
		next;
1 by edam
init
179
    }
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.
180
1 by edam
init
181
    # 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.
182
    if( /^[-_\.A-Za-z0-9 ]+$/ ) {
183
        $candidate_section = $_;
184
		chomp $candidate_section;
185
	}
1 by edam
init
186
    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.
187
        $candidate_section = '';
188
	}
189
190
	# display last line
191
	display_line( $last_line, $section ) if( $last_line ne '' );
192
193
    # display line
7 by edam
made section selection case insensitive and added short option (-s) for it
194
	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.
195
		( $section && $display_all ) )
196
	{
197
		$last_line = $_;
1 by edam
init
198
    }
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.
199
	else {
200
		$last_line = '';
201
	}
1 by edam
init
202
}
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.
203
display_line( $last_line, $section ) if( $last_line ne '' );