From c2c0a7d261e99f50b814760fd4d3e9382ca08a5f Mon Sep 17 00:00:00 2001 From: RayanR000 Date: Wed, 23 Sep 2026 12:52:56 -0400 Subject: [PATCH] Allow dashes in rc.* DOM references The lexer stopped an rc. DOM reference at the first '-', so `task _get rc.context.my-ctx` treated the argument as a plain word and failed with "is not a DOM reference". Keep consuming the name while a dash is followed by more of it. A trailing dash is still an operator. Closes #2219 --- src/Lexer.cpp | 10 ++++++++++ test/dom2.test.py | 7 +++++++ test/lexer_test.cpp | 20 ++++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Lexer.cpp b/src/Lexer.cpp index 5d07c34d1..80c475941 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -928,6 +928,16 @@ bool Lexer::isDOM(std::string& token, Lexer::Type& type) { std::string partialToken; Lexer::Type partialType; if (isLiteral("rc.", false, false) && isWord(partialToken, partialType)) { + // Configuration names may contain dashes, as in 'context.my-ctx', so keep + // consuming as long as a dash is followed by more of the name. + while (_text[_cursor] == '-') { + std::size_t dash = _cursor++; + if (!isWord(partialToken, partialType)) { + _cursor = dash; + break; + } + } + token = _text.substr(marker, _cursor - marker); type = Lexer::Type::dom; return true; diff --git a/test/dom2.test.py b/test/dom2.test.py index 0cd2403c0..14dae1a01 100755 --- a/test/dom2.test.py +++ b/test/dom2.test.py @@ -246,6 +246,13 @@ def test_dom_rc_name(self): self.assertEqual(code, 0) self.assertIn("YMD", out) + def test_dom_rc_name_with_dash(self): + """DOM rc.context. where the name contains a dash""" + self.t.config("context.my-ctx", "project:x") + code, out, err = self.t("_get rc.context.my-ctx") + self.assertEqual(code, 0) + self.assertEqual("project:x\n", out) + def test_dom_rc_missing(self): """DOM rc.missing""" code, out, err = self.t("_get rc.missing") diff --git a/test/lexer_test.cpp b/test/lexer_test.cpp index 0189699bb..22b4a402c 100644 --- a/test/lexer_test.cpp +++ b/test/lexer_test.cpp @@ -39,9 +39,9 @@ //////////////////////////////////////////////////////////////////////////////// int TEST_NAME(int, char**) { #ifdef PRODUCT_TASKWARRIOR - UnitTest t(1255); + UnitTest t(1291); #else - UnitTest t(1235); + UnitTest t(1271); #endif // Use same Datetime/Duraiton configuration as Context∴:staticInitialization. @@ -437,6 +437,22 @@ int TEST_NAME(int, char**) { "rc.foo", {{"rc.foo", Lexer::Type::dom}, NO, NO, NO, NO}, }, + { + "rc.context.my-ctx", + {{"rc.context.my-ctx", Lexer::Type::dom}, NO, NO, NO, NO}, + }, + { + "rc.foo-", + {{"rc.foo", Lexer::Type::dom}, {"-", Lexer::Type::op}, NO, NO, NO}, + }, + { + "due-1d", + {{"due", Lexer::Type::dom}, + {"-", Lexer::Type::op}, + {"1d", Lexer::Type::duration}, + NO, + NO}, + }, // URL {