Merge branch '2.4.2' into lexer2

This commit is contained in:
Paul Beckingham 2015-02-24 17:03:11 -05:00
commit 8c6892fed6
15 changed files with 89 additions and 30 deletions

View file

@ -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 ---------------------------

View file

@ -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

View file

@ -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));
}
}

View file

@ -141,7 +141,7 @@ void Hooks::onLaunch ()
{
std::vector <std::string>::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 <std::string>::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 <std::string>::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 <std::string>::iterator message;
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
context.debug (*message);
context.footnote (*message);
}
else
{

View file

@ -107,8 +107,10 @@ int CmdConfig::unsetConfigVariable (std::string name, bool confirmation /* = fal
bool change = false;
std::vector <std::string>::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)

View file

@ -26,9 +26,11 @@
#include <cmake.h>
#include <Context.h>
#include <Filter.h>
#include <sstream>
#include <algorithm>
#include <i18n.h>
#include <util.h>
#include <text.h>
#include <CmdContext.h>
#include <CmdConfig.h>
@ -128,15 +130,35 @@ std::vector <std::string> CmdContext::getContexts ()
int CmdContext::defineContext (std::vector <std::string>& 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 <Task> filtered;
const std::vector <Task>& 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 <std::string>& 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 <std::string>& 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;
}

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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)