Commands - info

- Migrated 'info' command to CmdInfo.
- Renamed 'info' command to 'information'.
This commit is contained in:
Paul Beckingham 2011-05-28 12:55:45 -04:00
parent 306f10b420
commit 0ce198ab8c
10 changed files with 451 additions and 363 deletions

View file

@ -329,6 +329,7 @@ void Arguments::extract_sequence (std::vector <int>& sequence)
if (low > high) if (low > high)
throw std::string ("Inverted sequence range high-low."); throw std::string ("Inverted sequence range high-low.");
// TODO Is this meaningful?
if (high - low >= ARGUMENTS_SEQUENCE_MAX_RANGE) if (high - low >= ARGUMENTS_SEQUENCE_MAX_RANGE)
throw std::string ("ID Range too large."); throw std::string ("ID Range too large.");

View file

@ -164,7 +164,6 @@ void Cmd::load ()
commands.push_back ("edit"); commands.push_back ("edit");
commands.push_back ("help"); commands.push_back ("help");
commands.push_back ("import"); commands.push_back ("import");
commands.push_back ("info");
commands.push_back ("log"); commands.push_back ("log");
commands.push_back ("prepend"); commands.push_back ("prepend");
commands.push_back ("projects"); commands.push_back ("projects");
@ -260,7 +259,6 @@ bool Cmd::isReadOnlyCommand ()
command == "diagnostics" || command == "diagnostics" ||
command == "config" || command == "config" ||
command == "help" || command == "help" ||
command == "info" ||
command == "projects" || command == "projects" ||
command == "push" || command == "push" ||
command == "shell" || command == "shell" ||

View file

@ -230,6 +230,9 @@ int Context::dispatch2 (std::string &out)
return c->execute (commandLine, out); return c->execute (commandLine, out);
} }
// TODO Need to invoke 'information' when a sequence/filter is present, but
// no command is specified.
// TODO When ::dispatch is eliminated, show usage on unrecognized command. // TODO When ::dispatch is eliminated, show usage on unrecognized command.
// commands["help"]->execute (commandLine, out); // commands["help"]->execute (commandLine, out);
@ -248,7 +251,6 @@ int Context::dispatch (std::string &out)
else if (cmd.command == "colors") { rc = handleColor (out); } else if (cmd.command == "colors") { rc = handleColor (out); }
else if (cmd.command == "config") { rc = handleConfig (out); } else if (cmd.command == "config") { rc = handleConfig (out); }
else if (cmd.command == "stats") { rc = handleReportStats (out); } else if (cmd.command == "stats") { rc = handleReportStats (out); }
else if (cmd.command == "info") { rc = handleInfo (out); }
else if (cmd.command == "history.monthly") { rc = handleReportHistoryMonthly (out); } else if (cmd.command == "history.monthly") { rc = handleReportHistoryMonthly (out); }
else if (cmd.command == "history.annual") { rc = handleReportHistoryAnnual (out); } else if (cmd.command == "history.annual") { rc = handleReportHistoryAnnual (out); }
else if (cmd.command == "ghistory.monthly") { rc = handleReportGHistoryMonthly (out); } else if (cmd.command == "ghistory.monthly") { rc = handleReportGHistoryMonthly (out); }

View file

