diff --git a/ChangeLog b/ChangeLog index f15f29135..0af2007f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -82,6 +82,9 @@ their descriptions. + Added feature #779, which uses more relevant and consistent terms on the 'burndown' charts. + + Added feature #800, adding a new command 'columns' that lists all the columns + available for custom reports, and includes their formatting options (thanks + to T. Charles Yun). # Tracked Bugs, sorted by ID. + Fixed bug #403, which disambiguates certain commands involving numbers. diff --git a/NEWS b/NEWS index e54fa05bf..328d95ce7 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ New Features in taskwarrior 2.0.0 - Filtering now available on most read-only commands. - The done, delete, start and stop commands now allow modification to the task and annotations. + - New 'columns' command to list the supported columns and formats. Please refer to the ChangeLog file for full details. There are too many to list here. diff --git a/src/Date.cpp b/src/Date.cpp index 9efb9ece0..47024f1a4 100644 --- a/src/Date.cpp +++ b/src/Date.cpp @@ -152,6 +152,12 @@ std::string Date::toISO () return iso.str (); } +//////////////////////////////////////////////////////////////////////////////// +double Date::toJulian () +{ + return (mT / 86400.0) + 2440587.5; +} + //////////////////////////////////////////////////////////////////////////////// void Date::toEpoch (time_t& epoch) { diff --git a/src/Date.h b/src/Date.h index 7124536e1..c15e251eb 100644 --- a/src/Date.h +++ b/src/Date.h @@ -49,6 +49,7 @@ public: time_t toEpoch (); std::string toEpochString (); std::string toISO (); + double toJulian (); void toMDY (int&, int&, int&); const std::string toString (const std::string& format = "m/d/Y") const; diff --git a/src/ViewTask.cpp b/src/ViewTask.cpp index bffadbfed..8229cabb8 100644 --- a/src/ViewTask.cpp +++ b/src/ViewTask.cpp @@ -111,7 +111,7 @@ std::string ViewTask::render (std::vector & data, std::vector & seque for (i = _columns.begin (); i != _columns.end (); ++i) { // Headers factor in to width calculations. - int global_min = utf8_length ((*i)->getLabel ()); + int global_min = utf8_length ((*i)->label ()); int global_ideal = global_min; for (unsigned int s = 0; s < sequence.size (); ++s) diff --git a/src/ViewText.cpp b/src/ViewText.cpp index a00445047..425c91fc8 100644 --- a/src/ViewText.cpp +++ b/src/ViewText.cpp @@ -115,7 +115,7 @@ std::string ViewText::render () for (unsigned int col = 0; col < _columns.size (); ++col) { // Headers factor in to width calculations. - int global_min = utf8_length (_columns[col]->getLabel ()); + int global_min = utf8_length (_columns[col]->label ()); int global_ideal = global_min; for (unsigned int row = 0; row < _data.size (); ++row) diff --git a/src/columns/ColDate.cpp b/src/columns/ColDate.cpp index 86cca1425..6f88efc69 100644 --- a/src/columns/ColDate.cpp +++ b/src/columns/ColDate.cpp @@ -43,8 +43,22 @@ ColumnDate::ColumnDate () { _name = ""; _type = "date"; - _style = "default"; + _style = "formatted"; _label = ""; + + _styles.push_back ("formatted"); + _styles.push_back ("julian"); + _styles.push_back ("epoch"); + _styles.push_back ("iso"); + _styles.push_back ("age"); + + Date now; + now -= 125; // So that "age" is non-zero. + _examples.push_back (now.toString (context.config.get ("dateformat"))); + _examples.push_back (format (now.toJulian (), 13, 12)); + _examples.push_back (now.toEpochString ()); + _examples.push_back (now.toISO ()); + _examples.push_back (Duration (Date () - now).formatCompact ()); } //////////////////////////////////////////////////////////////////////////////// @@ -68,7 +82,8 @@ void ColumnDate::measure (Task& task, int& minimum, int& maximum) { Date date ((time_t) strtol (task.get (_name).c_str (), NULL, 10)); - if (_style == "default") + if (_style == "default" || + _style == "formatted") { // Determine the output date format, which uses a hierarchy of definitions. // rc.report..dateformat @@ -84,9 +99,7 @@ void ColumnDate::measure (Task& task, int& minimum, int& maximum) } else if (_style == "julian") { - // (JD − 2440587.5) × 86400 - double julian = (date.toEpoch () / 86400.0) + 2440587.5; - minimum = maximum = format (julian, 13, 12).length (); + minimum = maximum = format (date.toJulian (), 13, 12).length (); } else if (_style == "epoch") { @@ -115,7 +128,8 @@ void ColumnDate::render ( { if (task.has (_name)) { - if (_style == "default") + if (_style == "default" || + _style == "formatted") { // Determine the output date format, which uses a hierarchy of definitions. // rc.report..dateformat @@ -135,13 +149,11 @@ void ColumnDate::render ( } else if (_style == "julian") { - double julian = (Date ((time_t) strtol (task.get (_name).c_str (), NULL, 10)) - .toEpoch () / 86400.0) + 2440587.5; - lines.push_back ( color.colorize ( rightJustify ( - format (julian, 13, 12), width))); + format (Date ((time_t) strtol (task.get (_name).c_str (), NULL, 10)) + .toJulian (), 13, 12), width))); } else if (_style == "epoch") { @@ -169,18 +181,6 @@ void ColumnDate::render ( rightJustify ( Duration (now - date).formatCompact (), width))); } - else if (_style == "short") - { - } - else if (_style == "active") - { - } - else if (_style == "countdown") - { - } - else if (_style == "remaining") - { - } } } diff --git a/src/columns/ColDepends.cpp b/src/columns/ColDepends.cpp index 7d589d538..e195258ad 100644 --- a/src/columns/ColDepends.cpp +++ b/src/columns/ColDepends.cpp @@ -41,8 +41,16 @@ ColumnDepends::ColumnDepends () { _name = "depends"; _type = "string"; - _style = "default"; + _style = "list"; _label = STRING_COLUMN_LABEL_DEP; + + _styles.push_back ("list"); + _styles.push_back ("count"); + _styles.push_back ("indicator"); + + _examples.push_back ("1 2 10"); + _examples.push_back ("[3]"); + _examples.push_back (context.config.get ("dependency.indicator")); } //////////////////////////////////////////////////////////////////////////////// @@ -76,7 +84,8 @@ void ColumnDepends::measure (Task& task, int& minimum, int& maximum) if (_style == "indicator") minimum = maximum = context.config.get ("dependency.indicator").length (); else if (_style == "count") minimum = maximum = 2 + format ((int) blocking.size ()).length (); - else if (_style == "default") + else if (_style == "default" || + _style == "list") { minimum = maximum = 0; if (task.has ("depends")) @@ -129,7 +138,8 @@ void ColumnDepends::render ( color.colorize ( rightJustify ("[" + format ((int)blocking.size ()) + "]", width))); } - else if (_style == "default") + else if (_style == "default" || + _style == "list") { std::vector blocking_ids; std::vector ::iterator t; diff --git a/src/columns/ColDescription.cpp b/src/columns/ColDescription.cpp index 49ca8225e..f490ce2cb 100644 --- a/src/columns/ColDescription.cpp +++ b/src/columns/ColDescription.cpp @@ -42,8 +42,35 @@ ColumnDescription::ColumnDescription () { _name = "description"; _type = "string"; - _style = "default"; + _style = "combined"; _label = STRING_COLUMN_LABEL_DESC; + + _styles.push_back ("combined"); + _styles.push_back ("desc"); + _styles.push_back ("oneline"); + _styles.push_back ("truncated"); + _styles.push_back ("count"); + + std::string t = Date ().toString (context.config.get ("dateformat")); + std::string d = STRING_COLUMN_EXAMPLES_DESC; + std::string a1 = STRING_COLUMN_EXAMPLES_ANNO1; + std::string a2 = STRING_COLUMN_EXAMPLES_ANNO2; + std::string a3 = STRING_COLUMN_EXAMPLES_ANNO3; + std::string a4 = STRING_COLUMN_EXAMPLES_ANNO4; + + _examples.push_back (d + + "\n " + t + " " + a1 + + "\n " + t + " " + a2 + + "\n " + t + " " + a3 + + "\n " + t + " " + a4); + _examples.push_back (d); + _examples.push_back (d + + " " + t + " " + a1 + + " " + t + " " + a2 + + " " + t + " " + a3 + + " " + t + " " + a4); + _examples.push_back (d.substr (0, 20) + "..."); + _examples.push_back (d + " [4]"); } //////////////////////////////////////////////////////////////////////////////// @@ -66,7 +93,8 @@ void ColumnDescription::measure (Task& task, int& minimum, int& maximum) // The text // // ... - if (_style == "default") + if (_style == "default" || + _style == "combined") { int indent = context.config.getInteger ("indent.annotation"); std::string format = context.config.get ("dateformat.annotation"); @@ -149,7 +177,8 @@ void ColumnDescription::render ( // This is a description // // ... - if (_style == "default") + if (_style == "default" || + _style == "combined") { int indent = context.config.getInteger ("indent.annotation"); diff --git a/src/columns/ColDue.cpp b/src/columns/ColDue.cpp index 943bbfcea..d6a779687 100644 --- a/src/columns/ColDue.cpp +++ b/src/columns/ColDue.cpp @@ -42,6 +42,12 @@ ColumnDue::ColumnDue () { _name = "due"; _label = STRING_COLUMN_LABEL_DUE; + + _styles.push_back ("countdown"); + + Date now; + now += 125; + _examples.push_back (Duration (now - Date ()).formatCompact ()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/columns/ColEnd.cpp b/src/columns/ColEnd.cpp index 388847b9f..7e4f9e910 100644 --- a/src/columns/ColEnd.cpp +++ b/src/columns/ColEnd.cpp @@ -33,8 +33,8 @@ //////////////////////////////////////////////////////////////////////////////// ColumnEnd::ColumnEnd () { - _name = "end"; - _label = STRING_COLUMN_LABEL_COMPLETE; + _name = "end"; + _label = STRING_COLUMN_LABEL_COMPLETE; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/columns/ColEntry.cpp b/src/columns/ColEntry.cpp index 04f8f8712..21915f5bf 100644 --- a/src/columns/ColEntry.cpp +++ b/src/columns/ColEntry.cpp @@ -33,8 +33,8 @@ //////////////////////////////////////////////////////////////////////////////// ColumnEntry::ColumnEntry () { - _name = "entry"; - _label = STRING_COLUMN_LABEL_ADDED; + _name = "entry"; + _label = STRING_COLUMN_LABEL_ADDED; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/columns/ColID.cpp b/src/columns/ColID.cpp index f9790c443..55eca33ef 100644 --- a/src/columns/ColID.cpp +++ b/src/columns/ColID.cpp @@ -40,8 +40,12 @@ ColumnID::ColumnID () { _name = "id"; _type = "number"; - _style = "default"; + _style = "number"; _label = STRING_COLUMN_LABEL_ID; + + _styles.push_back ("number"); + + _examples.push_back ("123"); } //////////////////////////////////////////////////////////////////////////////// @@ -69,7 +73,8 @@ void ColumnID::measure (Task& task, int& minimum, int& maximum) minimum = maximum = length; - if (_style != "default") + if (_style != "default" && + _style != "number") throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); } diff --git a/src/columns/ColPriority.cpp b/src/columns/ColPriority.cpp index 44236b49d..65a3c04dd 100644 --- a/src/columns/ColPriority.cpp +++ b/src/columns/ColPriority.cpp @@ -39,8 +39,14 @@ ColumnPriority::ColumnPriority () { _name = "priority"; _type = "string"; - _style = "default"; + _style = "short"; _label = STRING_COLUMN_LABEL_PRI; + + _styles.push_back ("short"); + _styles.push_back ("long"); + + _examples.push_back ("H"); + _examples.push_back ("High"); } //////////////////////////////////////////////////////////////////////////////// @@ -86,7 +92,8 @@ void ColumnPriority::measure (Task& task, int& minimum, int& maximum) else if (priority == "M") minimum = maximum = 6; else if (priority == "L") minimum = maximum = 3; } - else if (_style != "default") + else if (_style != "default" && + _style != "short") throw format (STRING_COLUMN_BAD_FORMAT, "priority", _style); } diff --git a/src/columns/ColProject.cpp b/src/columns/ColProject.cpp index 1a479909d..3e73a93a3 100644 --- a/src/columns/ColProject.cpp +++ b/src/columns/ColProject.cpp @@ -39,8 +39,14 @@ ColumnProject::ColumnProject () { _name = "project"; _type = "string"; - _style = "default"; + _style = "full"; _label = STRING_COLUMN_LABEL_PROJECT; + + _styles.push_back ("full"); + _styles.push_back ("parent"); + + _examples.push_back (STRING_COLUMN_EXAMPLES_PROJ); + _examples.push_back (STRING_COLUMN_EXAMPLES_PAR); } //////////////////////////////////////////////////////////////////////////////// @@ -66,7 +72,8 @@ void ColumnProject::measure (Task& task, int& minimum, int& maximum) if (period != std::string::npos) project = project.substr (0, period); } - else if (_style != "default") + else if (_style != "default" && + _style != "full") throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); minimum = longestWord (project); diff --git a/src/columns/ColRecur.cpp b/src/columns/ColRecur.cpp index f1edffaf9..d633f8388 100644 --- a/src/columns/ColRecur.cpp +++ b/src/columns/ColRecur.cpp @@ -39,8 +39,14 @@ ColumnRecur::ColumnRecur () { _name = "recur"; _type = "string"; - _style = "default"; + _style = "duration"; _label = STRING_COLUMN_LABEL_RECUR; + + _styles.push_back ("duration"); + _styles.push_back ("indicator"); + + _examples.push_back ("weekly"); + _examples.push_back (context.config.get ("recurrence.indicator")); } //////////////////////////////////////////////////////////////////////////////// @@ -69,7 +75,8 @@ void ColumnRecur::setStyle (const std::string& value) // Set the minimum and maximum widths for the value. void ColumnRecur::measure (Task& task, int& minimum, int& maximum) { - if (_style == "default") + if (_style == "default" || + _style == "duration") { minimum = maximum = task.get ("recur").length (); } @@ -89,7 +96,8 @@ void ColumnRecur::render ( int width, Color& color) { - if (_style == "default") + if (_style == "default" || + _style == "duration") { lines.push_back (color.colorize (rightJustify (task.get ("recur"), width))); } diff --git a/src/columns/ColStart.cpp b/src/columns/ColStart.cpp index d6f1ba702..930107134 100644 --- a/src/columns/ColStart.cpp +++ b/src/columns/ColStart.cpp @@ -39,6 +39,10 @@ ColumnStart::ColumnStart () { _name = "start"; _label = STRING_COLUMN_LABEL_STARTED; + + _styles.push_back ("active"); + + _examples.push_back (context.config.get ("active.indicator")); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/columns/ColStatus.cpp b/src/columns/ColStatus.cpp index af97cd01c..61d708340 100644 --- a/src/columns/ColStatus.cpp +++ b/src/columns/ColStatus.cpp @@ -39,8 +39,14 @@ ColumnStatus::ColumnStatus () { _name = "status"; _type = "string"; - _style = "default"; + _style = "long"; _label = STRING_COLUMN_LABEL_STATUS; + + _styles.push_back ("long"); + _styles.push_back ("short"); + + _examples.push_back (STRING_COLUMN_LABEL_STAT_PE); + _examples.push_back (STRING_COLUMN_LABEL_STAT_P); } //////////////////////////////////////////////////////////////////////////////// @@ -71,7 +77,8 @@ void ColumnStatus::measure (Task& task, int& minimum, int& maximum) { Task::status status = task.getStatus (); - if (_style == "default") + if (_style == "default" || + _style == "long") { if (status == Task::pending || status == Task::deleted || @@ -101,7 +108,8 @@ void ColumnStatus::render ( Task::status status = task.getStatus (); std::string value; - if (_style == "default") + if (_style == "default" || + _style == "long") { if (status == Task::pending) value = STRING_COLUMN_LABEL_STAT_PE; else if (status == Task::completed) value = STRING_COLUMN_LABEL_STAT_CO; diff --git a/src/columns/ColString.cpp b/src/columns/ColString.cpp index ea8166a04..68beee445 100644 --- a/src/columns/ColString.cpp +++ b/src/columns/ColString.cpp @@ -39,8 +39,18 @@ ColumnString::ColumnString () { _name = "string"; _type = "string"; - _style = "default"; + _style = "left"; _label = ""; + + _styles.push_back ("left"); + _styles.push_back ("right"); + _styles.push_back ("left_fixed"); + _styles.push_back ("right_fixed"); + + _styles.push_back ("Hello (wrapped) "); + _styles.push_back (" Hello (wrapped)"); + _styles.push_back ("Hello (no-wrap) "); + _styles.push_back (" Hello (no-wrap)"); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/columns/ColTags.cpp b/src/columns/ColTags.cpp index 7f4405007..acb98f866 100644 --- a/src/columns/ColTags.cpp +++ b/src/columns/ColTags.cpp @@ -40,8 +40,16 @@ ColumnTags::ColumnTags () { _name = "tags"; _type = "string"; - _style = "default"; + _style = "list"; _label = STRING_COLUMN_LABEL_TAGS; + + _styles.push_back ("list"); + _styles.push_back ("indicator"); + _styles.push_back ("count"); + + _examples.push_back (STRING_COLUMN_EXAMPLES_TAGS); + _examples.push_back (context.config.get ("tag.indicator")); + _examples.push_back ("[2]"); } //////////////////////////////////////////////////////////////////////////////// @@ -78,7 +86,8 @@ void ColumnTags::measure (Task& task, int& minimum, int& maximum) if (_style == "indicator") minimum = maximum = context.config.get ("tag.indicator").length (); else if (_style == "count") minimum = maximum = 3; - else if (_style == "default") + else if (_style == "default" || + _style == "list") { std::string tags = task.get (_name); minimum = 0; @@ -122,7 +131,8 @@ void ColumnTags::render ( color.colorize ( rightJustify ("[" + format ((int)all.size ()) + "]", width))); } - else if (_style == "default") + else if (_style == "default" || + _style == "list") { std::replace (tags.begin (), tags.end (), ',', ' '); std::vector all; diff --git a/src/columns/ColUUID.cpp b/src/columns/ColUUID.cpp index bd3c1a7a2..068d555c5 100644 --- a/src/columns/ColUUID.cpp +++ b/src/columns/ColUUID.cpp @@ -40,8 +40,14 @@ ColumnUUID::ColumnUUID () { _name = "uuid"; _type = "string"; - _style = "default"; + _style = "long"; _label = STRING_COLUMN_LABEL_UUID; + + _styles.push_back ("long"); + _styles.push_back ("short"); + + _examples.push_back ("f30cb9c3-3fc0-483f-bfb2-3bf134f00694"); + _examples.push_back ("34f00694"); } //////////////////////////////////////////////////////////////////////////////// @@ -59,8 +65,8 @@ bool ColumnUUID::validate (std::string& value) // Set the minimum and maximum widths for the value. void ColumnUUID::measure (Task&, int& minimum, int& maximum) { - if (_style == "default") minimum = maximum = 36; - else if (_style == "short") minimum = maximum = 8; + if (_style == "default" || _style == "long") minimum = maximum = 36; + else if (_style == "short") minimum = maximum = 8; else throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); } @@ -74,7 +80,8 @@ void ColumnUUID::render ( { // f30cb9c3-3fc0-483f-bfb2-3bf134f00694 default // 34f00694 short - if (_style == "default") + if (_style == "default" || + _style == "long") lines.push_back (color.colorize (leftJustify (task.get (_name), width))); else if (_style == "short") diff --git a/src/columns/ColUrgency.cpp b/src/columns/ColUrgency.cpp index 8d0870416..9c4a71444 100644 --- a/src/columns/ColUrgency.cpp +++ b/src/columns/ColUrgency.cpp @@ -39,8 +39,14 @@ ColumnUrgency::ColumnUrgency () { _name = "urgency"; _type = "number"; - _style = "default"; + _style = "real"; _label = STRING_COLUMN_LABEL_URGENCY; + + _styles.push_back ("real"); + _styles.push_back ("integer"); + + _examples.push_back ("4.6"); + _examples.push_back ("4"); } //////////////////////////////////////////////////////////////////////////////// @@ -52,9 +58,17 @@ ColumnUrgency::~ColumnUrgency () // Set the minimum and maximum widths for the value. void ColumnUrgency::measure (Task& task, int& minimum, int& maximum) { - minimum = maximum = format (task.urgency (), 4, 3).length (); + if (_style == "default" || + _style == "real") + { + minimum = maximum = format (task.urgency (), 4, 3).length (); + } + else if (_style == "integer") + { + minimum = maximum = format ((int)task.urgency ()).length (); + } - if (_style != "default") + else throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); } @@ -65,10 +79,21 @@ void ColumnUrgency::render ( int width, Color& color) { - lines.push_back ( - color.colorize ( - rightJustify ( - format (task.urgency (), 4, 3), width))); + if (_style == "default" || + _style == "real") + { + lines.push_back ( + color.colorize ( + rightJustify ( + format (task.urgency (), 4, 3), width))); + } + else if (_style == "integer") + { + lines.push_back ( + color.colorize ( + rightJustify ( + format ((int)task.urgency ()), width))); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/columns/Column.h b/src/columns/Column.h index 832fba0d7..cc95cd739 100644 --- a/src/columns/Column.h +++ b/src/columns/Column.h @@ -45,9 +45,11 @@ public: bool operator== (const Column&) const; // TODO Is this necessary? ~Column (); - std::string getStyle () { return _style; } - std::string getLabel () { return _label; } - std::string type () const { return _type; } + std::string style () const { return _style; } + std::string label () const { return _label; } + std::string type () const { return _type; } + std::vector styles () const { return _styles; } + std::vector examples () const { return _examples; } virtual void setStyle (const std::string& value) { _style = value; } virtual void setLabel (const std::string& value) { _label = value; } @@ -66,6 +68,8 @@ protected: std::string _style; std::string _label; std::string _report; + std::vector _styles; + std::vector _examples; }; #endif diff --git a/src/commands/CMakeLists.txt b/src/commands/CMakeLists.txt index d0967ef69..ccc9971d1 100644 --- a/src/commands/CMakeLists.txt +++ b/src/commands/CMakeLists.txt @@ -13,6 +13,7 @@ set (commands_SRCS Command.cpp Command.h CmdCalendar.cpp CmdCalendar.h CmdCommands.cpp CmdCommands.h CmdColor.cpp CmdColor.h + CmdColumns.cpp CmdColumns.h CmdConfig.cpp CmdConfig.h CmdCount.cpp CmdCount.h CmdCustom.cpp CmdCustom.h diff --git a/src/commands/CmdColumns.cpp b/src/commands/CmdColumns.cpp new file mode 100644 index 000000000..f294a126e --- /dev/null +++ b/src/commands/CmdColumns.cpp @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +// +//////////////////////////////////////////////////////////////////////////////// + +#define L10N // Localization complete. + +#include +#include +#include +#include +#include +#include +#include +#include + +extern Context context; + +//////////////////////////////////////////////////////////////////////////////// +CmdColumns::CmdColumns () +{ + _keyword = "columns"; + _usage = "task columns"; + _description = STRING_CMD_COLUMNS_USAGE; + _read_only = true; + _displays_id = false; +} + +//////////////////////////////////////////////////////////////////////////////// +int CmdColumns::execute (std::string& output) +{ + // Include all columns in the table. + std::vector names; + std::map ::const_iterator col; + for (col = context.columns.begin (); col != context.columns.end (); ++col) + names.push_back (col->first); + + std::sort (names.begin (), names.end ()); + + // Render a list of project names from the map. + ViewText formats; + formats.width (context.getWidth ()); + formats.add (Column::factory ("string", STRING_COLUMN_LABEL_COLUMN)); + formats.add (Column::factory ("string", STRING_COLUMN_LABEL_STYLES)); + formats.add (Column::factory ("string", STRING_COLUMN_LABEL_EXAMPLES)); + + Color alternate (context.config.get ("color.alternate")); + formats.colorOdd (alternate); + formats.intraColorOdd (alternate); + + std::vector ::iterator name; + for (name = names.begin (); name != names.end (); ++name) + { + const std::vector styles = context.columns[*name]->styles (); + const std::vector examples = context.columns[*name]->examples (); + + for (unsigned int i = 0; i < styles.size (); ++i) + { + int row = formats.addRow (); + formats.set (row, 0, i == 0 ? *name : ""); + formats.set (row, 1, styles[i] + (i == 0 ? "*" : "")); + formats.set (row, 2, i < examples.size () ? examples[i] : ""); + } + } + + output = optionalBlankLine () + + formats.render () + + "\n" + + STRING_CMD_COLUMNS_NOTE + + "\n"; + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdColumns.h b/src/commands/CmdColumns.h new file mode 100644 index 000000000..517489673 --- /dev/null +++ b/src/commands/CmdColumns.h @@ -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_CMDCOLUMNS +#define INCLUDED_CMDCOLUMNS +#define L10N // Localization complete. + +#include +#include + +class CmdColumns : public Command +{ +public: + CmdColumns (); + int execute (std::string&); +}; + +#endif +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/Command.cpp b/src/commands/Command.cpp index 979f79c01..bb3eba2ee 100644 --- a/src/commands/Command.cpp +++ b/src/commands/Command.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,7 @@ void Command::factory (std::map & all) c = new CmdBurndownWeekly (); all[c->keyword ()] = c; c = new CmdCalendar (); all[c->keyword ()] = c; c = new CmdColor (); all[c->keyword ()] = c; + c = new CmdColumns (); all[c->keyword ()] = c; c = new CmdCompletionCommands (); all[c->keyword ()] = c; c = new CmdCompletionConfig (); all[c->keyword ()] = c; c = new CmdCompletionIds (); all[c->keyword ()] = c; diff --git a/src/en-US.h b/src/en-US.h index 2824c4593..b81a8c47f 100644 --- a/src/en-US.h +++ b/src/en-US.h @@ -155,6 +155,19 @@ #define STRING_COLUMN_LABEL_FG "Foreground color" #define STRING_COLUMN_LABEL_BG "Background color" #define STRING_COLUMN_LABEL_DATE "Date" +#define STRING_COLUMN_LABEL_COLUMN "Columns" +#define STRING_COLUMN_LABEL_STYLES "Supported Formats" +#define STRING_COLUMN_LABEL_EXAMPLES "Example" + +// Column Examples +#define STRING_COLUMN_EXAMPLES_TAGS "home @chore" +#define STRING_COLUMN_EXAMPLES_PROJ "home.garden" +#define STRING_COLUMN_EXAMPLES_PAR "home" +#define STRING_COLUMN_EXAMPLES_DESC "Move your clothes down on to the lower peg" +#define STRING_COLUMN_EXAMPLES_ANNO1 "Immediately before your lunch" +#define STRING_COLUMN_EXAMPLES_ANNO2 "If you are playing in the match this afternoon" +#define STRING_COLUMN_EXAMPLES_ANNO3 "Before you write your letter home" +#define STRING_COLUMN_EXAMPLES_ANNO4 "If you're not getting your hair cut" // commands/Cmd* #define STRING_CMD_CONFLICT "Custom report '{1}' conflicts with built-in task command." @@ -287,6 +300,8 @@ #define STRING_CMD_ANNO_DONE "Annotated {1} '{2}'" #define STRING_CMD_ANNO_SUMMARY "Annotated {1} task." #define STRING_CMD_ANNO_SUMMARY_N "Annotated {1} tasks." +#define STRING_CMD_COLUMNS_USAGE "Displays supported columns and styles." +#define STRING_CMD_COLUMNS_NOTE "* Means default format, and therefore optionsl. For example, 'due' and 'due.formatted' are equivalent." // Config #define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake."