-
task add [tags] [attrs] desc...
- task list [tags] [attrs] desc...
- task long [tags] [attrs] desc...
- task ls [tags] [attrs] desc...
+ Usage: task
+ task add [tags] [attrs] desc...
task completed [tags] [attrs] desc...
- task ID [tags] [attrs] ["desc..."]
+ task ID [tags] [attrs] [desc...]
task ID /from/to/
task delete ID
task undelete ID
@@ -57,12 +55,18 @@
task calendar
task active
task overdue
- task oldest
- task newest
task stats
task export
task color
task version
+ task help
+ task list [tags] [attrs] desc...
+ task long [tags] [attrs] desc...
+ task ls [tags] [attrs] desc...
+ task newest [tags] [attrs] desc...
+ task oldest [tags] [attrs] desc...
+
+See http://www.beckingham.net/task.html for the latest releases and a full tutorial.
ID is the numeric identifier displayed by the 'task list' command
@@ -74,8 +78,11 @@ Attributes are:
project: Project name
priority: Priority
due: Due date
+ recur: Recurrence frequency
+ until: Recurrence end date
fg: Foreground color
bg: Background color
+ rc: Alternate .taskrc file
Any command or attribute name may be abbreviated if still unique:
task list project:Home
@@ -86,7 +93,7 @@ Some task descriptions need to be escaped because of the shell:
task add escaped \' quote
Many characters have special meaning to the shell, including:
- $ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~
+ $ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~
diff --git a/src/Config.cpp b/src/Config.cpp
index 48f549ea6..3476bc6f8 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -39,17 +39,32 @@
// These are default (but overridable) reports. These entries are necessary
// because these three reports were converted from hard-coded reports to custom
// reports, and therefore need these config file entries. However, users are
-// already used to seeing these three reports, but do not have these entries.
+// already used to seeing these five reports, but do not have these entries.
// The choice was a) make users edit their .taskrc files, b) write a .taskrc
// upgrade program to make the change, or c) this.
Config::Config ()
{
- (*this)["report.long.columns"] = "id,project,priority,entry,start,due,age,tags,description";
- (*this)["report.long.sort"] = "due+,priority-,project+";
- (*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
- (*this)["report.list.sort"] = "due+,priority-,project+";
- (*this)["report.ls.columns"] = "id,project,priority,description";
- (*this)["report.ls.sort"] = "priority-,project+";
+ (*this)["report.long.description"] = "Lists all task, all data, matching the specified criteria";
+ (*this)["report.long.columns"] = "id,project,priority,entry,start,due,recur,age,tags,description";
+ (*this)["report.long.sort"] = "due+,priority-,project+";
+
+ (*this)["report.list.description"] = "Lists all tasks matching the specified criteria";
+ (*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
+ (*this)["report.list.sort"] = "due+,priority-,project+";
+
+ (*this)["report.ls.description"] = "Minimal listing of all tasks matching the specified criteria";
+ (*this)["report.ls.columns"] = "id,project,priority,description";
+ (*this)["report.ls.sort"] = "priority-,project+";
+
+ (*this)["report.newest.description"] = "Shows the newest tasks";
+ (*this)["report.newest.columns"] = "id,project,priority,due,active,age,description";
+ (*this)["report.newest.sort"] = "id-";
+ (*this)["report.newest.limit"] = "10";
+
+ (*this)["report.oldest.description"] = "Shows the oldest tasks";
+ (*this)["report.oldest.columns"] = "id,project,priority,due,active,age,description";
+ (*this)["report.oldest.sort"] = "id+";
+ (*this)["report.oldest.limit"] = "10";
}
////////////////////////////////////////////////////////////////////////////////
@@ -59,9 +74,9 @@ Config::Config (const std::string& file)
}
////////////////////////////////////////////////////////////////////////////////
-// Read the Configuration filee and populate the *this map. The file format
-// is simply lines with name=value pairs. Whitespace between name, = and value
-// is not tolerated, but blank lines and comments starting with # are allowed.
+// Read the Configuration file and populate the *this map. The file format is
+// simply lines with name=value pairs. Whitespace between name, = and value is
+// not tolerated, but blank lines and comments starting with # are allowed.
bool Config::load (const std::string& file)
{
std::ifstream in;
@@ -154,17 +169,33 @@ void Config::createDefault (const std::string& home)
fprintf (out, "default.command=list\n");
// Custom reports.
- fprintf (out, "# Fields: id,uuid,project,priority,entry,start,due,age,active,tags,description\n");
- fprintf (out, "# Sort: due+,priority-,project+\n");
- fprintf (out, "# Filter: pro:x pri:H +bug\n");
- fprintf (out, "report.large.columns=id,uuid,project,priority,entry,start,due,age,active,tags,description\n");
- fprintf (out, "report.large.sort=due+,priority-,project+\n");
- fprintf (out, "report.long.columns=id,project,priority,entry,start,due,age,tags,description\n");
- fprintf (out, "report.long.sort=due+,priority-,project+\n");
- fprintf (out, "report.list.columns=id,project,priority,due,active,age,description\n");
- fprintf (out, "report.list.sort=due+,priority-,project+\n");
- fprintf (out, "report.ls.columns=id,project,priority,description\n");
- fprintf (out, "report.ls.sort=priority-,project+\n");
+ fprintf (out, "# Fields: id,uuid,project,priority,entry,start,due,recur,age,active,tags,description\n");
+ fprintf (out, "# Description: This report is ...\n");
+ fprintf (out, "# Sort: due+,priority-,project+\n");
+ fprintf (out, "# Filter: pro:x pri:H +bug\n");
+ fprintf (out, "# Limit: 10\n");
+
+ fprintf (out, "report.long.description=Lists all task, all data, matching the specified criteria");
+ fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description");
+ fprintf (out, "report.long.sort=due+,priority-,project+");
+
+ fprintf (out, "report.list.description=Lists all tasks matching the specified criteria");
+ fprintf (out, "report.list.columns=id,project,priority,due,active,age,description");
+ fprintf (out, "report.list.sort=due+,priority-,project+");
+
+ fprintf (out, "report.ls.description=Minimal listing of all tasks matching the specified criteria");
+ fprintf (out, "report.ls.columns=id,project,priority,description");
+ fprintf (out, "report.ls.sort=priority-,project+");
+
+ fprintf (out, "report.newest.description=Shows the newest tasks");
+ fprintf (out, "report.newest.columns=id,project,priority,due,active,age,description");
+ fprintf (out, "report.newest.sort=id-");
+ fprintf (out, "report.newest.limit=10");
+
+ fprintf (out, "report.oldest.description=Shows the oldest tasks");
+ fprintf (out, "report.oldest.columns=id,project,priority,due,active,age,description");
+ fprintf (out, "report.oldest.sort=id+");
+ fprintf (out, "report.oldest.limit=10");
fclose (out);
diff --git a/src/Grid.cpp b/src/Grid.cpp
index a391aa75b..bd1f0f6f5 100644
--- a/src/Grid.cpp
+++ b/src/Grid.cpp
@@ -325,7 +325,7 @@ Grid::Cell::operator int () const
case CELL_INT: return mInt;
case CELL_FLOAT: return (int) mFloat;
case CELL_DOUBLE: return (int) mDouble;
- case CELL_STRING: return mString.length ();
+ case CELL_STRING: return ::atoi (mString.c_str ());
}
return 0;
@@ -340,7 +340,7 @@ Grid::Cell::operator float () const
case CELL_INT: return (float) mInt;
case CELL_FLOAT: return mFloat;
case CELL_DOUBLE: return (float) mDouble;
- case CELL_STRING: return (float) mString.length ();
+ case CELL_STRING: return (float) ::atof (mString.c_str ());
}
return 0.0;
@@ -355,7 +355,7 @@ Grid::Cell::operator double () const
case CELL_INT: return (double) mInt;
case CELL_FLOAT: return (double) mFloat;
case CELL_DOUBLE: return mDouble;
- case CELL_STRING: return (double) mString.length ();
+ case CELL_STRING: return (double) ::atof (mString.c_str ());
}
return 0.0;
diff --git a/src/Table.cpp b/src/Table.cpp
index 071837cdf..8052ca0b3 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -994,7 +994,7 @@ void Table::clean (std::string& value)
}
////////////////////////////////////////////////////////////////////////////////
-const std::string Table::render ()
+const std::string Table::render (int maximum /* = 0 */)
{
calculateColumnWidths ();
@@ -1028,8 +1028,14 @@ const std::string Table::render ()
if (mSortColumns.size ())
sort (order);
+ // If a non-zero maximum is specified, then it limits the number of rows of
+ // the table that are rendered.
+ int limit = mRows;
+ if (maximum != 0)
+ limit = maximum;
+
// Print all rows.
- for (int row = 0; row < mRows; ++row)
+ for (int row = 0; row < limit; ++row)
{
std::vector > columns;
std::vector blanks;
diff --git a/src/Table.h b/src/Table.h
index fe098e896..aed5587e1 100644
--- a/src/Table.h
+++ b/src/Table.h
@@ -91,7 +91,7 @@ public:
int rowCount ();
int columnCount ();
- const std::string render ();
+ const std::string render (int maximum = 0);
private:
std::string getCell (const int, const int);
diff --git a/src/command.cpp b/src/command.cpp
index 0a6e9756a..4197810ba 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -367,8 +367,8 @@ std::string handleVersion (Config& conf)
"blanklines color color.active color.due color.overdue color.pri.H "
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
"confirmation curses data.location dateformat default.command "
- "default.priority defaultwidth due locking monthsperline nag newest next "
- "oldest project shadow.command shadow.file shadow.notify";
+ "default.priority defaultwidth due locking monthsperline nag next project "
+ "shadow.command shadow.file shadow.notify";
// This configuration variable is supported, but not documented. It exists
// so that unit tests can force color to be on even when the output from task
diff --git a/src/parse.cpp b/src/parse.cpp
index b87ce8dc9..b0a1c5197 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -130,12 +130,7 @@ static const char* commands[] =
"history",
"ghistory",
"info",
- "list",
- "long",
- "ls",
- "newest",
"next",
- "oldest",
"overdue",
"projects",
"start",
diff --git a/src/report.cpp b/src/report.cpp
index c88633ba0..ff26b34c8 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1678,302 +1678,6 @@ std::string handleReportOverdue (TDB& tdb, T& task, Config& conf)
return out.str ();
}
-////////////////////////////////////////////////////////////////////////////////
-// Successively apply filters based on the task object built from the command
-// line. Tasks that match all the specified criteria are listed.
-std::string handleReportOldest (TDB& tdb, T& task, Config& conf)
-{
- std::stringstream out;
-
- // Determine window size, and set table accordingly.
- int width = conf.get ("defaultwidth", 80);
-#ifdef HAVE_LIBNCURSES
- if (conf.get ("curses", true))
- {
- WINDOW* w = initscr ();
- width = w->_maxx + 1;
- endwin ();
- }
-#endif
-
- // Get the pending tasks.
- std::vector tasks;
- tdb.allPendingT (tasks);
- handleRecurrence (tdb, tasks);
- filter (tasks, task);
-
- initializeColorRules (conf);
-
- unsigned int quantity = conf.get ("oldest", 10);
-
- // Create a table for output.
- Table table;
- table.setTableWidth (width);
- table.addColumn ("ID");
- table.addColumn ("Project");
- table.addColumn ("Pri");
- table.addColumn ("Due");
- table.addColumn ("Active");
- table.addColumn ("Age");
- table.addColumn ("Description");
-
- if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
- {
- table.setColumnUnderline (0);
- table.setColumnUnderline (1);
- table.setColumnUnderline (2);
- table.setColumnUnderline (3);
- table.setColumnUnderline (4);
- table.setColumnUnderline (5);
- table.setColumnUnderline (6);
- }
- else
- table.setTableDashedUnderline ();
-
- table.setColumnWidth (0, Table::minimum);
- table.setColumnWidth (1, Table::minimum);
- table.setColumnWidth (2, Table::minimum);
- table.setColumnWidth (3, Table::minimum);
- table.setColumnWidth (4, Table::minimum);
- table.setColumnWidth (5, Table::minimum);
- table.setColumnWidth (6, Table::flexible);
-
- table.setColumnJustification (0, Table::right);
- table.setColumnJustification (3, Table::right);
- table.setColumnJustification (5, Table::right);
-
- table.sortOn (3, Table::ascendingDate);
- table.sortOn (2, Table::descendingPriority);
- table.sortOn (1, Table::ascendingCharacter);
-
- table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
-
- for (unsigned int i = 0; i < min (quantity, tasks.size ()); ++i)
- {
- T refTask (tasks[i]);
- Date now;
-
- // Now format the matching task.
- bool imminent = false;
- bool overdue = false;
- std::string due = refTask.getAttribute ("due");
- if (due.length ())
- {
- switch (getDueState (due))
- {
- case 2: overdue = true; break;
- case 1: imminent = true; break;
- case 0:
- default: break;
- }
-
- Date dt (::atoi (due.c_str ()));
- due = dt.toString (conf.get ("dateformat", "m/d/Y"));
- }
-
- std::string active;
- if (refTask.getAttribute ("start") != "")
- active = "*";
-
- std::string age;
- std::string created = refTask.getAttribute ("entry");
- if (created.length ())
- {
- Date dt (::atoi (created.c_str ()));
- formatTimeDeltaDays (age, (time_t) (now - dt));
- }
-
- // All criteria match, so add refTask to the output table.
- int row = table.addRow ();
- table.addCell (row, 0, refTask.getId ());
- table.addCell (row, 1, refTask.getAttribute ("project"));
- table.addCell (row, 2, refTask.getAttribute ("priority"));
- table.addCell (row, 3, due);
- table.addCell (row, 4, active);
- table.addCell (row, 5, age);
- table.addCell (row, 6, refTask.getDescription ());
-
- if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
- {
- Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
- Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg, conf);
- table.setRowFg (row, fg);
- table.setRowBg (row, bg);
-
- if (fg == Text::nocolor)
- {
- if (overdue)
- table.setCellFg (row, 3, Text::colorCode (conf.get ("color.overdue", "red")));
- else if (imminent)
- table.setCellFg (row, 3, Text::colorCode (conf.get ("color.due", "yellow")));
- }
- }
- }
-
- if (table.rowCount ())
- out << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
- else
- out << "No matches."
- << std::endl;
-
- return out.str ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Successively apply filters based on the task object built from the command
-// line. Tasks that match all the specified criteria are listed.
-std::string handleReportNewest (TDB& tdb, T& task, Config& conf)
-{
- std::stringstream out;
-
- // Determine window size, and set table accordingly.
- int width = conf.get ("defaultwidth", 80);
-#ifdef HAVE_LIBNCURSES
- if (conf.get ("curses", true))
- {
- WINDOW* w = initscr ();
- width = w->_maxx + 1;
- endwin ();
- }
-#endif
-
- // Get the pending tasks.
- std::vector tasks;
- tdb.allPendingT (tasks);
- handleRecurrence (tdb, tasks);
- filter (tasks, task);
-
- initializeColorRules (conf);
-
- int quantity = conf.get ("newest", 10);
-
- // Create a table for output.
- Table table;
- table.setTableWidth (width);
- table.addColumn ("ID");
- table.addColumn ("Project");
- table.addColumn ("Pri");
- table.addColumn ("Due");
- table.addColumn ("Active");
- table.addColumn ("Age");
- table.addColumn ("Description");
-
- if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
- {
- table.setColumnUnderline (0);
- table.setColumnUnderline (1);
- table.setColumnUnderline (2);
- table.setColumnUnderline (3);
- table.setColumnUnderline (4);
- table.setColumnUnderline (5);
- table.setColumnUnderline (6);
- }
- else
- table.setTableDashedUnderline ();
-
- table.setColumnWidth (0, Table::minimum);
- table.setColumnWidth (1, Table::minimum);
- table.setColumnWidth (2, Table::minimum);
- table.setColumnWidth (3, Table::minimum);
- table.setColumnWidth (4, Table::minimum);
- table.setColumnWidth (5, Table::minimum);
- table.setColumnWidth (6, Table::flexible);
-
- table.setColumnJustification (0, Table::right);
- table.setColumnJustification (3, Table::right);
- table.setColumnJustification (5, Table::right);
-
- table.sortOn (3, Table::ascendingDate);
- table.sortOn (2, Table::descendingPriority);
- table.sortOn (1, Table::ascendingCharacter);
-
- table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
-
- int total = tasks.size ();
- for (int i = total - 1; i >= max (0, total - quantity); --i)
- {
- T refTask (tasks[i]);
- Date now;
-
- // Now format the matching task.
- bool imminent = false;
- bool overdue = false;
- std::string due = refTask.getAttribute ("due");
- if (due.length ())
- {
- switch (getDueState (due))
- {
- case 2: overdue = true; break;
- case 1: imminent = true; break;
- case 0:
- default: break;
- }
-
- Date dt (::atoi (due.c_str ()));
- due = dt.toString (conf.get ("dateformat", "m/d/Y"));
- }
-
- std::string active;
- if (refTask.getAttribute ("start") != "")
- active = "*";
-
- std::string age;
- std::string created = refTask.getAttribute ("entry");
- if (created.length ())
- {
- Date dt (::atoi (created.c_str ()));
- formatTimeDeltaDays (age, (time_t) (now - dt));
- }
-
- // All criteria match, so add refTask to the output table.
- int row = table.addRow ();
- table.addCell (row, 0, refTask.getId ());
- table.addCell (row, 1, refTask.getAttribute ("project"));
- table.addCell (row, 2, refTask.getAttribute ("priority"));
- table.addCell (row, 3, due);
- table.addCell (row, 4, active);
- table.addCell (row, 5, age);
- table.addCell (row, 6, refTask.getDescription ());
-
- if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
- {
- Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
- Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg, conf);
- table.setRowFg (row, fg);
- table.setRowBg (row, bg);
-
- if (fg == Text::nocolor)
- {
- if (overdue)
- table.setCellFg (row, 3, Text::colorCode (conf.get ("color.overdue", "red")));
- else if (imminent)
- table.setCellFg (row, 3, Text::colorCode (conf.get ("color.due", "yellow")));
- }
- }
- }
-
- if (table.rowCount ())
- out << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
- else
- out << "No matches."
- << std::endl;
-
- return out.str ();
-}
-
-
////////////////////////////////////////////////////////////////////////////////
std::string handleReportStats (TDB& tdb, T& task, Config& conf)
{
@@ -2575,10 +2279,12 @@ std::string handleCustomReport (
}
}
+ int maximum = conf.get (std::string ("report.") + report + ".limit", (int)0);
+
std::stringstream out;
if (table.rowCount ())
out << optionalBlankLine (conf)
- << table.render ()
+ << table.render (maximum)
<< optionalBlankLine (conf)
<< table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks")
diff --git a/src/task.cpp b/src/task.cpp
index 3c1b2f629..eacaaf7f7 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -158,14 +158,6 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task overdue");
table.addCell (row, 2, "Shows all incomplete tasks that are beyond their due date");
- row = table.addRow ();
- table.addCell (row, 1, "task oldest");
- table.addCell (row, 2, "Shows the oldest tasks");
-
- row = table.addRow ();
- table.addCell (row, 1, "task newest");
- table.addCell (row, 2, "Shows the newest tasks");
-
row = table.addRow ();
table.addCell (row, 1, "task stats");
table.addCell (row, 2, "Shows task database statistics");
@@ -817,8 +809,6 @@ std::string runTaskCommand (
else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
- else if (command == "oldest") { if (gc) tdb.gc (); out = handleReportOldest (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
- else if (command == "newest") { if (gc) tdb.gc (); out = handleReportNewest (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
else if (command == "colors") { out = handleColor ( conf ); }
else if (command == "version") { out = handleVersion ( conf ); }
else if (command == "help") { longUsage ( conf ); }
diff --git a/src/task.h b/src/task.h
index dffc3ef17..05b710497 100644
--- a/src/task.h
+++ b/src/task.h
@@ -100,8 +100,6 @@ std::string handleReportCalendar (TDB&, T&, Config&);
std::string handleReportActive (TDB&, T&, Config&);
std::string handleReportOverdue (TDB&, T&, Config&);
std::string handleReportStats (TDB&, T&, Config&);
-std::string handleReportOldest (TDB&, T&, Config&);
-std::string handleReportNewest (TDB&, T&, Config&);
std::string handleCustomReport (TDB&, T&, Config&, const std::string&);
void validReportColumns (const std::vector &);