diff --git a/ChangeLog b/ChangeLog index 88aca373d..8d64a2737 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,6 +32,8 @@ (thanks to george js). - TW-1820 Install with -DLANGUAGE=2 flag not work. (thanks to E. Manuel Cerr'on Angeles) +- TW-1827 Extract annotations from a task + (thanks to Ryan). - TW-1855 "Well-known" CA certificates not properly auto-loaded (thanks to Flavio Poletti). - TW-1857 Change Task::get call to the more efficient Task::has diff --git a/NEWS b/NEWS index 2bd8d501d..b5384ceca 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ New Features in Taskwarrior 2.6.0 - The 'QUARTER' virutal tag was added. - Improved compatibility with SmartOS, OmniOS and OpenIndiana. + - New DOM reference: annotations.count. New Commands in Taskwarrior 2.6.0 diff --git a/src/DOM.cpp b/src/DOM.cpp index 539e2fe37..4f9be1621 100644 --- a/src/DOM.cpp +++ b/src/DOM.cpp @@ -167,6 +167,7 @@ bool getDOM (const std::string& name, Variant& value) // .second // // Annotations (entry is a date): +// annotations.count // annotations..entry // annotations..description // @@ -298,6 +299,12 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) } } + if (ref.data.size () && size == 2 && elements[0] == "annotations" && elements[1] == "count") + { + value = Variant (static_cast (ref.getAnnotationCount ())); + return true; + } + if (ref.data.size () && size == 3 && elements[0] == "annotations") { auto annos = ref.getAnnotations (); diff --git a/src/Lexer.cpp b/src/Lexer.cpp index ba9174cbb..486229499 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -1159,6 +1159,7 @@ bool Lexer::isOperator (std::string& token, Lexer::Type& type) // .second // // Annotations (entry is a date): +// annotations.count // annotations..entry // annotations..description // @@ -1259,6 +1260,13 @@ bool Lexer::isDOM (std::string& token, Lexer::Type& type) if (isLiteral ("annotations", true, false) && isLiteral (".", false, false)) { + if (isLiteral ("count", false, false)) + { + token = _text.substr (marker, _cursor - marker); + type = Lexer::Type::dom; + return true; + } + std::string extractedToken; Lexer::Type extractedType; if (isInteger (extractedToken, extractedType)) diff --git a/src/Task.cpp b/src/Task.cpp index 35deff3da..b12280c3f 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -1032,6 +1032,17 @@ std::string Task::composeJSON (bool decorate /*= false*/) const return out.str (); } +//////////////////////////////////////////////////////////////////////////////// +int Task::getAnnotationCount () const +{ + int count = 0; + for (auto& ann : data) + if (! ann.first.compare (0, 11, "annotation_", 11)) + ++count; + + return count; +} + //////////////////////////////////////////////////////////////////////////////// bool Task::hasAnnotations () const { diff --git a/src/Task.h b/src/Task.h index 2cf4da61a..6aa8121c7 100644 --- a/src/Task.h +++ b/src/Task.h @@ -128,6 +128,7 @@ public: std::vector getTags () const; void removeTag (const std::string&); + int getAnnotationCount () const; bool hasAnnotations () const; std::map getAnnotations () const; void setAnnotations (const std::map &); diff --git a/test/dom.t b/test/dom.t index c75eed548..ed084f4bd 100755 --- a/test/dom.t +++ b/test/dom.t @@ -146,6 +146,16 @@ class TestDOM(TestCase): code, out, err = self.t("_get 3.due.second") self.assertEqual("0\n", out) + def test_dom_annotation_count_1(self): + """ DOM 1.annotation.count """ + code, out, err = self.t("_get 1.annotations.count") + self.assertEqual("0\n", out) + + def test_dom_annotation_count_3(self): + """ DOM 3.annotation.count """ + code, out, err = self.t("_get 3.annotations.count") + self.assertEqual("1\n", out) + def test_dom_annotation_entry(self): """ DOM 3.annotations.1.entry """ code, out, err = self.t("_get 3.annotations.1.entry")