summaryrefslogtreecommitdiff
path: root/p/todo/todo.pl
blob: 31e55da788ede68ae91f2c48ac0912a9e61d79c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/perl -w
#
# Tool to parse todo files.
#
use strict;

# Parse a todo file and add tasks to \%todos.
sub parse_todo
{
    my ($todos, $path, $file) = @_;
    my $owner;
    local $_;
    local *FILE;
    # Check for duplicates and create task list.
    die "duplicate path: $path" if exists $$todos{''};
    $$todos{''} = [ ];
    my $tasks = $$todos{''};
    # Open file.
    open FILE, "<$file" or die "$file: $!";
    # Read each lines.
    while (<FILE>)
    {
	chomp;
	# Task line.
	/^([-+=x]) (?:\(([^)]+)\) |)(.+)$/ and do {
	    my ($state, $owner, $text) = ($1, $2 || $owner, $3);
	    #$owner = $1 if $2 =~ /^\((.*)\) $/;
	    my @owners = split /, */, $owner;
	    # Read next lines.
	    while (<FILE>)
	    {
		chomp;
		# Continued task, new paragraph.
		/^  $/ and $text .= "\n", next;
		# Continued task.
		/^  (.*)$/ and $text .= ' ' . $1, next;
		last;
	    }
	    # Add task.
	    push @$tasks, {
		state => $state,
		owner => [ @owners ],
		text => $text
	    };
	    last unless defined $_;
	    redo;
	};
	# Default owner line.
	/^\(([^)]+)\)$/ and $owner = $1, next;
	# Subtask line.
	/^[-\w\d]+$/ and do {
	    my $path = $path . '/' . $_;
	    $$todos{$_} ||= { };
	    my $todos = $$todos{$_};
	    die "duplicate path: $path" if exists $$todos{''};
	    $$todos{''} = [ ];
	    $tasks = $$todos{''};
	    next;
	};
	# Empty line.
	/^$/ and next;
	# Else, die.
	die 'Invalid format';
    }
    # Close file.
    close FILE;
}

# Read dir and parse each todo files it contains.
sub parse_dir
{
    my ($todos, $path, $dir) = @_;
    local $_;
    local @_;
    local *DIR;
    # Read files list.
    opendir DIR, $dir or die "$dir: $!";
    @_ = readdir DIR;
    closedir DIR;
    # Filter todo files & dirs lists.
    my @todofiles = grep { !/^\./ && /\.todo$/ && -f "$dir/$_" } @_;
    s/\.todo$// foreach @todofiles;
    my @tododirs = grep { !/^\./ && -d "$dir/$_" } @_;
    # Create empty hashes.
    $$todos{$_} ||= { } foreach @todofiles, @tododirs;
    # Process each todo files.
    parse_todo ($$todos{$_}, "$path/$_", "$dir/$_.todo") foreach @todofiles;
    # Recurse into each dirs.
    parse_dir ($$todos{$_}, "$path/$_", "$dir/$_") foreach @tododirs;
}

my %todos;

parse_dir (\%todos, '', '.');

{
    use Data::Dumper;
    print Dumper \%todos;
}