@ -9,6 +9,7 @@ set (commands_SRCS Command.cpp Command.h
CmdCustom.cpp CmdCustom.h CmdCustom.cpp CmdCustom.h
CmdExec.cpp CmdExec.h CmdExec.cpp CmdExec.h
CmdHelp.cpp CmdHelp.h CmdHelp.cpp CmdHelp.h
CmdInfo.cpp CmdInfo.h
CmdInstall.cpp CmdInstall.h CmdInstall.cpp CmdInstall.h
CmdLogo.cpp CmdLogo.h CmdLogo.cpp CmdLogo.h
CmdShow.cpp CmdShow.h CmdShow.cpp CmdShow.h

View file

@ -134,10 +134,6 @@ int CmdHelp::execute (const std::string& command_line, std::string& output)
view.set (row, 1, "task delete ID"); view.set (row, 1, "task delete ID");
view.set (row, 2, "Deletes the specified task."); view.set (row, 2, "Deletes the specified task.");
row = view.addRow ();
view.set (row, 1, "task info ID");
view.set (row, 2, "Shows all data, metadata for specified task.");
row = view.addRow (); row = view.addRow ();
view.set (row, 1, "task start ID"); view.set (row, 1, "task start ID");
view.set (row, 2, "Marks specified task as started."); view.set (row, 2, "Marks specified task as started.");

402
src/commands/CmdInfo.cpp Normal file
View file

@ -0,0 +1,402 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <sstream>
#include <Context.h>
#include <Date.h>
#include <Duration.h>
#include <ViewText.h>
#include <main.h>
#include <text.h>
#include <CmdInfo.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdInfo::CmdInfo ()
{
_keyword = "information";
_usage = "task information <filter>";
_description = "Shows all data and metadata for specified tasks.";
_read_only = true;
_displays_id = true;
}
////////////////////////////////////////////////////////////////////////////////
int CmdInfo::execute (const std::string& command_line, std::string& output)
{
int rc = 0;
// Get all the tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.loadPending (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Filter sequence.
context.filter.applySequence (tasks, context.sequence);
// Read the undo file.
std::vector <std::string> undo;
if (context.config.getBoolean ("journal.info"))
{
Directory location (context.config.get ("data.location"));
std::string undoFile = location.data + "/undo.data";
File::read (undoFile, undo);
}
// Find the task.
std::stringstream out;
std::vector <Task>::iterator task;
for (task = tasks.begin (); task != tasks.end (); ++task)
{
ViewText view;
view.width (context.getWidth ());
view.add (Column::factory ("string", "Name"));
view.add (Column::factory ("string", "Value"));
// If an alternating row color is specified, notify the table.
if (context.color ())
{
Color alternate (context.config.get ("color.alternate"));
view.colorOdd (alternate);
view.intraColorOdd (alternate);
}
Date now;
// id
int row = view.addRow ();
view.set (row, 0, "ID");
view.set (row, 1, format (task->id));
std::string status = ucFirst (Task::statusToText (task->getStatus ()));
// description
Color c;
autoColorize (*task, c);
row = view.addRow ();
view.set (row, 0, "Description");
view.set (row, 1, getFullDescription (*task, "info"), c);
// status
row = view.addRow ();
view.set (row, 0, "Status");
view.set (row, 1, status);
// project
if (task->has ("project"))
{
row = view.addRow ();
view.set (row, 0, "Project");
view.set (row, 1, task->get ("project"));
}
// priority
if (task->has ("priority"))
{
row = view.addRow ();
view.set (row, 0, "Priority");
view.set (row, 1, task->get ("priority"));
}
// dependencies: blocked
{
std::vector <Task> blocked;
dependencyGetBlocking (*task, blocked);
if (blocked.size ())
{
std::stringstream message;
std::vector <Task>::const_iterator it;
for (it = blocked.begin (); it != blocked.end (); ++it)
message << it->id << " " << it->get ("description") << "\n";
row = view.addRow ();
view.set (row, 0, "This task blocked by");
view.set (row, 1, message.str ());
}
}
// dependencies: blocking
{
std::vector <Task> blocking;
dependencyGetBlocked (*task, blocking);
if (blocking.size ())
{
std::stringstream message;
std::vector <Task>::const_iterator it;
for (it = blocking.begin (); it != blocking.end (); ++it)
message << it->id << " " << it->get ("description") << "\n";
row = view.addRow ();
view.set (row, 0, "This task is blocking");
view.set (row, 1, message.str ());
}
}
// recur
if (task->has ("recur"))
{
row = view.addRow ();
view.set (row, 0, "Recurrence");
view.set (row, 1, task->get ("recur"));
}
// until
if (task->has ("until"))
{
row = view.addRow ();
view.set (row, 0, "Recur until");
Date dt (atoi (task->get ("until").c_str ()));
std::string format = context.config.get ("reportdateformat");
if (format == "")
format = context.config.get ("dateformat");
std::string until = getDueDate (*task, format);
view.set (row, 1, until);
}
// mask
if (task->getStatus () == Task::recurring)
{
row = view.addRow ();
view.set (row, 0, "Mask");
view.set (row, 1, task->get ("mask"));
}
if (task->has ("parent"))
{
// parent
row = view.addRow ();
view.set (row, 0, "Parent task");
view.set (row, 1, task->get ("parent"));
// imask
row = view.addRow ();
view.set (row, 0, "Mask Index");
view.set (row, 1, task->get ("imask"));
}
// due (colored)
if (task->has ("due"))
{
row = view.addRow ();
view.set (row, 0, "Due");
std::string format = context.config.get ("reportdateformat");
if (format == "")
format = context.config.get ("dateformat");
view.set (row, 1, getDueDate (*task, format));
}
// wait
if (task->has ("wait"))
{
row = view.addRow ();
view.set (row, 0, "Waiting until");
Date dt (atoi (task->get ("wait").c_str ()));
view.set (row, 1, dt.toString (context.config.get ("dateformat")));
}
// start
if (task->has ("start"))
{
row = view.addRow ();
view.set (row, 0, "Start");
Date dt (atoi (task->get ("start").c_str ()));
view.set (row, 1, dt.toString (context.config.get ("dateformat")));
}
// end
if (task->has ("end"))
{
row = view.addRow ();
view.set (row, 0, "End");
Date dt (atoi (task->get ("end").c_str ()));
view.set (row, 1, dt.toString (context.config.get ("dateformat")));
}
// tags ...
std::vector <std::string> tags;
task->getTags (tags);
if (tags.size ())
{
std::string allTags;
join (allTags, " ", tags);
row = view.addRow ();
view.set (row, 0, "Tags");
view.set (row, 1, allTags);
}
// uuid
row = view.addRow ();
view.set (row, 0, "UUID");
std::string uuid = task->get ("uuid");
view.set (row, 1, uuid);
// entry
row = view.addRow ();
view.set (row, 0, "Entered");
Date dt (atoi (task->get ("entry").c_str ()));
std::string entry = dt.toString (context.config.get ("dateformat"));
std::string age;
std::string created = task->get ("entry");
if (created.length ())
{
Date dt (atoi (created.c_str ()));
age = Duration (now - dt).format ();
}
view.set (row, 1, entry + " (" + age + ")");
// fg
std::string color = task->get ("fg");
if (color != "")
{
row = view.addRow ();
view.set (row, 0, "Foreground color");
view.set (row, 1, color);
}
// bg
color = task->get ("bg");
if (color != "")
{
row = view.addRow ();
view.set (row, 0, "Background color");
view.set (row, 1, color);
}
// Task::urgency
row = view.addRow ();
view.set (row, 0, "Urgency");
view.set (row, 1, trimLeft (format (task->urgency (), 4, 4)));
// Create a second table, containing undo log change details.
ViewText journal;
// If an alternating row color is specified, notify the table.
if (context.color ())
{
Color alternate (context.config.get ("color.alternate"));
journal.colorOdd (alternate);
journal.intraColorOdd (alternate);
}
journal.width (context.getWidth ());
journal.add (Column::factory ("string", "Date"));
journal.add (Column::factory ("string", "Modification"));
if (context.config.getBoolean ("journal.info") &&
undo.size () > 3)
{
// Scan the undo data for entries matching this task.
std::string when;
std::string previous;
std::string current;
unsigned int i = 0;
long total_time = 0;
while (i < undo.size ())
{
when = undo[i++];
previous = "";
if (undo[i].substr (0, 3) == "old")
previous = undo[i++];
current = undo[i++];
i++; // Separator
if (current.find ("uuid:\"" + uuid) != std::string::npos)
{
if (previous != "")
{
int row = journal.addRow ();
Date timestamp (atoi (when.substr (5).c_str ()));
journal.set (row, 0, timestamp.toString (context.config.get ("dateformat")));
Task before (previous.substr (4));
Task after (current.substr (4));
journal.set (row, 1, taskInfoDifferences (before, after));
// calculate the total active time
if (before.get ("start") == ""
&& after.get ("start") != "")
{
// task started
total_time -= timestamp.toEpoch ();
}
else if (before.get ("start") != ""
&& after.get ("start") == "")
{
// task stopped
total_time += timestamp.toEpoch ();
}
}
}
}
// add now() if task is still active
if (total_time < 0)
total_time += Date ().toEpoch ();
// print total active time
if (total_time > 0)
{
row = journal.addRow ();
journal.set (row, 0, "Total active time");
journal.set (row, 1, Duration (total_time).format (),
(context.color () ? Color ("bold") : Color ()));
}
}
out << optionalBlankLine ()
<< view.render ()
<< "\n";
if (journal.rows () > 0)
out << journal.render ()
<< "\n";
}
if (! tasks.size ())
{
out << "No matches.\n";
rc = 1;
}
output = out.str ();
return rc;
}
////////////////////////////////////////////////////////////////////////////////

42
src/commands/CmdInfo.h Normal file
View file

@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_CMDINFO
#define INCLUDED_CMDINFO
#define L10N // Localization complete.
#include <string>
#include <Command.h>
class CmdInfo : public Command
{
public:
CmdInfo ();
int execute (const std::string&, std::string&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -31,6 +31,7 @@
#include <CmdCustom.h> #include <CmdCustom.h>
#include <CmdExec.h> #include <CmdExec.h>
#include <CmdHelp.h> #include <CmdHelp.h>
#include <CmdInfo.h>
#include <CmdInstall.h> #include <CmdInstall.h>
#include <CmdLogo.h> #include <CmdLogo.h>
#include <CmdShow.h> #include <CmdShow.h>
@ -49,6 +50,7 @@ void Command::factory (std::map <std::string, Command*>& all)
c = new CmdExec (); all[c->keyword ()] = c; c = new CmdExec (); all[c->keyword ()] = c;
c = new CmdHelp (); all[c->keyword ()] = c; c = new CmdHelp (); all[c->keyword ()] = c;
c = new CmdInstall (); all[c->keyword ()] = c; c = new CmdInstall (); all[c->keyword ()] = c;
c = new CmdInfo (); all[c->keyword ()] = c;
c = new CmdLogo (); all[c->keyword ()] = c; c = new CmdLogo (); all[c->keyword ()] = c;
c = new CmdShow (); all[c->keyword ()] = c; c = new CmdShow (); all[c->keyword ()] = c;
c = new CmdTags (); all[c->keyword ()] = c; c = new CmdTags (); all[c->keyword ()] = c;

View file

@ -95,7 +95,6 @@ void handleDiagnostics (std::string&);
int handleEdit (std::string&); int handleEdit (std::string&);
// report.cpp // report.cpp
int handleInfo (std::string&);
int handleReportSummary (std::string&); int handleReportSummary (std::string&);
int handleReportCalendar (std::string&); int handleReportCalendar (std::string&);
int handleReportStats (std::string&); int handleReportStats (std::string&);

View file

@ -51,361 +51,6 @@ static void countTasks (const std::vector <Task>&, const std::string&, const std
extern Context context; extern Context context;
////////////////////////////////////////////////////////////////////////////////
// Display all information for the given task.
int handleInfo (std::string& outs)
{
int rc = 0;
// Get all the tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.loadPending (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Filter sequence.
context.filter.applySequence (tasks, context.sequence);
// Read the undo file.
std::vector <std::string> undo;
if (context.config.getBoolean ("journal.info"))
{
Directory location (context.config.get ("data.location"));
std::string undoFile = location.data + "/undo.data";
File::read (undoFile, undo);
}
// Find the task.
std::stringstream out;
std::vector <Task>::iterator task;
for (task = tasks.begin (); task != tasks.end (); ++task)
{
ViewText view;
view.width (context.getWidth ());
view.add (Column::factory ("string", "Name"));
view.add (Column::factory ("string", "Value"));
// If an alternating row color is specified, notify the table.
if (context.color ())
{
Color alternate (context.config.get ("color.alternate"));
view.colorOdd (alternate);
view.intraColorOdd (alternate);
}
Date now;
// id
int row = view.addRow ();
view.set (row, 0, "ID");
view.set (row, 1, format (task->id));
std::string status = ucFirst (Task::statusToText (task->getStatus ()));
// description
Color c;
autoColorize (*task, c);
row = view.addRow ();
view.set (row, 0, "Description");
view.set (row, 1, getFullDescription (*task, "info"), c);
// status
row = view.addRow ();
view.set (row, 0, "Status");
view.set (row, 1, status);
// project
if (task->has ("project"))
{
row = view.addRow ();
view.set (row, 0, "Project");
view.set (row, 1, task->get ("project"));
}
// priority
if (task->has ("priority"))
{
row = view.addRow ();
view.set (row, 0, "Priority");
view.set (row, 1, task->get ("priority"));
}
// dependencies: blocked
{
std::vector <Task> blocked;
dependencyGetBlocking (*task, blocked);
if (blocked.size ())
{
std::stringstream message;
std::vector <Task>::const_iterator it;
for (it = blocked.begin (); it != blocked.end (); ++it)
message << it->id << " " << it->get ("description") << "\n";
row = view.addRow ();
view.set (row, 0, "This task blocked by");
view.set (row, 1, message.str ());
}
}
// dependencies: blocking
{
std::vector <Task> blocking;
dependencyGetBlocked (*task, blocking);
if (blocking.size ())
{
std::stringstream message;
std::vector <Task>::const_iterator it;
for (it = blocking.begin (); it != blocking.end (); ++it)
message << it->id << " " << it->get ("description") << "\n";
row = view.addRow ();
view.set (row, 0, "This task is blocking");
view.set (row, 1, message.str ());
}
}
// recur
if (task->has ("recur"))
{
row = view.addRow ();
view.set (row, 0, "Recurrence");
view.set (row, 1, task->get ("recur"));
}
// until
if (task->has ("until"))
{
row = view.addRow ();
view.set (row, 0, "Recur until");
Date dt (atoi (task->get ("until").c_str ()));
std::string format = context.config.get ("reportdateformat");
if (format == "")
format = context.config.get ("dateformat");
std::string until = getDueDate (*task, format);
view.set (row, 1, until);
}
// mask
if (task->getStatus () == Task::recurring)
{
row = view.addRow ();
view.set (row, 0, "Mask");
view.set (row, 1, task->get ("mask"));
}
if (task->has ("parent"))
{
// parent
row = view.addRow ();
view.set (row, 0, "Parent task");
view.set (row, 1, task->get ("parent"));
// imask
row = view.addRow ();
view.set (row, 0, "Mask Index");
view.set (row, 1, task->get ("imask"));
}
// due (colored)
if (task->has ("due"))
{
row = view.addRow ();
view.set (row, 0, "Due");
std::string format = context.config.get ("reportdateformat");
if (format == "")
format = context.config.get ("dateformat");
view.set (row, 1, getDueDate (*task, format));
}
// wait
if (task->has ("wait"))
{
row = view.addRow ();
view.set (row, 0, "Waiting until");
Date dt (atoi (task->get ("wait").c_str ()));
view.set (row, 1, dt.toString (context.config.get ("dateformat")));
}
// start
if (task->has ("start"))
{
row = view.addRow ();
view.set (row, 0, "Start");
Date dt (atoi (task->get ("start").c_str ()));
view.set (row, 1, dt.toString (context.config.get ("dateformat")));
}
// end
if (task->has ("end"))
{
row = view.addRow ();
view.set (row, 0, "End");
Date dt (atoi (task->get ("end").c_str ()));
view.set (row, 1, dt.toString (context.config.get ("dateformat")));
}
// tags ...
std::vector <std::string> tags;
task->getTags (tags);
if (tags.size ())
{
std::string allTags;
join (allTags, " ", tags);
row = view.addRow ();
view.set (row, 0, "Tags");
view.set (row, 1, allTags);
}
// uuid
row = view.addRow ();
view.set (row, 0, "UUID");
std::string uuid = task->get ("uuid");
view.set (row, 1, uuid);
// entry
row = view.addRow ();
view.set (row, 0, "Entered");
Date dt (atoi (task->get ("entry").c_str ()));
std::string entry = dt.toString (context.config.get ("dateformat"));
std::string age;
std::string created = task->get ("entry");
if (created.length ())
{
Date dt (atoi (created.c_str ()));
age = Duration (now - dt).format ();
}
view.set (row, 1, entry + " (" + age + ")");
// fg
std::string color = task->get ("fg");
if (color != "")
{
row = view.addRow ();
view.set (row, 0, "Foreground color");
view.set (row, 1, color);
}
// bg
color = task->get ("bg");
if (color != "")
{
row = view.addRow ();
view.set (row, 0, "Background color");
view.set (row, 1, color);
}
// Task::urgency
row = view.addRow ();
view.set (row, 0, "Urgency");
view.set (row, 1, trimLeft (format (task->urgency (), 4, 4)));
// Create a second table, containing undo log change details.
ViewText journal;
// If an alternating row color is specified, notify the table.
if (context.color ())
{
Color alternate (context.config.get ("color.alternate"));
journal.colorOdd (alternate);
journal.intraColorOdd (alternate);
}
journal.width (context.getWidth ());
journal.add (Column::factory ("string", "Date"));
journal.add (Column::factory ("string", "Modification"));
if (context.config.getBoolean ("journal.info") &&
undo.size () > 3)
{
// Scan the undo data for entries matching this task.
std::string when;
std::string previous;
std::string current;
unsigned int i = 0;
long total_time = 0;
while (i < undo.size ())
{
when = undo[i++];
previous = "";
if (undo[i].substr (0, 3) == "old")
previous = undo[i++];
current = undo[i++];
i++; // Separator
if (current.find ("uuid:\"" + uuid) != std::string::npos)
{
if (previous != "")
{
int row = journal.addRow ();
Date timestamp (atoi (when.substr (5).c_str ()));
journal.set (row, 0, timestamp.toString (context.config.get ("dateformat")));
Task before (previous.substr (4));
Task after (current.substr (4));
journal.set (row, 1, taskInfoDifferences (before, after));
// calculate the total active time
if (before.get ("start") == ""
&& after.get ("start") != "")
{
// task started
total_time -= timestamp.toEpoch ();
}
else if (before.get ("start") != ""
&& after.get ("start") == "")
{
// task stopped
total_time += timestamp.toEpoch ();
}
}
}
}
// add now() if task is still active
if (total_time < 0)
total_time += Date ().toEpoch ();
// print total active time
if (total_time > 0)
{
row = journal.addRow ();
journal.set (row, 0, "Total active time");
journal.set (row, 1, Duration (total_time).format (),
(context.color () ? Color ("bold") : Color ()));
}
}
out << optionalBlankLine ()
<< view.render ()
<< "\n";
if (journal.rows () > 0)
out << journal.render ()
<< "\n";
}
if (! tasks.size ())
{
out << "No matches.\n";
rc = 1;
}
outs = out.str ();
return rc;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Project Remaining Avg Age Complete 0% 100% // Project Remaining Avg Age Complete 0% 100%
// A 12 13d 55% XXXXXXXXXXXXX----------- // A 12 13d 55% XXXXXXXXXXXXX-----------