diff --git a/src/Config.cpp b/src/Config.cpp index e710505ce..e4c247c7b 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -165,6 +165,7 @@ std::string Config::_defaults = "rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n" "\n" "# General decoration\n" + "rule.color.merge=yes\n" "color.label=\n" "color.label.sort=\n" "color.alternate=on gray2\n" @@ -239,6 +240,7 @@ std::string Config::_defaults = "rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n" "\n" "# General decoration\n" + "rule.color.merge=yes\n" "color.label=\n" "color.label.sort=\n" "color.alternate=\n" diff --git a/src/rules.cpp b/src/rules.cpp index 39e2d001b..3c6970cca 100644 --- a/src/rules.cpp +++ b/src/rules.cpp @@ -88,58 +88,68 @@ void initializeColorRules () } //////////////////////////////////////////////////////////////////////////////// -static void colorizeBlocked (Task& task, const Color& base, Color& c) +static void applyColor (const Color& base, Color& c, bool merge) +{ + if (merge) + c.blend (base); + else + c = base; +} + + +//////////////////////////////////////////////////////////////////////////////// +static void colorizeBlocked (Task& task, const Color& base, Color& c, bool merge) { if (task.is_blocked) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeBlocking (Task& task, const Color& base, Color& c) +static void colorizeBlocking (Task& task, const Color& base, Color& c, bool merge) { if (task.is_blocking) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeTagged (Task& task, const Color& base, Color& c) +static void colorizeTagged (Task& task, const Color& base, Color& c, bool merge) { if (task.getTagCount ()) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeActive (Task& task, const Color& base, Color& c) +static void colorizeActive (Task& task, const Color& base, Color& c, bool merge) { if (task.has ("start") && !task.has ("end")) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeScheduled (Task& task, const Color& base, Color& c) +static void colorizeScheduled (Task& task, const Color& base, Color& c, bool merge) { if (task.has ("scheduled") && Date (task.get_date ("scheduled")) <= now) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeUntil (Task& task, const Color& base, Color& c) +static void colorizeUntil (Task& task, const Color& base, Color& c, bool merge) { if (task.has ("until")) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeTag (Task& task, const std::string& rule, const Color& base, Color& c) +static void colorizeTag (Task& task, const std::string& rule, const Color& base, Color& c, bool merge) { if (task.hasTag (rule.substr (10))) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeProject (Task& task, const std::string& rule, const Color& base, Color& c) +static void colorizeProject (Task& task, const std::string& rule, const Color& base, Color& c, bool merge) { // Observe the case sensitivity setting. bool sensitive = context.config.getBoolean ("search.case.sensitive"); @@ -150,25 +160,25 @@ static void colorizeProject (Task& task, const std::string& rule, const Color& b // Match project names leftmost. if (rule_trunc.length () <= project.length ()) if (compare (rule_trunc, project.substr (0, rule_trunc.length ()), sensitive)) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeProjectNone (Task& task, const Color& base, Color& c) +static void colorizeProjectNone (Task& task, const Color& base, Color& c, bool merge) { if (task.get ("project") == "") - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeTagNone (Task& task, const Color& base, Color& c) +static void colorizeTagNone (Task& task, const Color& base, Color& c, bool merge) { if (task.getTagCount () == 0) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeKeyword (Task& task, const std::string& rule, const Color& base, Color& c) +static void colorizeKeyword (Task& task, const std::string& rule, const Color& base, Color& c, bool merge) { // Observe the case sensitivity setting. bool sensitive = context.config.getBoolean ("search.case.sensitive"); @@ -176,7 +186,7 @@ static void colorizeKeyword (Task& task, const std::string& rule, const Color& b // The easiest thing to check is the description, because it is just one // attribute. if (find (task.get ("description"), rule.substr (14), sensitive) != std::string::npos) - c.blend (base); + applyColor (base, c, merge); // Failing the description check, look at all annotations, returning on the // first match. @@ -187,7 +197,7 @@ static void colorizeKeyword (Task& task, const std::string& rule, const Color& b if (it.first.substr (0, 11) == "annotation_" && find (it.second, rule.substr (14), sensitive) != std::string::npos) { - c.blend (base); + applyColor (base, c, merge); return; } } @@ -195,28 +205,27 @@ static void colorizeKeyword (Task& task, const std::string& rule, const Color& b } //////////////////////////////////////////////////////////////////////////////// -static void colorizeUDA (Task& task, const std::string& rule, const Color& base, Color& c) +static void colorizeUDA (Task& task, const std::string& rule, const Color& base, Color& c, bool merge) { // Is the rule color.uda.name.value or color.uda.name? size_t pos = rule.find (".", 10); if (pos == std::string::npos) { if (task.has (rule.substr (10))) - c.blend (base); + applyColor (base, c, merge); } else { const std::string uda = rule.substr (10, pos - 10); const std::string val = rule.substr (pos + 1); - if (val == "none" && ! task.has (uda)) - c.blend (base); - else if (task.get (uda) == val) - c.blend (base); + if (val == "none" && ! task.has (uda) || + task.get (uda) == val) + applyColor (base, c, merge); } } //////////////////////////////////////////////////////////////////////////////// -static void colorizeDue (Task& task, const Color& base, Color& c) +static void colorizeDue (Task& task, const Color& base, Color& c, bool merge) { if (task.has ("due")) { @@ -224,12 +233,12 @@ static void colorizeDue (Task& task, const Color& base, Color& c) if (status != Task::completed && status != Task::deleted && task.getDateState ("due") == Task::dateAfterToday) - c.blend (base); + applyColor (base, c, merge); } } //////////////////////////////////////////////////////////////////////////////// -static void colorizeDueToday (Task& task, const Color& base, Color& c) +static void colorizeDueToday (Task& task, const Color& base, Color& c, bool merge) { if (task.has ("due")) { @@ -238,12 +247,12 @@ static void colorizeDueToday (Task& task, const Color& base, Color& c) if (status != Task::completed && status != Task::deleted && (dateState == Task::dateLaterToday || dateState == Task::dateEarlierToday)) - c.blend (base); + applyColor (base, c, merge); } } //////////////////////////////////////////////////////////////////////////////// -static void colorizeOverdue (Task& task, const Color& base, Color& c) +static void colorizeOverdue (Task& task, const Color& base, Color& c, bool merge) { if (task.has ("due")) { @@ -251,29 +260,29 @@ static void colorizeOverdue (Task& task, const Color& base, Color& c) if (status != Task::completed && status != Task::deleted && task.getDateState ("due") == Task::dateBeforeToday) - c.blend (base); + applyColor (base, c, merge); } } //////////////////////////////////////////////////////////////////////////////// -static void colorizeRecurring (Task& task, const Color& base, Color& c) +static void colorizeRecurring (Task& task, const Color& base, Color& c, bool merge) { if (task.has ("recur")) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeCompleted (Task& task, const Color& base, Color& c) +static void colorizeCompleted (Task& task, const Color& base, Color& c, bool merge) { if (task.getStatus () == Task::completed) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeDeleted (Task& task, const Color& base, Color& c) +static void colorizeDeleted (Task& task, const Color& base, Color& c, bool merge) { if (task.getStatus () == Task::deleted) - c.blend (base); + applyColor (base, c, merge); } //////////////////////////////////////////////////////////////////////////////// @@ -287,36 +296,40 @@ void autoColorize (Task& task, Color& c) return; } + bool merge = context.config.getBoolean ("rule.color.merge"); + // Note: c already contains colors specifically assigned via command. // Note: These rules form a hierarchy - the last rule is King, hence the // reverse iterator. + for (auto r = gsPrecedence.rbegin (); r != gsPrecedence.rend (); ++r) { Color base = gsColor[*r]; if (base.nontrivial ()) { - if (*r == "color.blocked") colorizeBlocked (task, base, c); - else if (*r == "color.blocking") colorizeBlocking (task, base, c); - else if (*r == "color.tagged") colorizeTagged (task, base, c); - else if (*r == "color.active") colorizeActive (task, base, c); - else if (*r == "color.scheduled") colorizeScheduled (task, base, c); - else if (*r == "color.until") colorizeUntil (task, base, c); - else if (*r == "color.project.none") colorizeProjectNone (task, base, c); - else if (*r == "color.tag.none") colorizeTagNone (task, base, c); - else if (*r == "color.due") colorizeDue (task, base, c); - else if (*r == "color.due.today") colorizeDueToday (task, base, c); - else if (*r == "color.overdue") colorizeOverdue (task, base, c); - else if (*r == "color.recurring") colorizeRecurring (task, base, c); - else if (*r == "color.completed") colorizeCompleted (task, base, c); - else if (*r == "color.deleted") colorizeDeleted (task, base, c); + if (*r == "color.blocked") colorizeBlocked (task, base, c, merge); + else if (*r == "color.blocking") colorizeBlocking (task, base, c, merge); + else if (*r == "color.tagged") colorizeTagged (task, base, c, merge); + else if (*r == "color.active") colorizeActive (task, base, c, merge); + else if (*r == "color.scheduled") colorizeScheduled (task, base, c, merge); + else if (*r == "color.until") colorizeUntil (task, base, c, merge); + else if (*r == "color.project.none") colorizeProjectNone (task, base, c, merge); + else if (*r == "color.tag.none") colorizeTagNone (task, base, c, merge); + else if (*r == "color.due") colorizeDue (task, base, c, merge); + else if (*r == "color.due.today") colorizeDueToday (task, base, c, merge); + else if (*r == "color.overdue") colorizeOverdue (task, base, c, merge); + else if (*r == "color.recurring") colorizeRecurring (task, base, c, merge); + else if (*r == "color.completed") colorizeCompleted (task, base, c, merge); + else if (*r == "color.deleted") colorizeDeleted (task, base, c, merge); // Wildcards - else if (r->substr (0, 10) == "color.tag.") colorizeTag (task, *r, base, c); - else if (r->substr (0, 14) == "color.project.") colorizeProject (task, *r, base, c); - else if (r->substr (0, 14) == "color.keyword.") colorizeKeyword (task, *r, base, c); - else if (r->substr (0, 10) == "color.uda.") colorizeUDA (task, *r, base, c); + else if (r->substr (0, 10) == "color.tag.") colorizeTag (task, *r, base, c, merge); + else if (r->substr (0, 14) == "color.project.") colorizeProject (task, *r, base, c, merge); + else if (r->substr (0, 14) == "color.keyword.") colorizeKeyword (task, *r, base, c, merge); + else if (r->substr (0, 10) == "color.uda.") colorizeUDA (task, *r, base, c, merge); } } + } ////////////////////////////////////////////////////////////////////////////////