Enhancement - header, footer, message

- Added header, footer and message sinks.
- Added individual colorization of headers, footers and messages.
- Added new configuration variables to Config.cpp, taskrc.5.
- Added colorization functions to rules.cpp
This commit is contained in:
Paul Beckingham 2009-06-16 21:55:30 -04:00
parent e7a0a20d55
commit 8a22ac7cf2
8 changed files with 130 additions and 46 deletions

View file

@ -230,6 +230,18 @@ Colors any task assigned to project X.
.TP .TP
.B color.keyword.X=on_blue .B color.keyword.X=on_blue
Colors any task where the description contains X. Colors any task where the description contains X.
.TP
.B color.header=green
Colors any of the messages printed prior to the report output.
.TP
.B color.message=green
Colors any of the messages printed after the report output.
.TP
.B color.footnote=green
Colors any of the messages printed last.
.RE .RE
.TP .TP

View file

@ -147,6 +147,9 @@ void Config::createDefault (const std::string& home)
fprintf (out, "#color.project.garden=on_green\n"); // TODO i18n fprintf (out, "#color.project.garden=on_green\n"); // TODO i18n
fprintf (out, "#color.keyword.car=on_blue\n"); // TODO i18n fprintf (out, "#color.keyword.car=on_blue\n"); // TODO i18n
fprintf (out, "#color.recurring=on_red\n"); // TODO i18n fprintf (out, "#color.recurring=on_red\n"); // TODO i18n
fprintf (out, "#color.header=bold_green\n"); // TODO i18n
fprintf (out, "#color.footnote=bold_green\n"); // TODO i18n
fprintf (out, "#color.message=bold_red\n"); // TODO i18n
fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ()); // TODO i18n fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ()); // TODO i18n
fprintf (out, "#shadow.command=list\n"); // TODO i18n fprintf (out, "#shadow.command=list\n"); // TODO i18n
fprintf (out, "#shadow.notify=on\n"); // TODO i18n fprintf (out, "#shadow.notify=on\n"); // TODO i18n

View file

@ -100,6 +100,9 @@ void Context::initialize ()
config.set ("color", "off"); config.set ("color", "off");
} }
if (config.get ("color", true))
initializeColorRules ();
// Load appropriate stringtable as soon after the config file as possible, to // Load appropriate stringtable as soon after the config file as possible, to
// allow all subsequent messages to be localizable. // allow all subsequent messages to be localizable.
std::string location = expandPath (config.get ("data.location")); std::string location = expandPath (config.get ("data.location"));
@ -126,10 +129,11 @@ void Context::initialize ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int Context::run () int Context::run ()
{ {
std::string output;
try try
{ {
parse (); // Parse command line. parse (); // Parse command line.
std::cout << dispatch (); // Dispatch to command handlers. output = dispatch (); // Dispatch to command handlers.
} }
catch (const std::string& error) catch (const std::string& error)
@ -142,15 +146,23 @@ int Context::run ()
message (stringtable.get (100, "Unknown error.")); message (stringtable.get (100, "Unknown error."));
} }
// Dump all headers.
foreach (h, headers)
std::cout << colorizeHeader (*h) << std::endl;
// Dump the report output.
std::cout << output;
// Dump all messages. // Dump all messages.
foreach (m, messages) foreach (m, messages)
std::cout << *m << std::endl; std::cout << colorizeMessage (*m) << std::endl;
// Dump all footnotes.
if (footnotes.size ()) if (footnotes.size ())
{ {
std::cout << std::endl; std::cout << std::endl;
foreach (f, footnotes) foreach (f, footnotes)
std::cout << *f << std::endl; std::cout << colorizeFootnote (*f) << std::endl;
} }
return 0; return 0;
@ -347,10 +359,10 @@ void Context::parse ()
{ {
// The '--' argument shuts off all parsing - everything is an argument. // The '--' argument shuts off all parsing - everything is an argument.
if (*arg == "--") if (*arg == "--")
{ {
std::cout << "# parse terminator '" << *arg << "'" << std::endl; header ("parse terminator '" + *arg + "'");
terminated = true; terminated = true;
} }
// Sequence // Sequence
// Note: "add" doesn't require an ID // Note: "add" doesn't require an ID
@ -358,7 +370,7 @@ std::cout << "# parse terminator '" << *arg << "'" << std::endl;
! foundSomethingAfterSequence && ! foundSomethingAfterSequence &&
sequence.valid (*arg)) sequence.valid (*arg))
{ {
std::cout << "# parse sequence '" << *arg << "'" << std::endl; header ("parse sequence '" + *arg + "'");
sequence.parse (*arg); sequence.parse (*arg);
foundSequence = true; foundSequence = true;
} }
@ -368,7 +380,7 @@ std::cout << "# parse sequence '" << *arg << "'" << std::endl;
(*arg)[0] == '+' && (*arg)[0] == '+' &&
validTag (*arg)) validTag (*arg))
{ {
std::cout << "# parse tag addition '" << *arg << "'" << std::endl; header ("parse tag addition '" + *arg + "'");
if (foundSequence) if (foundSequence)
foundSomethingAfterSequence = true; foundSomethingAfterSequence = true;
@ -381,7 +393,7 @@ std::cout << "# parse tag addition '" << *arg << "'" << std::endl;
(*arg)[0] == '-' && (*arg)[0] == '-' &&
validTag (*arg)) validTag (*arg))
{ {
std::cout << "# parse tag removal '" << *arg << "'" << std::endl; header ("parse tag removal '" + *arg + "'");
if (foundSequence) if (foundSequence)
foundSomethingAfterSequence = true; foundSomethingAfterSequence = true;
@ -395,7 +407,7 @@ std::cout << "# parse tag removal '" << *arg << "'" << std::endl;
// Atributes - name[.mod]:[value] // Atributes - name[.mod]:[value]
else if (attribute.valid (*arg)) else if (attribute.valid (*arg))
{ {
std::cout << "# parse attribute '" << *arg << "'" << std::endl; header ("parse attribute '" + *arg + "'");
if (foundSequence) if (foundSequence)
foundSomethingAfterSequence = true; foundSomethingAfterSequence = true;
@ -419,7 +431,7 @@ std::cout << "# parse attribute '" << *arg << "'" << std::endl;
if (foundSequence) if (foundSequence)
foundSomethingAfterSequence = true; foundSomethingAfterSequence = true;
std::cout << "# parse subst '" << *arg << "'" << std::endl; header ("parse subst '" + *arg + "'");
subst.parse (*arg); subst.parse (*arg);
} }
@ -427,7 +439,7 @@ std::cout << "# parse subst '" << *arg << "'" << std::endl;
else if (cmd.command == "" && else if (cmd.command == "" &&
cmd.valid (*arg)) cmd.valid (*arg))
{ {
std::cout << "# parse cmd '" << *arg << "'" << std::endl; header ("parse cmd '" + *arg + "'");
cmd.parse (*arg); cmd.parse (*arg);
if (foundSequence) if (foundSequence)
@ -437,7 +449,7 @@ std::cout << "# parse cmd '" << *arg << "'" << std::endl;
// Anything else is just considered description. // Anything else is just considered description.
else else
{ {
std::cout << "# parse description '" << *arg << "'" << std::endl; header ("parse description '" + *arg + "'");
if (foundSequence) if (foundSequence)
foundSomethingAfterSequence = true; foundSomethingAfterSequence = true;
@ -450,7 +462,7 @@ std::cout << "# parse description '" << *arg << "'" << std::endl;
// terminated, therefore everything subsequently is a description. // terminated, therefore everything subsequently is a description.
else else
{ {
std::cout << "# parse post-termination description '" << *arg << "'" << std::endl; header ("parse post-termination description '" + *arg + "'");
if (foundSequence) if (foundSequence)
foundSomethingAfterSequence = true; foundSomethingAfterSequence = true;
@ -480,7 +492,7 @@ std::cout << "# parse post-termination description '" << *arg << "'"
// Stuff the command line. // Stuff the command line.
args.clear (); args.clear ();
split (args, defaultCommand, ' '); split (args, defaultCommand, ' ');
std::cout << "[task " << defaultCommand << "]" << std::endl; header ("[task " + defaultCommand + "]");
// Reinitialize the context and recurse. // Reinitialize the context and recurse.
initialize (); initialize ();
@ -503,7 +515,7 @@ void Context::autoFilter ()
foreach (word, words) foreach (word, words)
{ {
filter.push_back (Att ("description", "has", *word)); filter.push_back (Att ("description", "has", *word));
std::cout << "# auto filter: " << att->first << ".has:" << *word << "" << std::endl; header ("auto filter: " + att->first + ".has:" + *word);
} }
} }
@ -511,7 +523,7 @@ void Context::autoFilter ()
else if (att->first == "project") else if (att->first == "project")
{ {
filter.push_back (Att ("project", "startswith", att->second.value ())); filter.push_back (Att ("project", "startswith", att->second.value ()));
std::cout << "# auto filter: " << att->first << ".startswith:" << att->second.value () << "" << std::endl; header ("auto filter: " + att->first + ".startswith:" + att->second.value ());
} }
// TODO Don't create a uuid for every task? // TODO Don't create a uuid for every task?
@ -523,7 +535,7 @@ void Context::autoFilter ()
att->first != "project") att->first != "project")
{ {
filter.push_back (att->second); filter.push_back (att->second);
std::cout << "# auto filter: " << att->first << ":" << att->second.value () << "" << std::endl; header ("auto filter: " + att->first + ":" + att->second.value ());
} }
} }
@ -533,17 +545,23 @@ void Context::autoFilter ()
foreach (tag, tagAdditions) foreach (tag, tagAdditions)
{ {
filter.push_back (Att ("tags", "has", *tag)); filter.push_back (Att ("tags", "has", *tag));
std::cout << "# auto filter: +" << *tag << "" << std::endl; header ("auto filter: +" + *tag);
} }
// Include tagRemovals. // Include tagRemovals.
foreach (tag, tagRemovals) foreach (tag, tagRemovals)
{ {
filter.push_back (Att ("tags", "hasnt", *tag)); filter.push_back (Att ("tags", "hasnt", *tag));
std::cout << "# auto filter: -" << *tag << "" << std::endl; header ("auto filter: -" + *tag);
} }
} }
////////////////////////////////////////////////////////////////////////////////
void Context::header (const std::string& input)
{
headers.push_back (input);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Context::message (const std::string& input) void Context::message (const std::string& input)
{ {

View file

@ -52,6 +52,7 @@ public:
int getWidth (); // determine terminal width int getWidth (); // determine terminal width
void header (const std::string&); // Header sink
void message (const std::string&); // Message sink void message (const std::string&); // Message sink
void footnote (const std::string&); // Footnote sink void footnote (const std::string&); // Footnote sink
@ -76,6 +77,7 @@ public:
std::vector <std::string> tagRemovals; std::vector <std::string> tagRemovals;
private: private:
std::vector <std::string> headers;
std::vector <std::string> messages; std::vector <std::string> messages;
std::vector <std::string> footnotes; std::vector <std::string> footnotes;
bool inShadow; bool inShadow;

View file

@ -380,14 +380,15 @@ std::string handleVersion ()
std::string recognized = std::string recognized =
" blanklines color color.active color.due color.overdue color.pri.H " " blanklines color color.active color.due color.overdue color.pri.H "
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged " "color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
"confirmation curses data.location dateformat default.command " "color.footnote color.message confirmation curses data.location dateformat "
"default.priority defaultwidth displayweeknumber due echo.command locale " "default.command default.priority defaultwidth displayweeknumber due "
"locking monthsperline nag next project shadow.command shadow.file " "echo.command locale locking monthsperline nag next project shadow.command "
"shadow.notify weekstart editor import.synonym.id import.synonym.uuid " "shadow.file shadow.notify weekstart editor import.synonym.id "
"import.synonym.status import.synonym.tags import.synonym.entry " "import.synonym.uuid import.synonym.status import.synonym.tags "
"import.synonym.start import.synonym.due import.synonym.recur " "import.synonym.entry import.synonym.start import.synonym.due "
"import.synonym.end import.synonym.project import.synonym.priority " "import.synonym.recur import.synonym.end import.synonym.project "
"import.synonym.fg import.synonym.bg import.synonym.description "; "import.synonym.priority import.synonym.fg import.synonym.bg "
"import.synonym.description ";
// This configuration variable is supported, but not documented. It exists // 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 // so that unit tests can force color to be on even when the output from task

View file

@ -116,7 +116,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, task->id); table.addCell (row++, columnCount, task->id);
} }
else if (*col == "uuid") else if (*col == "uuid")
@ -127,7 +127,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("uuid")); table.addCell (row++, columnCount, task->get ("uuid"));
} }
else if (*col == "project") else if (*col == "project")
@ -138,7 +138,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("project")); table.addCell (row++, columnCount, task->get ("project"));
} }
else if (*col == "priority") else if (*col == "priority")
@ -149,7 +149,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("priority")); table.addCell (row++, columnCount, task->get ("priority"));
} }
else if (*col == "entry") else if (*col == "entry")
@ -167,7 +167,7 @@ std::string handleCustomReport (const std::string& report)
{ {
Date dt (::atoi (entered.c_str ())); Date dt (::atoi (entered.c_str ()));
entered = dt.toString (context.config.get ("dateformat", "m/d/Y")); entered = dt.toString (context.config.get ("dateformat", "m/d/Y"));
table.addCell (++row, columnCount, entered); table.addCell (row++, columnCount, entered);
} }
} }
} }
@ -187,7 +187,7 @@ std::string handleCustomReport (const std::string& report)
{ {
Date dt (::atoi (started.c_str ())); Date dt (::atoi (started.c_str ()));
started = dt.toString (context.config.get ("dateformat", "m/d/Y")); started = dt.toString (context.config.get ("dateformat", "m/d/Y"));
table.addCell (++row, columnCount, started); table.addCell (row++, columnCount, started);
} }
} }
} }
@ -207,7 +207,7 @@ std::string handleCustomReport (const std::string& report)
{ {
Date dt (::atoi (started.c_str ())); Date dt (::atoi (started.c_str ()));
started = dt.toString (context.config.get ("dateformat", "m/d/Y")); started = dt.toString (context.config.get ("dateformat", "m/d/Y"));
table.addCell (++row, columnCount, started); table.addCell (row++, columnCount, started);
} }
} }
} }
@ -221,7 +221,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
std::string due; std::string due;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, getDueDate (*task)); table.addCell (row++, columnCount, getDueDate (*task));
dueColumn = columnCount; dueColumn = columnCount;
} }
@ -243,7 +243,7 @@ std::string handleCustomReport (const std::string& report)
{ {
Date dt (::atoi (created.c_str ())); Date dt (::atoi (created.c_str ()));
age = formatSeconds ((time_t) (now - dt)); age = formatSeconds ((time_t) (now - dt));
table.addCell (++row, columnCount, age); table.addCell (row++, columnCount, age);
} }
} }
} }
@ -265,7 +265,7 @@ std::string handleCustomReport (const std::string& report)
{ {
Date dt (::atoi (created.c_str ())); Date dt (::atoi (created.c_str ()));
age = formatSecondsCompact ((time_t) (now - dt)); age = formatSecondsCompact ((time_t) (now - dt));
table.addCell (++row, columnCount, age); table.addCell (row++, columnCount, age);
} }
} }
} }
@ -279,7 +279,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
if (task->get ("start") != "") if (task->get ("start") != "")
table.addCell (++row, columnCount, "*"); table.addCell (row++, columnCount, "*");
} }
else if (*col == "tags") else if (*col == "tags")
@ -295,7 +295,7 @@ std::string handleCustomReport (const std::string& report)
{ {
task->getTags (all); task->getTags (all);
join (tags, " ", all); join (tags, " ", all);
table.addCell (++row, columnCount, tags); table.addCell (row++, columnCount, tags);
} }
} }
@ -307,7 +307,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("description")); table.addCell (row++, columnCount, task->get ("description"));
} }
else if (*col == "description") else if (*col == "description")
@ -318,7 +318,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, getFullDescription (*task)); table.addCell (row++, columnCount, getFullDescription (*task));
} }
else if (*col == "recur") else if (*col == "recur")
@ -329,7 +329,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("recur")); table.addCell (row++, columnCount, task->get ("recur"));
} }
else if (*col == "recurrence_indicator") else if (*col == "recurrence_indicator")
@ -340,7 +340,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, table.addCell (row++, columnCount,
task->get ("recur") != "" ? "R" : ""); task->get ("recur") != "" ? "R" : "");
} }
@ -352,7 +352,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0; int row = 0;
foreach (task, tasks) foreach (task, tasks)
table.addCell (++row, columnCount, table.addCell (row++, columnCount,
task->getTagCount () ? "+" : ""); task->getTagCount () ? "+" : "");
} }

