diff --git a/ChangeLog b/ChangeLog index 9893ec545..ddb9c00c9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,7 @@ - Implemented the context feature. - Closed dangling pipes in execute (), resolving problems when a hook script forks (thanks to Jens Erat). +- Re-enabled hook script feedback when exiting with 0 exit status. ------ current release --------------------------- diff --git a/doc/man/task.1.in b/doc/man/task.1.in index 65352f5d4..887dd7e16 100644 --- a/doc/man/task.1.in +++ b/doc/man/task.1.in @@ -433,7 +433,7 @@ Outputs a list of available contexts along with their definitions. Unsets the currently active context, if any was set. .TP -.B task context none +.B task context show Shows the currently active context, along with its definition. .TP @@ -1017,12 +1017,12 @@ result affected by the current active context. 2 1d Home Clean the dishes 1.14 $ task context home - Context 'home' applied. + Context 'home' set. Use 'task context none' to remove. $ task list ID Age Project Description Urg 2 1d Home Clean the dishes 1.14 - Context 'home' applied. + Context 'home' set. Use 'task context none' to remove. As seen in the example above, context is applied by specifying its name to the "context" command. To change the currently applied context, just pass the diff --git a/src/CLI.cpp b/src/CLI.cpp index cc7f74ac2..2801f3cb2 100644 --- a/src/CLI.cpp +++ b/src/CLI.cpp @@ -414,7 +414,7 @@ void CLI::addContextFilter () { addRawFilter("( " + contextFilter + " )"); if (context.verbose ("context")) - context.footnote (format("Context '{1}' applied.", contextName)); + context.footnote (format("Context '{1}' set. Use 'task context none' to remove.", contextName)); } } diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 342b5f3b1..f1f99d1c8 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -141,7 +141,7 @@ void Hooks::onLaunch () { std::vector ::iterator message; for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) - context.debug (*message); + context.footnote (*message); } else { @@ -208,7 +208,7 @@ void Hooks::onExit () { std::vector ::iterator message; for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) - context.debug (*message); + context.footnote (*message); } else { @@ -274,7 +274,7 @@ void Hooks::onAdd (Task& task) std::vector ::iterator message; for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) - context.debug (*message); + context.footnote (*message); } else { @@ -345,7 +345,7 @@ void Hooks::onModify (const Task& before, Task& after) std::vector ::iterator message; for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) - context.debug (*message); + context.footnote (*message); } else { diff --git a/src/commands/CmdConfig.cpp b/src/commands/CmdConfig.cpp index 52e883d45..8f7fcf802 100644 --- a/src/commands/CmdConfig.cpp +++ b/src/commands/CmdConfig.cpp @@ -107,8 +107,10 @@ int CmdConfig::unsetConfigVariable (std::string name, bool confirmation /* = fal bool change = false; std::vector ::iterator line; - for (line = contents.begin (); line != contents.end (); ++line) + for (line = contents.begin (); line != contents.end (); ) { + bool lineDeleted = false; + // If there is a comment on the line, it must follow the pattern. std::string::size_type comment = line->find ("#"); std::string::size_type pos = line->find (name + "="); @@ -123,10 +125,15 @@ int CmdConfig::unsetConfigVariable (std::string name, bool confirmation /* = fal if (!confirmation || confirm (format (STRING_CMD_CONFIG_CONFIRM3, name))) { - *line = ""; + // vector::erase method returns a valid iterator to the next object + line = contents.erase (line); + lineDeleted = true; change = true; } } + + if (! lineDeleted) + line++; } if (change) diff --git a/src/commands/CmdContext.cpp b/src/commands/CmdContext.cpp index 659f667a0..e689daeb5 100644 --- a/src/commands/CmdContext.cpp +++ b/src/commands/CmdContext.cpp @@ -26,9 +26,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -128,15 +130,35 @@ std::vector CmdContext::getContexts () int CmdContext::defineContext (std::vector & words, std::stringstream& out) { int rc = 0; + bool confirmation = context.config.getBoolean ("confirmation"); if (words.size () > 2) { std::string name = "context." + words[1]; std::string value = joinWords (words, 2); - // TODO: Check if the value is a proper filter + + // Check if the value is a proper filter by filtering current pending.data + Filter filter; + std::vector filtered; + const std::vector & pending = context.tdb2.pending.get_tasks (); + + try + { + context.cli.addRawFilter ("( " + value + " )"); + filter.subset (pending, filtered); + } + catch (std::string exception) + { + throw format (STRING_CMD_CONTEXT_DEF_ABRT2, exception); + } + + // Make user explicitly confirm filters that are matching no pending tasks + if (filtered.size () == 0) + if (confirmation && + ! confirm (format (STRING_CMD_CONTEXT_DEF_CONF, value))) + throw std::string (STRING_CMD_CONTEXT_DEF_ABRT); // Set context definition config variable - bool confirmation = context.config.getBoolean ("confirmation"); bool success = CmdConfig::setConfigVariable (name, value, confirmation); if (success) @@ -148,7 +170,10 @@ int CmdContext::defineContext (std::vector & words, std::stringstre } } else - throw STRING_CMD_CONTEXT_DEF_USAG; + { + out << STRING_CMD_CONTEXT_DEF_USAG << "\n"; + rc = 1; + } return rc; } @@ -188,7 +213,10 @@ int CmdContext::deleteContext (std::vector & words, std::stringstre out << format (STRING_CMD_CONTEXT_DEL_FAIL, words[1]) << "\n"; } else - throw STRING_CMD_CONTEXT_DEL_USAG; + { + out << STRING_CMD_CONTEXT_DEL_USAG << "\n"; + rc = 1; + } return rc; } diff --git a/src/l10n/deu-DEU.h b/src/l10n/deu-DEU.h index 20d76442b..a374165d1 100644 --- a/src/l10n/deu-DEU.h +++ b/src/l10n/deu-DEU.h @@ -565,12 +565,15 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}" +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/src/l10n/eng-USA.h b/src/l10n/eng-USA.h index cc7838142..112db87ae 100644 --- a/src/l10n/eng-USA.h +++ b/src/l10n/eng-USA.h @@ -565,12 +565,15 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}" +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/src/l10n/epo-RUS.h b/src/l10n/epo-RUS.h index cef22854d..057946ca3 100644 --- a/src/l10n/epo-RUS.h +++ b/src/l10n/epo-RUS.h @@ -565,12 +565,15 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}" +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/src/l10n/esp-ESP.h b/src/l10n/esp-ESP.h index 6eb6e64e3..d99053429 100644 --- a/src/l10n/esp-ESP.h +++ b/src/l10n/esp-ESP.h @@ -574,12 +574,15 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}" +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/src/l10n/fra-FRA.h b/src/l10n/fra-FRA.h index cdc7bbcb9..11d3b2cb6 100644 --- a/src/l10n/fra-FRA.h +++ b/src/l10n/fra-FRA.h @@ -565,12 +565,14 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/src/l10n/ita-ITA.h b/src/l10n/ita-ITA.h index b3ec61fb1..5e5255572 100644 --- a/src/l10n/ita-ITA.h +++ b/src/l10n/ita-ITA.h @@ -564,12 +564,15 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}" +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/src/l10n/pol-POL.h b/src/l10n/pol-POL.h index c296c2700..f3e2a0fcd 100644 --- a/src/l10n/pol-POL.h +++ b/src/l10n/pol-POL.h @@ -565,12 +565,15 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}" +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/src/l10n/por-PRT.h b/src/l10n/por-PRT.h index 1587291ae..97d9de571 100644 --- a/src/l10n/por-PRT.h +++ b/src/l10n/por-PRT.h @@ -565,12 +565,15 @@ #define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined." #define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined." #define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided." +#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted." +#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}" +#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?" #define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted." #define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted." #define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified." #define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined." #define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found." -#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' applied." +#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove." #define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied." #define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied." #define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied." diff --git a/test/context.t b/test/context.t index a185c77bc..b040ea83f 100755 --- a/test/context.t +++ b/test/context.t @@ -105,7 +105,7 @@ class ContextManagementTest(TestCase): output = self.t(('context', 'delete', 'work'))[1] # Assert correct output - self.assertIn("Context 'work' undefined.", output) + self.assertIn("Context 'work' deleted.", output) # Assert that taskrc does not countain context work definition self.assertFalse(any('context.work=' in line for line in self.t.taskrc_content)) @@ -118,7 +118,7 @@ class ContextManagementTest(TestCase): output = self.t.runError(('context', 'delete', 'work'))[1] # Assert correct output - self.assertIn("Context 'work' was not undefined.", output) + self.assertIn("Context 'work' not deleted.", output) # Assert that taskrc does not countain context work definition self.assertFalse(any('context.work=' in line for line in self.t.taskrc_content)) @@ -133,7 +133,7 @@ class ContextManagementTest(TestCase): output = self.t(('context', 'delete', 'work'))[1] # Assert correct output - self.assertIn("Context 'work' undefined.", output) + self.assertIn("Context 'work' deleted.", output) # Assert that taskrc does not countain context work definition self.assertFalse(any('context.work=' in line for line in self.t.taskrc_content)) @@ -182,7 +182,7 @@ class ContextManagementTest(TestCase): self.t(('context', 'define', 'home', '+home'))[1] output = self.t(('context', 'home'))[1] - self.assertIn("Context 'home' applied.", output) + self.assertIn("Context 'home' set.", output) self.assertIn("context=home\n", self.t.taskrc_content) def test_context_resetting(self): @@ -195,7 +195,7 @@ class ContextManagementTest(TestCase): self.t(('context', 'home'))[1] output = self.t(('context', 'home'))[1] - self.assertIn("Context 'home' applied.", output) + self.assertIn("Context 'home' set.", output) contains_home = lambda line: line == "context=home\n" self.assertEqual(len(filter(contains_home, self.t.taskrc_content)), 1) @@ -213,20 +213,20 @@ class ContextManagementTest(TestCase): # Switch to home context output = self.t(('context', 'home'))[1] - self.assertIn("Context 'home' applied.", output) + self.assertIn("Context 'home' set.", output) self.assertEqual(len(filter(contains_home, self.t.taskrc_content)), 1) # Switch to work context output = self.t(('context', 'work'))[1] - self.assertIn("Context 'work' applied.", output) + self.assertIn("Context 'work' set.", output) self.assertNotIn("context=home\n", self.t.taskrc_content) self.assertEqual(len(filter(contains_work, self.t.taskrc_content)), 1) # Switch back to home context output = self.t(('context', 'home'))[1] - self.assertIn("Context 'home' applied.", output) + self.assertIn("Context 'home' set.", output) self.assertNotIn("context=work\n", self.t.taskrc_content) self.assertEqual(len(filter(contains_home, self.t.taskrc_content)), 1)