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
.B color.keyword.X=on_blue
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
.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.keyword.car=on_blue\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.command=list\n"); // TODO i18n
fprintf (out, "#shadow.notify=on\n"); // TODO i18n

View file

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

View file

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

View file

@ -380,14 +380,15 @@ std::string handleVersion ()
std::string recognized =
" 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 displayweeknumber due echo.command locale "
"locking monthsperline nag next project shadow.command shadow.file "
"shadow.notify weekstart editor import.synonym.id import.synonym.uuid "
"import.synonym.status import.synonym.tags import.synonym.entry "
"import.synonym.start import.synonym.due import.synonym.recur "
"import.synonym.end import.synonym.project import.synonym.priority "
"import.synonym.fg import.synonym.bg import.synonym.description ";
"color.footnote color.message confirmation curses data.location dateformat "
"default.command default.priority defaultwidth displayweeknumber due "
"echo.command locale locking monthsperline nag next project shadow.command "
"shadow.file shadow.notify weekstart editor import.synonym.id "
"import.synonym.uuid import.synonym.status import.synonym.tags "
"import.synonym.entry import.synonym.start import.synonym.due "
"import.synonym.recur import.synonym.end import.synonym.project "
"import.synonym.priority import.synonym.fg import.synonym.bg "
"import.synonym.description ";
// 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

View file

@ -116,7 +116,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount, task->id);
table.addCell (row++, columnCount, task->id);
}
else if (*col == "uuid")
@ -127,7 +127,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("uuid"));
table.addCell (row++, columnCount, task->get ("uuid"));
}
else if (*col == "project")
@ -138,7 +138,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("project"));
table.addCell (row++, columnCount, task->get ("project"));
}
else if (*col == "priority")
@ -149,7 +149,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("priority"));
table.addCell (row++, columnCount, task->get ("priority"));
}
else if (*col == "entry")
@ -167,7 +167,7 @@ std::string handleCustomReport (const std::string& report)
{
Date dt (::atoi (entered.c_str ()));
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 ()));
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 ()));
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;
std::string due;
foreach (task, tasks)
table.addCell (++row, columnCount, getDueDate (*task));
table.addCell (row++, columnCount, getDueDate (*task));
dueColumn = columnCount;
}
@ -243,7 +243,7 @@ std::string handleCustomReport (const std::string& report)
{
Date dt (::atoi (created.c_str ()));
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 ()));
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;
foreach (task, tasks)
if (task->get ("start") != "")
table.addCell (++row, columnCount, "*");
table.addCell (row++, columnCount, "*");
}
else if (*col == "tags")
@ -295,7 +295,7 @@ std::string handleCustomReport (const std::string& report)
{
task->getTags (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;
foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("description"));
table.addCell (row++, columnCount, task->get ("description"));
}
else if (*col == "description")
@ -318,7 +318,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount, getFullDescription (*task));
table.addCell (row++, columnCount, getFullDescription (*task));
}
else if (*col == "recur")
@ -329,7 +329,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount, task->get ("recur"));
table.addCell (row++, columnCount, task->get ("recur"));
}
else if (*col == "recurrence_indicator")
@ -340,7 +340,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount,
table.addCell (row++, columnCount,
task->get ("recur") != "" ? "R" : "");
}
@ -352,7 +352,7 @@ std::string handleCustomReport (const std::string& report)
int row = 0;
foreach (task, tasks)
table.addCell (++row, columnCount,
table.addCell (row++, columnCount,
task->getTagCount () ? "+" : "");
}

View file

@ -102,6 +102,9 @@ std::string handleCustomReport (const std::string&);
// rules.cpp
void initializeColorRules ();
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
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;
}
////////////////////////////////////////////////////////////////////////////////