mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-27 00:57:19 +02:00
Feature #800
- 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).
This commit is contained in:
parent
3a5370ddf1
commit
27a04b29f5
28 changed files with 372 additions and 64 deletions
|
@ -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.<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.<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")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <int> blocking_ids;
|
||||
std::vector <Task>::iterator t;
|
||||
|
|
|
@ -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
|
||||
// <indent> <date> <anno>
|
||||
// ...
|
||||
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
|
||||
// <date> <anno>
|
||||
// ...
|
||||
if (_style == "default")
|
||||
if (_style == "default" ||
|
||||
_style == "combined")
|
||||
{
|
||||
int indent = context.config.getInteger ("indent.annotation");
|
||||
|
||||
|
|
|
@ -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 ());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
ColumnEnd::ColumnEnd ()
|
||||
{
|
||||
_name = "end";
|
||||
_label = STRING_COLUMN_LABEL_COMPLETE;
|
||||
_name = "end";
|
||||
_label = STRING_COLUMN_LABEL_COMPLETE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
ColumnEntry::ColumnEntry ()
|
||||
{
|
||||
_name = "entry";
|
||||
_label = STRING_COLUMN_LABEL_ADDED;
|
||||
_name = "entry";
|
||||
_label = STRING_COLUMN_LABEL_ADDED;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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 <std::string> all;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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 <std::string> styles () const { return _styles; }
|
||||
std::vector <std::string> 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 <std::string> _styles;
|
||||
std::vector <std::string> _examples;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue