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 '' ); |