View file

@ -102,6 +102,9 @@ std::string handleCustomReport (const std::string&);
// rules.cpp // rules.cpp
void initializeColorRules (); void initializeColorRules ();
void autoColorize (Task&, Text::color&, Text::color&); void autoColorize (Task&, Text::color&, Text::color&);
std::string colorizeHeader (const std::string&);
std::string colorizeMessage (const std::string&);
std::string colorizeFootnote (const std::string&);
// import.cpp // import.cpp
std::string handleImport (); std::string handleImport ();

View file

@ -236,4 +236,49 @@ void autoColorize (
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string colorizeHeader (const std::string& input)
{
if (gsFg["color.header"] != Text::nocolor ||
gsBg["color.header"] != Text::nocolor)
{
return Text::colorize (
gsFg["color.header"],
gsBg["color.header"],
input);
}
return input;
}
////////////////////////////////////////////////////////////////////////////////
std::string colorizeMessage (const std::string& input)
{
if (gsFg["color.message"] != Text::nocolor ||
gsBg["color.message"] != Text::nocolor)
{
return Text::colorize (
gsFg["color.message"],
gsBg["color.message"],
input);
}
return input;
}
////////////////////////////////////////////////////////////////////////////////
std::string colorizeFootnote (const std::string& input)
{
if (gsFg["color.footnote"] != Text::nocolor ||
gsBg["color.footnote"] != Text::nocolor)
{
return Text::colorize (
gsFg["color.footnote"],
gsBg["color.footnote"],
input);
}
return input;
}
////////////////////////////////////////////////////////////////////////////////