[Vimoutliner] VimOutliner as a task manager? - thescript
Fredrik
fredrik at jumans.net
Sat Nov 3 05:52:27 EST 2007
I might as well attach my script here... First I add some shortcutkeys
to it in my .vimrc as this :
" GTD stuff
map gp :%!/<path>/groupby.pl project<CR>
map gc :%!/<path>/groupby.pl context<CR>
Below follows the whole script. Bare in mind that this is a betascript
so I have added something that creates a copy of the file that is edited
before regrouping so you need to change paths etc :
#!/usr/bin/perl -W
use strict;
use Data::Dumper;
my %in;
my %projects;
my %contexts;
# Help sort to sort pos
sub possort { # {{{1
my @a = split (/\./, $a); my @b = split (/\./, $b);
my $min = $#a;
if ($#b < $#a) {$min = $#b}
my $result=0;
for (my $c=0; $c <= $min; $c++) {
if ($a[$c] > $b[$c]) {$result = 1; last}
elsif ($a[$c] < $b[$c]) {$result = -1; last}
}
if ($result == 0) {
if ($#a < $#b) {$result = -1}
elsif ($#a > $#b) {$result = 1}
}
return $result;
} # }}}1
# Count tabs at beginning of line
sub ctabs { # {{{1
my ($t) = @_;
my @t = split (//, $t);
my $c=0;
while ($t[$c] eq "\t") {$c++}
return $c;
} #}}}1
# Create full projectname based on position
sub fullprojectname { # {{{1
my ($pos) = @_;
my $name = $in{$pos}{"text"};
while ($pos =~ /\./) {
$pos =~ s/\.\d*?$//;
$name = $in{$pos}{"text"}.":$name";
}
return $name;
} # }}}1
# Take a projectstring and break it apart
sub addfullproject { # {{{1
my ($project) = @_;
if (!defined $projects{$project}) {$projects{$project} = ""}
while ($project =~ /\:/) {
my @p = split (/\:/, $project);
pop @p; $project = join (":", @p);
if (!defined $projects{$project}) {$projects{$project} =
""}
}
} # }}}1
# Parse projectline to datastructure
sub parseproject { # {{{1
my ($pos, $lc, $line) = @_;
my %data;
$line =~ s/.*\% //;
$in{$pos}{"type"} = "P";
$in{$pos}{"text"} = $line;
$projects{&fullprojectname($pos)} = $pos;
} # }}}1
# Parse contextline to datastructure
sub parsecontext { # {{{1
my ($pos, $lc, $line) = @_;
if ($pos =~ /\./) {
print "Context at line $lc must be a root object\n";
exit;
}
$line =~ s/\@//;
$in{$pos}{"type"} = "C";
$in{$pos}{"text"} = $line;
$contexts{$line} = $pos;
} # }}}1
# Parse miscline to datastructure
sub parsemisc { # {{{1
my ($pos, $lc, $line) = @_;
if ($pos !~ /\./) {
print "Misc at line $lc can not be a root object\n";
exit;
}
$in{$pos}{"type"} = "M";
$in{$pos}{"text"} = $line
} # }}}1
# Parse taskline to datastructure
sub parsetask { # {{{1
my ($pos, $lc, $line) = @_;
$in{$pos}{"type"} = "T";
$in{$pos}{"status"} = "";
if ($line =~ /^\[.\] /) {
$in{$pos}{"status"} = $line;
$in{$pos}{"status"} =~ s/.*\[//;
$in{$pos}{"status"} =~ s/\].*//;
$line =~ s/.*\] //;
}
if ($line =~ / \{.*\}$/) {
$in{$pos}{"project"} = $line;
$in{$pos}{"project"} =~ s/.*\{//;
$in{$pos}{"project"} =~ s/\}.*//;
&addfullproject ($in{$pos}{"project"});
$line =~ s/ \{.*//;
} else {
my $tmppos = $pos; $tmppos =~ s/\.\d*?$//;
$in{$pos}{"project"} = &fullprojectname($tmppos);
}
if ($line =~ / \@/) {
$in{$pos}{"context"} = $line;
$in{$pos}{"context"} =~ s/.* \@//;
if (!defined $contexts{$in{$pos}{"context"}}) {
$contexts{$in{$pos}{"context"}} = "";
}
$line =~ s/ \@.*$//;
} else {
my $tmppos = $pos; $tmppos =~ s/\.\d*?$//;
$in{$pos}{"context"} = $in{$tmppos}{"text"};
}
$in{$pos}{"text"} = $line;
} # }}}1
# Convert lines to hash by type
sub parseline { # {{{1
my ($pos, $lc, $line) = @_;
$line =~ s/[\n\r]//g;
$line =~ s/^\s*//; $line =~ s/\s*$//;
if ($line =~ / \@.*$/) {&parsetask($pos,$lc,$line)}
elsif ($line =~ / \{.*\}/) {&parsetask($pos,$lc,$line)}
elsif ($line =~ /^\[.\] \d*% /) {&parseproject($pos,$lc,$line)}
elsif ($line =~ /^\@/) {&parsecontext($pos,$lc,$line)}
else {&parsemisc($pos,$lc,$line)}
} # }}}1
# Read stdin and parse lines to data
sub readstdin { # {{{1
my @pos;
my $lc=0;
my $date = `date +"%Y%m%d%H%M%S"`; $date =~ s/[\n\r]//;
open (FILE, ">/<path>/.backup-".$date) or die "No backup!";
while (<STDIN>) {
$lc++;
print FILE $_;
if (/^\s*$/) {next} # Skip blank lines
# Create current position
my $ctabs = &ctabs($_);
if ($ctabs > $#pos) {push (@pos, 0)}
elsif ($ctabs < $#pos) {
while ($ctabs < $#pos) {pop @pos}
$pos[$#pos]++;
} else {$pos[$#pos]++}
# Clean up line a bit
$_ =~ s/[\n\r]//g;
$_ =~ s/^\s*//; $_ =~ s/\s*$//;
&parseline(join(".", @pos), $lc, $_);
}
close (FILE);
} #}}}1
# Go trough all %in and find tasks
sub findtask { # {{{{1
my ($context, $project, $status) = @_;
my @found;
foreach my $pos (sort possort keys %in) {
if ($in{$pos}{"type"} eq "T") {
if ($in{$pos}{"status"} eq $status) {
if ($context ne "" ) {
if ($in{$pos}{"context"} eq
$context) {
push (@found, $pos);
}
} else {
if ($in{$pos}{"project"} eq
$project) {
push (@found, $pos);
}
}
}
}
}
return (@found);
} # }}}1
# Go through all of %in and find misc lines
sub findmisc { # {{{1
my ($parent) = @_;
my @found;
foreach my $pos (sort possort keys %in) {
if ($pos =~ /^$parent\.\d*$/) {
if ($in{$pos}{"type"} eq "M") {
push (@found, $pos);
}
}
}
return (@found);
} # }}}1
# Print context view
sub printcontextview { # {{{1
foreach my $context (sort keys %contexts) {
my @activetasks = &findtask ($context,"","_");
my @passivetasks = &findtask ($context,"","");
if (($#activetasks >= 0) || ($#passivetasks >= 0)) {
print "\@$context\n";
}
# Print active tasks
foreach my $taskpos (@activetasks) {
print "\t[_] ".$in{$taskpos}{"text"};
print " {".$in{$taskpos}{"project"}."}\n";
foreach my $miscpos (&findmisc ($taskpos)) {
print "\t\t".$in{$miscpos}{"text"}."\n";
}
}
# Print passive tasks
foreach my $taskpos (@passivetasks) {
print "\t".$in{$taskpos}{"text"};
print " {".$in{$taskpos}{"project"}."}\n";
foreach my $miscpos (&findmisc ($taskpos)) {
print "\t\t".$in{$miscpos}{"text"}."\n";
}
}
if (($#activetasks >= 0) || ($#passivetasks >= 0)) {
print "\n";
}
}
# Print projects
foreach my $proj (sort keys %projects) {
my $tabs = $proj;
$tabs =~ s/[^\:]//g;
$tabs =~ s/\:/\t/g;
my $short = $proj;
$short =~ s/.*\://;
print $tabs."[_] % ".$short."\n";
if ($projects{$proj} ne "") {
# Print project comments
foreach my $miscpos (&findmisc
($projects{$proj})) {
print
$tabs."\t".$in{$miscpos}{"text"}."\n";
}
# Print finished tasks
foreach my $taskpos (&findtask ("",$proj,"X")) {
print $tabs."\t[X]
".$in{$taskpos}{"text"};
print "
\@".$in{$taskpos}{"context"}."\n";
foreach my $miscpos (&findmisc
($taskpos)) {
print
$tabs."\t\t".$in{$miscpos}{"text"}."\n";
}
}
}
}
} # }}}1
# Print the projectview
sub printprojectview { # {{{1
foreach my $proj (sort keys %projects) {
my $tabs = $proj;
$tabs =~ s/[^\:]//g;
$tabs =~ s/\:/\t/g;
my $short = $proj;
$short =~ s/.*\://;
print $tabs."[_] % ".$short."\n";
# Print project comments
foreach my $miscpos (&findmisc ($projects{$proj})) {
print $tabs."\t".$in{$miscpos}{"text"}."\n";
}
# Print passive tasks
foreach my $taskpos (&findtask ("",$proj,"")) {
print $tabs."\t".$in{$taskpos}{"text"};
print " \@".$in{$taskpos}{"context"}."\n";
foreach my $miscpos (&findmisc ($taskpos)) {
print
$tabs."\t\t".$in{$miscpos}{"text"}."\n";
}
}
# Print active tasks
foreach my $taskpos (&findtask ("",$proj,"_")) {
print $tabs."\t[_] ".$in{$taskpos}{"text"};
print " \@".$in{$taskpos}{"context"}."\n";
foreach my $miscpos (&findmisc ($taskpos)) {
print
$tabs."\t\t".$in{$miscpos}{"text"}."\n";
}
}
# Print finished tasks
foreach my $taskpos (&findtask ("",$proj,"X")) {
print $tabs."\t[X] ".$in{$taskpos}{"text"};
print " \@".$in{$taskpos}{"context"}."\n";
foreach my $miscpos (&findmisc ($taskpos)) {
print
$tabs."\t\t".$in{$miscpos}{"text"}."\n";
}
}
}
} # }}}1
# ----- MAIN -----
if ($#ARGV != 0) {
print "Not enough command line parameters!\n";
exit;
}
&readstdin;
if ($ARGV[0] eq "project") {
&printprojectview;
} else {
&printcontextview;
}
#print Dumper(%in);
#foreach my $key (sort keys %contexts) {
#print $key."\n";
#}
# vim600: set foldlevel=0 foldmethod=marker:
More information about the VimOutliner
mailing list