mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-27 00:57:19 +02:00
Enhancement - Hooks
- Implemented lots of command hooks.
This commit is contained in:
parent
78c7408380
commit
dd423d315b
6 changed files with 2818 additions and 2651 deletions
|
@ -248,7 +248,9 @@ int Context::dispatch (std::string &out)
|
||||||
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); rc = handleCustomReport (cmd.command, out); }
|
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); rc = handleCustomReport (cmd.command, out); }
|
||||||
|
|
||||||
// If the command is not recognized, display usage.
|
// If the command is not recognized, display usage.
|
||||||
else { rc = shortUsage (out); }
|
else { hooks.trigger ("pre-usage-command");
|
||||||
|
rc = shortUsage (out);
|
||||||
|
hooks.trigger ("post-usage-command"); }
|
||||||
|
|
||||||
// Only update the shadow file if such an update was not suppressed (shadow),
|
// Only update the shadow file if such an update was not suppressed (shadow),
|
||||||
if (cmd.isWriteCommand () && !inShadow)
|
if (cmd.isWriteCommand () && !inShadow)
|
||||||
|
|
2101
src/command.cpp
2101
src/command.cpp
File diff suppressed because it is too large
Load diff
894
src/custom.cpp
894
src/custom.cpp
|
@ -111,522 +111,530 @@ int runCustomReport (
|
||||||
std::string &outs)
|
std::string &outs)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
// Load report configuration.
|
|
||||||
std::vector <std::string> columns;
|
|
||||||
split (columns, columnList, ',');
|
|
||||||
validReportColumns (columns);
|
|
||||||
|
|
||||||
std::vector <std::string> labels;
|
if (context.hooks.trigger ("pre-custom-report-command") &&
|
||||||
split (labels, labelList, ',');
|
context.hooks.trigger (std::string ("pre-") + report + "-command"))
|
||||||
|
|
||||||
if (columns.size () != labels.size () && labels.size () != 0)
|
|
||||||
throw std::string ("There are a different number of columns than labels ") +
|
|
||||||
"for report '" + report + "'.";
|
|
||||||
|
|
||||||
std::map <std::string, std::string> columnLabels;
|
|
||||||
if (labels.size ())
|
|
||||||
for (unsigned int i = 0; i < columns.size (); ++i)
|
|
||||||
columnLabels[columns[i]] = labels[i];
|
|
||||||
|
|
||||||
std::vector <std::string> sortOrder;
|
|
||||||
split (sortOrder, sortList, ',');
|
|
||||||
validSortColumns (columns, sortOrder);
|
|
||||||
|
|
||||||
std::vector <std::string> filterArgs;
|
|
||||||
split (filterArgs, filterList, ' ');
|
|
||||||
{
|
{
|
||||||
Cmd cmd (report);
|
// Load report configuration.
|
||||||
Task task;
|
std::vector <std::string> columns;
|
||||||
Sequence sequence;
|
split (columns, columnList, ',');
|
||||||
Subst subst;
|
validReportColumns (columns);
|
||||||
Filter filter;
|
|
||||||
context.parse (filterArgs, cmd, task, sequence, subst, filter);
|
|
||||||
|
|
||||||
context.sequence.combine (sequence);
|
std::vector <std::string> labels;
|
||||||
|
split (labels, labelList, ',');
|
||||||
|
|
||||||
// Allow limit to be overridden by the command line.
|
if (columns.size () != labels.size () && labels.size () != 0)
|
||||||
if (!context.task.has ("limit") && task.has ("limit"))
|
throw std::string ("There are a different number of columns than labels ") +
|
||||||
context.task.set ("limit", task.get ("limit"));
|
"for report '" + report + "'.";
|
||||||
|
|
||||||
foreach (att, filter)
|
std::map <std::string, std::string> columnLabels;
|
||||||
context.filter.push_back (*att);
|
if (labels.size ())
|
||||||
}
|
for (unsigned int i = 0; i < columns.size (); ++i)
|
||||||
|
columnLabels[columns[i]] = labels[i];
|
||||||
|
|
||||||
// Filter sequence.
|
std::vector <std::string> sortOrder;
|
||||||
if (context.sequence.size ())
|
split (sortOrder, sortList, ',');
|
||||||
context.filter.applySequence (tasks, context.sequence);
|
validSortColumns (columns, sortOrder);
|
||||||
|
|
||||||
// Initialize colorization for subsequent auto colorization.
|
std::vector <std::string> filterArgs;
|
||||||
initializeColorRules ();
|
split (filterArgs, filterList, ' ');
|
||||||
|
|
||||||
Table table;
|
|
||||||
table.setTableWidth (context.getWidth ());
|
|
||||||
table.setDateFormat (context.config.get ("dateformat"));
|
|
||||||
table.setReportName (report);
|
|
||||||
|
|
||||||
foreach (task, tasks)
|
|
||||||
table.addRow ();
|
|
||||||
|
|
||||||
int columnCount = 0;
|
|
||||||
int dueColumn = -1;
|
|
||||||
foreach (col, columns)
|
|
||||||
{
|
|
||||||
// Add each column individually.
|
|
||||||
if (*col == "id")
|
|
||||||
{
|
{
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "ID");
|
Cmd cmd (report);
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
Task task;
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
Sequence sequence;
|
||||||
|
Subst subst;
|
||||||
|
Filter filter;
|
||||||
|
context.parse (filterArgs, cmd, task, sequence, subst, filter);
|
||||||
|
|
||||||
int row = 0;
|
context.sequence.combine (sequence);
|
||||||
foreach (task, tasks)
|
|
||||||
if (task->id != 0)
|
// Allow limit to be overridden by the command line.
|
||||||
table.addCell (row++, columnCount, task->id);
|
if (!context.task.has ("limit") && task.has ("limit"))
|
||||||
else
|
context.task.set ("limit", task.get ("limit"));
|
||||||
table.addCell (row++, columnCount, "-");
|
|
||||||
|
foreach (att, filter)
|
||||||
|
context.filter.push_back (*att);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (*col == "uuid")
|
// Filter sequence.
|
||||||
|
if (context.sequence.size ())
|
||||||
|
context.filter.applySequence (tasks, context.sequence);
|
||||||
|
|
||||||
|
// Initialize colorization for subsequent auto colorization.
|
||||||
|
initializeColorRules ();
|
||||||
|
|
||||||
|
Table table;
|
||||||
|
table.setTableWidth (context.getWidth ());
|
||||||
|
table.setDateFormat (context.config.get ("dateformat"));
|
||||||
|
table.setReportName (report);
|
||||||
|
|
||||||
|
foreach (task, tasks)
|
||||||
|
table.addRow ();
|
||||||
|
|
||||||
|
int columnCount = 0;
|
||||||
|
int dueColumn = -1;
|
||||||
|
foreach (col, columns)
|
||||||
{
|
{
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "UUID");
|
// Add each column individually.
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
if (*col == "id")
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
foreach (task, tasks)
|
|
||||||
table.addCell (row++, columnCount, task->get ("uuid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "project")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Project");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
foreach (task, tasks)
|
|
||||||
table.addCell (row++, columnCount, task->get ("project"));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "priority")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Pri");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
foreach (task, tasks)
|
|
||||||
table.addCell (row++, columnCount, task->get ("priority"));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "priority_long")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Pri");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
std::string pri;
|
|
||||||
foreach (task, tasks)
|
|
||||||
{
|
{
|
||||||
pri = task->get ("priority");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "ID");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
if (pri == "H") pri = "High"; // TODO i18n
|
int row = 0;
|
||||||
else if (pri == "M") pri = "Medium"; // TODO i18n
|
foreach (task, tasks)
|
||||||
else if (pri == "L") pri = "Low"; // TODO i18n
|
if (task->id != 0)
|
||||||
|
table.addCell (row++, columnCount, task->id);
|
||||||
table.addCell (row++, columnCount, pri);
|
else
|
||||||
|
table.addCell (row++, columnCount, "-");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "entry")
|
else if (*col == "uuid")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Added");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string entered;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
entered = tasks[row].get ("entry");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "UUID");
|
||||||
if (entered.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
foreach (task, tasks)
|
||||||
|
table.addCell (row++, columnCount, task->get ("uuid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "project")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Project");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
foreach (task, tasks)
|
||||||
|
table.addCell (row++, columnCount, task->get ("project"));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "priority")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Pri");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
foreach (task, tasks)
|
||||||
|
table.addCell (row++, columnCount, task->get ("priority"));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "priority_long")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Pri");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
std::string pri;
|
||||||
|
foreach (task, tasks)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (entered.c_str ()));
|
pri = task->get ("priority");
|
||||||
entered = dt.toString (context.config.get ("dateformat"));
|
|
||||||
table.addCell (row, columnCount, entered);
|
if (pri == "H") pri = "High"; // TODO i18n
|
||||||
|
else if (pri == "M") pri = "Medium"; // TODO i18n
|
||||||
|
else if (pri == "L") pri = "Low"; // TODO i18n
|
||||||
|
|
||||||
|
table.addCell (row++, columnCount, pri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "entry_time")
|
else if (*col == "entry")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Added");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string entered;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
entered = tasks[row].get ("entry");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Added");
|
||||||
if (entered.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
std::string entered;
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (entered.c_str ()));
|
entered = tasks[row].get ("entry");
|
||||||
entered = dt.toStringWithTime (context.config.get ("dateformat"));
|
if (entered.length ())
|
||||||
table.addCell (row, columnCount, entered);
|
{
|
||||||
|
Date dt (::atoi (entered.c_str ()));
|
||||||
|
entered = dt.toString (context.config.get ("dateformat"));
|
||||||
|
table.addCell (row, columnCount, entered);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "start")
|
else if (*col == "entry_time")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Started");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string started;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
started = tasks[row].get ("start");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Added");
|
||||||
if (started.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
std::string entered;
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (started.c_str ()));
|
entered = tasks[row].get ("entry");
|
||||||
started = dt.toString (context.config.get ("dateformat"));
|
if (entered.length ())
|
||||||
table.addCell (row, columnCount, started);
|
{
|
||||||
|
Date dt (::atoi (entered.c_str ()));
|
||||||
|
entered = dt.toStringWithTime (context.config.get ("dateformat"));
|
||||||
|
table.addCell (row, columnCount, entered);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "start_time")
|
else if (*col == "start")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Started");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string started;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
started = tasks[row].get ("start");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Started");
|
||||||
if (started.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
std::string started;
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (started.c_str ()));
|
started = tasks[row].get ("start");
|
||||||
started = dt.toStringWithTime (context.config.get ("dateformat"));
|
if (started.length ())
|
||||||
table.addCell (row, columnCount, started);
|
{
|
||||||
|
Date dt (::atoi (started.c_str ()));
|
||||||
|
started = dt.toString (context.config.get ("dateformat"));
|
||||||
|
table.addCell (row, columnCount, started);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "end")
|
else if (*col == "start_time")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Completed");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string started;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
started = tasks[row].get ("end");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Started");
|
||||||
if (started.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
std::string started;
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (started.c_str ()));
|
started = tasks[row].get ("start");
|
||||||
started = dt.toString (context.config.get ("dateformat"));
|
if (started.length ())
|
||||||
table.addCell (row, columnCount, started);
|
{
|
||||||
|
Date dt (::atoi (started.c_str ()));
|
||||||
|
started = dt.toStringWithTime (context.config.get ("dateformat"));
|
||||||
|
table.addCell (row, columnCount, started);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "end_time")
|
else if (*col == "end")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Completed");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string format = context.config.get ("dateformat");
|
|
||||||
|
|
||||||
std::string started;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
started = tasks[row].get ("end");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Completed");
|
||||||
if (started.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
std::string started;
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (started.c_str ()));
|
started = tasks[row].get ("end");
|
||||||
started = dt.toStringWithTime (format);
|
if (started.length ())
|
||||||
table.addCell (row, columnCount, started);
|
{
|
||||||
|
Date dt (::atoi (started.c_str ()));
|
||||||
|
started = dt.toString (context.config.get ("dateformat"));
|
||||||
|
table.addCell (row, columnCount, started);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "due")
|
else if (*col == "end_time")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Due");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
std::string format = context.config.get ("report." + report + ".dateformat");
|
|
||||||
if (format == "")
|
|
||||||
format = context.config.get ("dateformat.report");
|
|
||||||
if (format == "")
|
|
||||||
format = context.config.get ("dateformat");
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
std::string due;
|
|
||||||
foreach (task, tasks)
|
|
||||||
table.addCell (row++, columnCount, getDueDate (*task, format));
|
|
||||||
|
|
||||||
dueColumn = columnCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "age")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string created;
|
|
||||||
std::string age;
|
|
||||||
Date now;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
created = tasks[row].get ("entry");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Completed");
|
||||||
if (created.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
std::string format = context.config.get ("dateformat");
|
||||||
|
|
||||||
|
std::string started;
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (created.c_str ()));
|
started = tasks[row].get ("end");
|
||||||
age = formatSeconds ((time_t) (now - dt));
|
if (started.length ())
|
||||||
table.addCell (row, columnCount, age);
|
{
|
||||||
|
Date dt (::atoi (started.c_str ()));
|
||||||
|
started = dt.toStringWithTime (format);
|
||||||
|
table.addCell (row, columnCount, started);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "age_compact")
|
else if (*col == "due")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
std::string created;
|
|
||||||
std::string age;
|
|
||||||
Date now;
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
{
|
||||||
created = tasks[row].get ("entry");
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Due");
|
||||||
if (created.length ())
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
std::string format = context.config.get ("report." + report + ".dateformat");
|
||||||
|
if (format == "")
|
||||||
|
format = context.config.get ("dateformat.report");
|
||||||
|
if (format == "")
|
||||||
|
format = context.config.get ("dateformat");
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
std::string due;
|
||||||
|
foreach (task, tasks)
|
||||||
|
table.addCell (row++, columnCount, getDueDate (*task, format));
|
||||||
|
|
||||||
|
dueColumn = columnCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "age")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
std::string created;
|
||||||
|
std::string age;
|
||||||
|
Date now;
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
{
|
{
|
||||||
Date dt (::atoi (created.c_str ()));
|
created = tasks[row].get ("entry");
|
||||||
age = formatSecondsCompact ((time_t) (now - dt));
|
if (created.length ())
|
||||||
table.addCell (row, columnCount, age);
|
{
|
||||||
|
Date dt (::atoi (created.c_str ()));
|
||||||
|
age = formatSeconds ((time_t) (now - dt));
|
||||||
|
table.addCell (row, columnCount, age);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "active")
|
else if (*col == "age_compact")
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Active");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
if (tasks[row].has ("start"))
|
|
||||||
table.addCell (row, columnCount, "*");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "tags")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Tags");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
std::vector <std::string> all;
|
|
||||||
std::string tags;
|
|
||||||
foreach (task, tasks)
|
|
||||||
{
|
{
|
||||||
task->getTags (all);
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Age");
|
||||||
join (tags, " ", all);
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
table.addCell (row++, columnCount, tags);
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "description_only")
|
std::string created;
|
||||||
{
|
std::string age;
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description");
|
Date now;
|
||||||
table.setColumnWidth (columnCount, Table::flexible);
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
foreach (task, tasks)
|
|
||||||
table.addCell (row++, columnCount, task->get ("description"));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "description")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description");
|
|
||||||
table.setColumnWidth (columnCount, Table::flexible);
|
|
||||||
table.setColumnJustification (columnCount, Table::left);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
foreach (task, tasks)
|
|
||||||
table.addCell (row++, columnCount, getFullDescription (*task, report));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "recur")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Recur");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
{
|
|
||||||
std::string recur = tasks[row].get ("recur");
|
|
||||||
if (recur != "")
|
|
||||||
table.addCell (row, columnCount, recur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "recurrence_indicator")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "R");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
if (tasks[row].has ("recur"))
|
|
||||||
table.addCell (row, columnCount, "R");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "tag_indicator")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "T");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
|
||||||
if (tasks[row].getTagCount ())
|
|
||||||
table.addCell (row, columnCount, "+");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*col == "wait")
|
|
||||||
{
|
|
||||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Wait");
|
|
||||||
table.setColumnWidth (columnCount, Table::minimum);
|
|
||||||
table.setColumnJustification (columnCount, Table::right);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
std::string wait;
|
|
||||||
foreach (task, tasks)
|
|
||||||
{
|
|
||||||
wait = task->get ("wait");
|
|
||||||
if (wait != "")
|
|
||||||
{
|
{
|
||||||
Date dt (::atoi (wait.c_str ()));
|
created = tasks[row].get ("entry");
|
||||||
wait = dt.toString (context.config.get ("dateformat"));
|
if (created.length ())
|
||||||
table.addCell (row++, columnCount, wait);
|
{
|
||||||
|
Date dt (::atoi (created.c_str ()));
|
||||||
|
age = formatSecondsCompact ((time_t) (now - dt));
|
||||||
|
table.addCell (row, columnCount, age);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (*col == "active")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Active");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
|
if (tasks[row].has ("start"))
|
||||||
|
table.addCell (row, columnCount, "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "tags")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Tags");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
std::vector <std::string> all;
|
||||||
|
std::string tags;
|
||||||
|
foreach (task, tasks)
|
||||||
|
{
|
||||||
|
task->getTags (all);
|
||||||
|
join (tags, " ", all);
|
||||||
|
table.addCell (row++, columnCount, tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "description_only")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description");
|
||||||
|
table.setColumnWidth (columnCount, Table::flexible);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
foreach (task, tasks)
|
||||||
|
table.addCell (row++, columnCount, task->get ("description"));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "description")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Description");
|
||||||
|
table.setColumnWidth (columnCount, Table::flexible);
|
||||||
|
table.setColumnJustification (columnCount, Table::left);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
foreach (task, tasks)
|
||||||
|
table.addCell (row++, columnCount, getFullDescription (*task, report));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "recur")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Recur");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
|
{
|
||||||
|
std::string recur = tasks[row].get ("recur");
|
||||||
|
if (recur != "")
|
||||||
|
table.addCell (row, columnCount, recur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "recurrence_indicator")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "R");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
|
if (tasks[row].has ("recur"))
|
||||||
|
table.addCell (row, columnCount, "R");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "tag_indicator")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "T");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||||
|
if (tasks[row].getTagCount ())
|
||||||
|
table.addCell (row, columnCount, "+");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*col == "wait")
|
||||||
|
{
|
||||||
|
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Wait");
|
||||||
|
table.setColumnWidth (columnCount, Table::minimum);
|
||||||
|
table.setColumnJustification (columnCount, Table::right);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
std::string wait;
|
||||||
|
foreach (task, tasks)
|
||||||
|
{
|
||||||
|
wait = task->get ("wait");
|
||||||
|
if (wait != "")
|
||||||
|
{
|
||||||
|
Date dt (::atoi (wait.c_str ()));
|
||||||
|
wait = dt.toString (context.config.get ("dateformat"));
|
||||||
|
table.addCell (row++, columnCount, wait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common to all columns.
|
||||||
|
// Add underline.
|
||||||
|
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||||
|
context.config.getBoolean ("fontunderline"))
|
||||||
|
table.setColumnUnderline (columnCount);
|
||||||
|
else
|
||||||
|
table.setTableDashedUnderline ();
|
||||||
|
|
||||||
|
++columnCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common to all columns.
|
// Dynamically add sort criteria.
|
||||||
// Add underline.
|
// Build a map of column names -> index.
|
||||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
std::map <std::string, unsigned int> columnIndex;
|
||||||
context.config.getBoolean ("fontunderline"))
|
for (unsigned int c = 0; c < columns.size (); ++c)
|
||||||
table.setColumnUnderline (columnCount);
|
columnIndex[columns[c]] = c;
|
||||||
else
|
|
||||||
table.setTableDashedUnderline ();
|
|
||||||
|
|
||||||
++columnCount;
|
foreach (sortColumn, sortOrder)
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamically add sort criteria.
|
|
||||||
// Build a map of column names -> index.
|
|
||||||
std::map <std::string, unsigned int> columnIndex;
|
|
||||||
for (unsigned int c = 0; c < columns.size (); ++c)
|
|
||||||
columnIndex[columns[c]] = c;
|
|
||||||
|
|
||||||
foreach (sortColumn, sortOrder)
|
|
||||||
{
|
|
||||||
// Separate column and direction.
|
|
||||||
std::string column = sortColumn->substr (0, sortColumn->length () - 1);
|
|
||||||
char direction = (*sortColumn)[sortColumn->length () - 1];
|
|
||||||
|
|
||||||
// TODO This code should really be using Att::type.
|
|
||||||
if (column == "id")
|
|
||||||
table.sortOn (columnIndex[column],
|
|
||||||
(direction == '+' ?
|
|
||||||
Table::ascendingNumeric :
|
|
||||||
Table::descendingNumeric));
|
|
||||||
|
|
||||||
else if (column == "priority")
|
|
||||||
table.sortOn (columnIndex[column],
|
|
||||||
(direction == '+' ?
|
|
||||||
Table::ascendingPriority :
|
|
||||||
Table::descendingPriority));
|
|
||||||
|
|
||||||
else if (column == "entry" || column == "start" || column == "wait" ||
|
|
||||||
column == "until" || column == "end")
|
|
||||||
table.sortOn (columnIndex[column],
|
|
||||||
(direction == '+' ?
|
|
||||||
Table::ascendingDate :
|
|
||||||
Table::descendingDate));
|
|
||||||
|
|
||||||
else if (column == "due")
|
|
||||||
table.sortOn (columnIndex[column],
|
|
||||||
(direction == '+' ?
|
|
||||||
Table::ascendingDueDate :
|
|
||||||
Table::descendingDueDate));
|
|
||||||
|
|
||||||
else if (column == "recur")
|
|
||||||
table.sortOn (columnIndex[column],
|
|
||||||
(direction == '+' ?
|
|
||||||
Table::ascendingPeriod :
|
|
||||||
Table::descendingPeriod));
|
|
||||||
|
|
||||||
else
|
|
||||||
table.sortOn (columnIndex[column],
|
|
||||||
(direction == '+' ?
|
|
||||||
Table::ascendingCharacter :
|
|
||||||
Table::descendingCharacter));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now auto colorize all rows.
|
|
||||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
|
||||||
{
|
|
||||||
for (unsigned int row = 0; row < tasks.size (); ++row)
|
|
||||||
{
|
{
|
||||||
Color c (tasks[row].get ("fg") + " " + tasks[row].get ("bg"));
|
// Separate column and direction.
|
||||||
autoColorize (tasks[row], c);
|
std::string column = sortColumn->substr (0, sortColumn->length () - 1);
|
||||||
table.setRowColor (row, c);
|
char direction = (*sortColumn)[sortColumn->length () - 1];
|
||||||
|
|
||||||
|
// TODO This code should really be using Att::type.
|
||||||
|
if (column == "id")
|
||||||
|
table.sortOn (columnIndex[column],
|
||||||
|
(direction == '+' ?
|
||||||
|
Table::ascendingNumeric :
|
||||||
|
Table::descendingNumeric));
|
||||||
|
|
||||||
|
else if (column == "priority")
|
||||||
|
table.sortOn (columnIndex[column],
|
||||||
|
(direction == '+' ?
|
||||||
|
Table::ascendingPriority :
|
||||||
|
Table::descendingPriority));
|
||||||
|
|
||||||
|
else if (column == "entry" || column == "start" || column == "wait" ||
|
||||||
|
column == "until" || column == "end")
|
||||||
|
table.sortOn (columnIndex[column],
|
||||||
|
(direction == '+' ?
|
||||||
|
Table::ascendingDate :
|
||||||
|
Table::descendingDate));
|
||||||
|
|
||||||
|
else if (column == "due")
|
||||||
|
table.sortOn (columnIndex[column],
|
||||||
|
(direction == '+' ?
|
||||||
|
Table::ascendingDueDate :
|
||||||
|
Table::descendingDueDate));
|
||||||
|
|
||||||
|
else if (column == "recur")
|
||||||
|
table.sortOn (columnIndex[column],
|
||||||
|
(direction == '+' ?
|
||||||
|
Table::ascendingPeriod :
|
||||||
|
Table::descendingPeriod));
|
||||||
|
|
||||||
|
else
|
||||||
|
table.sortOn (columnIndex[column],
|
||||||
|
(direction == '+' ?
|
||||||
|
Table::ascendingCharacter :
|
||||||
|
Table::descendingCharacter));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If an alternating row color is specified, notify the table.
|
// Now auto colorize all rows.
|
||||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||||
{
|
{
|
||||||
Color alternate (context.config.get ("color.alternate"));
|
for (unsigned int row = 0; row < tasks.size (); ++row)
|
||||||
if (alternate.nontrivial ())
|
{
|
||||||
table.setTableAlternateColor (alternate);
|
Color c (tasks[row].get ("fg") + " " + tasks[row].get ("bg"));
|
||||||
}
|
autoColorize (tasks[row], c);
|
||||||
|
table.setRowColor (row, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Limit the number of rows according to the report definition.
|
// If an alternating row color is specified, notify the table.
|
||||||
int maximum = context.config.getInteger (std::string ("report.") + report + ".limit");
|
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||||
|
{
|
||||||
|
Color alternate (context.config.get ("color.alternate"));
|
||||||
|
if (alternate.nontrivial ())
|
||||||
|
table.setTableAlternateColor (alternate);
|
||||||
|
}
|
||||||
|
|
||||||
// If the custom report has a defined limit, then allow a numeric override.
|
// Limit the number of rows according to the report definition.
|
||||||
// This is an integer specified as a filter (limit:10).
|
int maximum = context.config.getInteger (std::string ("report.") + report + ".limit");
|
||||||
if (context.task.has ("limit"))
|
|
||||||
maximum = atoi (context.task.get ("limit").c_str ());
|
|
||||||
|
|
||||||
std::stringstream out;
|
// If the custom report has a defined limit, then allow a numeric override.
|
||||||
if (table.rowCount ())
|
// This is an integer specified as a filter (limit:10).
|
||||||
out << optionalBlankLine ()
|
if (context.task.has ("limit"))
|
||||||
<< table.render (maximum)
|
maximum = atoi (context.task.get ("limit").c_str ());
|
||||||
<< optionalBlankLine ()
|
|
||||||
<< table.rowCount ()
|
std::stringstream out;
|
||||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
if (table.rowCount ())
|
||||||
|
out << optionalBlankLine ()
|
||||||
|
<< table.render (maximum)
|
||||||
|
<< optionalBlankLine ()
|
||||||
|
<< table.rowCount ()
|
||||||
|
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||||
|
<< std::endl;
|
||||||
|
else {
|
||||||
|
out << "No matches."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
else {
|
rc = 1;
|
||||||
out << "No matches."
|
}
|
||||||
<< std::endl;
|
|
||||||
rc = 1;
|
outs = out.str ();
|
||||||
|
context.hooks.trigger (std::string ("post-") + report + "-command");
|
||||||
|
context.hooks.trigger ("post-custom-report-command");
|
||||||
}
|
}
|
||||||
|
|
||||||
outs = out.str ();
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
75
src/edit.cpp
75
src/edit.cpp
|
@ -603,50 +603,57 @@ ARE_THESE_REALLY_HARMFUL:
|
||||||
// wrench. To be used sparingly.
|
// wrench. To be used sparingly.
|
||||||
int handleEdit (std::string &outs)
|
int handleEdit (std::string &outs)
|
||||||
{
|
{
|
||||||
std::stringstream out;
|
int rc = 0;
|
||||||
|
|
||||||
std::vector <Task> tasks;
|
if (context.hooks.trigger ("pre-edit-command"))
|
||||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
|
||||||
handleRecurrence ();
|
|
||||||
Filter filter;
|
|
||||||
context.tdb.loadPending (tasks, filter);
|
|
||||||
|
|
||||||
// Filter sequence.
|
|
||||||
std::vector <Task> all = tasks;
|
|
||||||
context.filter.applySequence (tasks, context.sequence);
|
|
||||||
|
|
||||||
foreach (task, tasks)
|
|
||||||
{
|
{
|
||||||
editFile (*task);
|
std::stringstream out;
|
||||||
context.tdb.update (*task);
|
|
||||||
/*
|
std::vector <Task> tasks;
|
||||||
foreach (other, all)
|
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||||
|
handleRecurrence ();
|
||||||
|
Filter filter;
|
||||||
|
context.tdb.loadPending (tasks, filter);
|
||||||
|
|
||||||
|
// Filter sequence.
|
||||||
|
std::vector <Task> all = tasks;
|
||||||
|
context.filter.applySequence (tasks, context.sequence);
|
||||||
|
|
||||||
|
foreach (task, tasks)
|
||||||
{
|
{
|
||||||
if (other->id != task.id) // Don't edit the same task again.
|
editFile (*task);
|
||||||
|
context.tdb.update (*task);
|
||||||
|
/*
|
||||||
|
foreach (other, all)
|
||||||
{
|
{
|
||||||
if (task.has ("parent") &&
|
if (other->id != task.id) // Don't edit the same task again.
|
||||||
if (other is parent of task)
|
|
||||||
{
|
{
|
||||||
// Transfer everything but mask, imask, uuid, parent.
|
if (task.has ("parent") &&
|
||||||
}
|
if (other is parent of task)
|
||||||
else if (task is parent of other)
|
{
|
||||||
{
|
// Transfer everything but mask, imask, uuid, parent.
|
||||||
// Transfer everything but mask, imask, uuid, parent.
|
}
|
||||||
}
|
else if (task is parent of other)
|
||||||
else if (task and other are siblings)
|
{
|
||||||
{
|
// Transfer everything but mask, imask, uuid, parent.
|
||||||
// Transfer everything but mask, imask, uuid, parent.
|
}
|
||||||
|
else if (task and other are siblings)
|
||||||
|
{
|
||||||
|
// Transfer everything but mask, imask, uuid, parent.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
context.tdb.commit ();
|
||||||
|
context.tdb.unlock ();
|
||||||
|
|
||||||
|
outs = out.str ();
|
||||||
|
context.hooks.trigger ("post-edit-command");
|
||||||
}
|
}
|
||||||
|
|
||||||
context.tdb.commit ();
|
return rc;
|
||||||
context.tdb.unlock ();
|
|
||||||
|
|
||||||
outs = out.str ();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
121
src/import.cpp
121
src/import.cpp
|
@ -1148,74 +1148,81 @@ static std::string importCSV (const std::vector <std::string>& lines)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int handleImport (std::string &outs)
|
int handleImport (std::string &outs)
|
||||||
{
|
{
|
||||||
std::stringstream out;
|
int rc = 0;
|
||||||
|
|
||||||
// Use the description as a file name.
|
if (context.hooks.trigger ("pre-import-command"))
|
||||||
std::string file = trim (context.task.get ("description"));
|
|
||||||
if (file.length () > 0)
|
|
||||||
{
|
{
|
||||||
// Load the file.
|
std::stringstream out;
|
||||||
std::vector <std::string> all;
|
|
||||||
File::read (file, all);
|
|
||||||
|
|
||||||
std::vector <std::string> lines;
|
// Use the description as a file name.
|
||||||
std::vector <std::string>::iterator it;
|
std::string file = trim (context.task.get ("description"));
|
||||||
for (it = all.begin (); it != all.end (); ++it)
|
if (file.length () > 0)
|
||||||
{
|
{
|
||||||
std::string line = *it;
|
// Load the file.
|
||||||
|
std::vector <std::string> all;
|
||||||
|
File::read (file, all);
|
||||||
|
|
||||||
// Strip comments
|
std::vector <std::string> lines;
|
||||||
std::string::size_type pound = line.find ("#");
|
std::vector <std::string>::iterator it;
|
||||||
if (pound != std::string::npos)
|
for (it = all.begin (); it != all.end (); ++it)
|
||||||
line = line.substr (0, pound);
|
{
|
||||||
|
std::string line = *it;
|
||||||
|
|
||||||
trim (line);
|
// Strip comments
|
||||||
|
std::string::size_type pound = line.find ("#");
|
||||||
|
if (pound != std::string::npos)
|
||||||
|
line = line.substr (0, pound);
|
||||||
|
|
||||||
// Skip blank lines
|
trim (line);
|
||||||
if (line.length () > 0)
|
|
||||||
lines.push_back (line);
|
// Skip blank lines
|
||||||
|
if (line.length () > 0)
|
||||||
|
lines.push_back (line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a guess at the file type.
|
||||||
|
fileType type = determineFileType (lines);
|
||||||
|
std::string identifier;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case task_1_4_3: identifier = "This looks like an older task export file."; break;
|
||||||
|
case task_1_5_0: identifier = "This looks like a recent task export file."; break;
|
||||||
|
case task_1_6_0: identifier = "This looks like a current task export file."; break;
|
||||||
|
case task_cmd_line: identifier = "This looks like task command line arguments."; break;
|
||||||
|
case todo_sh_2_0: identifier = "This looks like a todo.sh 2.x file."; break;
|
||||||
|
case csv: identifier = "This looks like a CSV file, but not a task export file."; break;
|
||||||
|
case text: identifier = "This looks like a text file with one task per line."; break;
|
||||||
|
case not_a_clue:
|
||||||
|
throw std::string ("Task cannot determine which type of file this is, "
|
||||||
|
"and cannot proceed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// For tty users, confirm the import, as it is destructive.
|
||||||
|
if (isatty (fileno (stdout)))
|
||||||
|
if (! confirm (identifier + " Okay to proceed?"))
|
||||||
|
throw std::string ("Task will not import any data.");
|
||||||
|
|
||||||
|
// Determine which type it might be, then attempt an import.
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case task_1_4_3: out << importTask_1_4_3 (lines); break;
|
||||||
|
case task_1_5_0: out << importTask_1_5_0 (lines); break;
|
||||||
|
case task_1_6_0: out << importTask_1_6_0 (lines); break;
|
||||||
|
case task_cmd_line: out << importTaskCmdLine (lines); break;
|
||||||
|
case todo_sh_2_0: out << importTodoSh_2_0 (lines); break;
|
||||||
|
case csv: out << importCSV (lines); break;
|
||||||
|
case text: out << importText (lines); break;
|
||||||
|
case not_a_clue: /* to stop the compiler from complaining. */ break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
throw std::string ("You must specify a file to import.");
|
||||||
|
|
||||||
// Take a guess at the file type.
|
outs = out.str ();
|
||||||
fileType type = determineFileType (lines);
|
context.hooks.trigger ("post-import-command");
|
||||||
std::string identifier;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case task_1_4_3: identifier = "This looks like an older task export file."; break;
|
|
||||||
case task_1_5_0: identifier = "This looks like a recent task export file."; break;
|
|
||||||
case task_1_6_0: identifier = "This looks like a current task export file."; break;
|
|
||||||
case task_cmd_line: identifier = "This looks like task command line arguments."; break;
|
|
||||||
case todo_sh_2_0: identifier = "This looks like a todo.sh 2.x file."; break;
|
|
||||||
case csv: identifier = "This looks like a CSV file, but not a task export file."; break;
|
|
||||||
case text: identifier = "This looks like a text file with one task per line."; break;
|
|
||||||
case not_a_clue:
|
|
||||||
throw std::string ("Task cannot determine which type of file this is, "
|
|
||||||
"and cannot proceed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// For tty users, confirm the import, as it is destructive.
|
|
||||||
if (isatty (fileno (stdout)))
|
|
||||||
if (! confirm (identifier + " Okay to proceed?"))
|
|
||||||
throw std::string ("Task will not import any data.");
|
|
||||||
|
|
||||||
// Determine which type it might be, then attempt an import.
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case task_1_4_3: out << importTask_1_4_3 (lines); break;
|
|
||||||
case task_1_5_0: out << importTask_1_5_0 (lines); break;
|
|
||||||
case task_1_6_0: out << importTask_1_6_0 (lines); break;
|
|
||||||
case task_cmd_line: out << importTaskCmdLine (lines); break;
|
|
||||||
case todo_sh_2_0: out << importTodoSh_2_0 (lines); break;
|
|
||||||
case csv: out << importCSV (lines); break;
|
|
||||||
case text: out << importText (lines); break;
|
|
||||||
case not_a_clue: /* to stop the compiler from complaining. */ break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
throw std::string ("You must specify a file to import.");
|
|
||||||
|
|
||||||
outs = out.str ();
|
return rc;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
2274
src/report.cpp
2274
src/report.cpp
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue