From 8a22ac7cf26fb93b65c5e9f54c3d8666977a9271 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 16 Jun 2009 21:55:30 -0400 Subject: [PATCH] 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 --- doc/man/taskrc.5 | 12 ++++++++++ src/Config.cpp | 3 +++ src/Context.cpp | 60 +++++++++++++++++++++++++++++++----------------- src/Context.h | 2 ++ src/command.cpp | 17 +++++++------- src/custom.cpp | 34 +++++++++++++-------------- src/main.h | 3 +++ src/rules.cpp | 45 ++++++++++++++++++++++++++++++++++++ 8 files changed, 130 insertions(+), 46 deletions(-) diff --git a/doc/man/taskrc.5 b/doc/man/taskrc.5 index e7a2c9a11..5671185de 100644 --- a/doc/man/taskrc.5 +++ b/doc/man/taskrc.5 @@ -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 diff --git a/src/Config.cpp b/src/Config.cpp index fb38d42ef..d9195a3bd 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -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 diff --git a/src/Context.cpp b/src/Context.cpp index 705f95e7d..9638fe69b 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -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. + parse (); // Parse command line. + 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; @@ -347,10 +359,10 @@ 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; -} + } // Sequence // Note: "add" doesn't require an ID @@ -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) { diff --git a/src/Context.h b/src/Context.h index dce8b7a03..63b353e9e 100644 --- a/src/Context.h +++ b/src/Context.h @@ -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 tagRemovals; private: + std::vector headers; std::vector messages; std::vector footnotes; bool inShadow; diff --git a/src/command.cpp b/src/command.cpp index 1885c4299..7fee10a02 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -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 diff --git a/src/custom.cpp b/src/custom.cpp index 85bd1ae29..3dc43cabb 100644 --- a/src/custom.cpp +++ b/src/custom.cpp @@ -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 () ? "+" : ""); } diff --git a/src/main.h b/src/main.h index 4ff2f351c..702401a38 100644 --- a/src/main.h +++ b/src/main.h @@ -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 (); diff --git a/src/rules.cpp b/src/rules.cpp index 4dbb2fa76..fa7e2004a 100644 --- a/src/rules.cpp +++ b/src/rules.cpp @@ -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; +} + +////////////////////////////////////////////////////////////////////////////////