summaryrefslogtreecommitdiffstats
path: root/lib/App/Hiveminder/Utils.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/App/Hiveminder/Utils.pm')
-rw-r--r--lib/App/Hiveminder/Utils.pm173
1 files changed, 173 insertions, 0 deletions
diff --git a/lib/App/Hiveminder/Utils.pm b/lib/App/Hiveminder/Utils.pm
new file mode 100644
index 0000000..ab9cfd0
--- /dev/null
+++ b/lib/App/Hiveminder/Utils.pm
@@ -0,0 +1,173 @@
+#!/usr/bin/perl
+package App::Hiveminder::Utils;
+use strict;
+use warnings;
+use List::MoreUtils qw/any/;
+use File::Temp qw/tempfile/;
+use Fcntl qw/F_SETFD/;
+require Exporter;
+our @ISA = qw/Exporter/;
+our @EXPORT_OK = qw/get_text_from_editor get_text_from_editor_or_cmdline in
+ parse_args update_tasks colorize display_tasks/;
+
+sub get_text_from_editor { # {{{
+ my $editor = $ENV{EDITOR} || $ENV{VISUAL} || '/bin/nano';
+ my ($fh, $fn) = tempfile;
+ my $device = '/dev/fd/' . fileno($fh);
+
+ # use the filehandle if possible, fall back to the filename
+ if (-w $device && -l $device && readlink($device) eq $fn) {
+ fcntl($fh, F_SETFD, 0);
+ system($editor, $device);
+ }
+ else {
+ close $fh;
+ system($editor, $fn);
+ open $fh, '<', $fn or die "Couldn't reopen $fn";
+ }
+
+ local $/ = undef;
+ my $text = <$fh>;
+ unlink $fn;
+
+ return $text;
+} # }}}
+sub get_text_from_editor_or_cmdline { # {{{
+ return join ' ', @_ if @_ > 0;
+ return get_text_from_editor;
+} # }}}
+sub in { # {{{
+ my $word = shift;
+ return any { $_ eq $word } @_;
+} # }}}
+sub parse_args { # {{{
+ my $ret = {};
+
+ # XXX: handle 'will complete' and 'sort by *'
+ # XXX: support the new Net::Hiveminder capability of searching on multiple
+ # keys per value
+ # XXX: currently, searching by 'q' doesn't work, but this is a limitation
+ # of the current hiveminder REST interface i believe
+ my @filters = ('accepted', 'complete', 'completed', 'description', 'due',
+ 'group', 'owner', 'pending', 'priority', 'q', 'requestor',
+ 'starts', 'summary', 'tag', 'unaccepted', 'search', 'id');
+ my @time_filters = ('completed', 'due', 'starts');
+ my @num_filters = ('priority');
+ my @arg_filters = ('completed', 'description', 'due', 'group', 'owner',
+ 'priority', 'q', 'requestor', 'starts', 'summary',
+ 'tag', 'id');
+
+ my %filter = (
+ name => '',
+ is_neg => 0,
+ );
+ for my $word (@_) {
+ if (!$filter{name}) {
+ if ($word eq 'not') {
+ $filter{is_neg} = 1;
+ next;
+ }
+ elsif ($word =~ m{^/}) {
+ $filter{name} = 'q';
+ $word =~ s{^/(.*)}{$1};
+ redo;
+ }
+ elsif (in($word, @filters)) {
+ $word = 'q' if $word eq 'search';
+ $filter{name} = $word;
+ if (!in($filter{name}, @arg_filters)) {
+ if ($filter{is_neg}) {
+ $filter{name} .= '_not';
+ }
+ $ret->{$filter{name}} = 1;
+ $filter{is_neg} = 0;
+ $filter{name} = '';
+ }
+ next;
+ }
+ else {
+ $filter{name} = 'id';
+ redo;
+ }
+ }
+ else {
+ if ((in($filter{name}, @time_filters) &&
+ ($word eq 'after' || $word eq 'before')) ||
+ (in($filter{name}, @num_filters) &&
+ ($word eq 'above' || $word eq 'below')) ||
+ $word eq 'not') {
+ $filter{name} .= "_$word";
+ next;
+ }
+
+ if (defined $ret->{$filter{name}}) {
+ push @{ $ret->{$filter{name}} }, $word;
+ }
+ else {
+ $ret->{$filter{name}} = [$word];
+ }
+ $filter{name} = '';
+ }
+ }
+
+ return $ret;
+} # }}}
+sub update_tasks { # {{{
+ my ($hm, $tasks, $updater) = @_;
+ my @tasks = ();
+ if (ref $tasks eq 'HASH') {
+ @tasks = $hm->get_tasks(%$tasks);
+ }
+ elsif (ref $tasks eq 'ARRAY') {
+ @tasks = @$tasks;
+ }
+ my $ret = [];
+ for my $task (@tasks) {
+ push @$ret, $hm->update_task($task, &$updater($task));
+ }
+ return $ret;
+} # }}}
+sub colorize { # {{{
+ my %priorities = (
+ lowest => 34,
+ low => 36,
+ high => 33,
+ highest => 31,
+ );
+ for my $line (@_) {
+ if ($line =~ /^\*/) {
+ $line = "\e[1;30;40m".$line."\e[0m";
+ next;
+ }
+ my $task_color = "37";
+ $task_color = "32" if
+ $line =~ s/ (\[(?:\"[^"]+\" ?)+\])/ \e[32m$1\e[0m/;
+ $task_color = "1;37" if
+ $line =~ s/ (\[by: [^\]]+\])/ \e[1;37m$1\e[0m/;
+ $task_color = "35" if
+ $line =~ s/ (\[due: [^\]]+\])/ \e[35m$1\e[0m/;
+ $task_color = "1;$priorities{$2}" if
+ $line =~ s/ (\[priority: (\w+)\])/" \e[1;$priorities{$2}m$1\e[0m"/e;
+ $task_color = "33" if
+ $line =~ s/ (\[starts: [^\]]+\])/ \e[33m$1\e[0m/;
+ $task_color = "1;30" if
+ $line =~ s/ (\[done\])/ \e[1;30m$1\e[0m/;
+ $line =~ s/^(#\w+)/\e[${task_color}m$1\e[0m/;
+ }
+
+ return join "\n", @_;
+} # }}}
+sub display_tasks { # {{{
+ my $hm = shift;
+ my @lines = $hm->display_tasks(@_);
+ my $text;
+ if (-t *STDOUT) {
+ $text = colorize @lines;
+ }
+ else {
+ $text = join "\n", @lines;
+ }
+ return $text;
+} # }}}
+
+1;