Enhancement - substitutions /from/to/g
- Added support for the "g" modifier to the substitution command, that replace every occurrence of "from" with "to", in the task description and any annotations.
This commit is contained in:
@@ -40,6 +40,8 @@
|
|||||||
date, because of an assumption of 365 days per year, which failed to
|
date, because of an assumption of 365 days per year, which failed to
|
||||||
consider leap years (thanks to T. Charles Yun).
|
consider leap years (thanks to T. Charles Yun).
|
||||||
+ Annotations can now be modified with the substitution commands /from/to/.
|
+ Annotations can now be modified with the substitution commands /from/to/.
|
||||||
|
+ Substitutions can now be made global with /from/to/g and all occurrences
|
||||||
|
of "from" will be replaced with "to".
|
||||||
|
|
||||||
------ old releases ------------------------------
|
------ old releases ------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ ID Project Pri Description
|
|||||||
set via the "newest" configuration variable.
|
set via the "newest" configuration variable.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<strong>% task /from/to/</strong>
|
<strong>% task <id> /from/to/</strong>
|
||||||
<p>
|
<p>
|
||||||
If a task has been entered with a typo, it can be easily corrected
|
If a task has been entered with a typo, it can be easily corrected
|
||||||
by this command. For example:
|
by this command. For example:
|
||||||
@@ -309,14 +309,22 @@ ID Project Pri Description
|
|||||||
...</code></pre>
|
...</code></pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This command makes single corrections to a task description.
|
This command makes a single correction to the first occurrence of
|
||||||
|
"from" in a task description.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
If a task is annotated, the annotation can be modified using
|
If a task is annotated, the annotation can also be modified using
|
||||||
this command.
|
this command.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<strong>% task <id> /from/to/g</strong>
|
||||||
|
<p>
|
||||||
|
The "g" modifier to the substitution command causes every occurrence
|
||||||
|
of "from" to be replaced with "to", in both the description and any
|
||||||
|
annotations.
|
||||||
|
</p>
|
||||||
|
|
||||||
<strong>% task tags</strong>
|
<strong>% task tags</strong>
|
||||||
<p>
|
<p>
|
||||||
This command will generate a list of all the tags that are currently
|
This command will generate a list of all the tags that are currently
|
||||||
|
|||||||
@@ -145,6 +145,8 @@
|
|||||||
date, because of an assumption of 365 days per year, which failed to
|
date, because of an assumption of 365 days per year, which failed to
|
||||||
consider leap years (thanks to T. Charles Yun).
|
consider leap years (thanks to T. Charles Yun).
|
||||||
<li>Annotations can now be modified with the substitution commands /from/to/.
|
<li>Annotations can now be modified with the substitution commands /from/to/.
|
||||||
|
<li>Substitutions can now be made global with /from/to/g and all occurrences
|
||||||
|
of "from" will be replaced with "to".
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
23
src/T.cpp
23
src/T.cpp
@@ -40,6 +40,9 @@ T::T ()
|
|||||||
mTags.clear ();
|
mTags.clear ();
|
||||||
mAttributes.clear ();
|
mAttributes.clear ();
|
||||||
mDescription = "";
|
mDescription = "";
|
||||||
|
mFrom = "";
|
||||||
|
mTo = "";
|
||||||
|
mGlobal = false;
|
||||||
mAnnotations.clear ();
|
mAnnotations.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,17 +243,25 @@ void T::removeAttribute (const std::string& name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void T::getSubstitution (std::string& from, std::string& to) const
|
void T::getSubstitution (
|
||||||
|
std::string& from,
|
||||||
|
std::string& to,
|
||||||
|
bool& global) const
|
||||||
{
|
{
|
||||||
from = mFrom;
|
from = mFrom;
|
||||||
to = mTo;
|
to = mTo;
|
||||||
|
global = mGlobal;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void T::setSubstitution (const std::string& from, const std::string& to)
|
void T::setSubstitution (
|
||||||
|
const std::string& from,
|
||||||
|
const std::string& to,
|
||||||
|
bool global)
|
||||||
{
|
{
|
||||||
mFrom = from;
|
mFrom = from;
|
||||||
mTo = to;
|
mTo = to;
|
||||||
|
mGlobal = global;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
5
src/T.h
5
src/T.h
@@ -58,8 +58,8 @@ public:
|
|||||||
void setDescription (const std::string& description) { mDescription = description; }
|
void setDescription (const std::string& description) { mDescription = description; }
|
||||||
int getAnnotationCount () const { return mAnnotations.size (); }
|
int getAnnotationCount () const { return mAnnotations.size (); }
|
||||||
|
|
||||||
void getSubstitution (std::string&, std::string&) const;
|
void getSubstitution (std::string&, std::string&, bool&) const;
|
||||||
void setSubstitution (const std::string&, const std::string&);
|
void setSubstitution (const std::string&, const std::string&, bool);
|
||||||
|
|
||||||
bool hasTag (const std::string&) const;
|
bool hasTag (const std::string&) const;
|
||||||
|
|
||||||
@@ -101,6 +101,7 @@ private:
|
|||||||
std::map<std::string, std::string> mAttributes;
|
std::map<std::string, std::string> mAttributes;
|
||||||
std::string mFrom;
|
std::string mFrom;
|
||||||
std::string mTo;
|
std::string mTo;
|
||||||
|
bool mGlobal;
|
||||||
std::map <time_t, std::string> mAnnotations;
|
std::map <time_t, std::string> mAnnotations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -756,40 +756,67 @@ std::string handleModify (TDB& tdb, T& task, Config& conf)
|
|||||||
|
|
||||||
std::string from;
|
std::string from;
|
||||||
std::string to;
|
std::string to;
|
||||||
task.getSubstitution (from, to);
|
bool global;
|
||||||
|
task.getSubstitution (from, to, global);
|
||||||
if (from != "")
|
if (from != "")
|
||||||
{
|
{
|
||||||
std::string description = original.getDescription ();
|
std::string description = original.getDescription ();
|
||||||
size_t pattern = description.find (from);
|
size_t pattern;
|
||||||
if (pattern != std::string::npos)
|
|
||||||
|
if (global)
|
||||||
{
|
{
|
||||||
description = description.substr (0, pattern) +
|
// Perform all subs on description.
|
||||||
to +
|
while ((pattern = description.find (from)) != std::string::npos)
|
||||||
description.substr (pattern + from.length (), std::string::npos);
|
{
|
||||||
|
description.replace (pattern, from.length (), to);
|
||||||
|
++changes;
|
||||||
|
}
|
||||||
|
|
||||||
original.setDescription (description);
|
original.setDescription (description);
|
||||||
++changes;
|
|
||||||
}
|
// Perform all subs on annotations.
|
||||||
else
|
|
||||||
{
|
|
||||||
std::map <time_t, std::string> annotations;
|
std::map <time_t, std::string> annotations;
|
||||||
original.getAnnotations (annotations);
|
original.getAnnotations (annotations);
|
||||||
|
|
||||||
std::map <time_t, std::string>::iterator it;
|
std::map <time_t, std::string>::iterator it;
|
||||||
for (it = annotations.begin (); it != annotations.end (); ++it)
|
for (it = annotations.begin (); it != annotations.end (); ++it)
|
||||||
{
|
{
|
||||||
size_t pattern = it->second.find (from);
|
while ((pattern = it->second.find (from)) != std::string::npos)
|
||||||
if (pattern != std::string::npos)
|
|
||||||
{
|
{
|
||||||
it->second = it->second.substr (0, pattern) +
|
it->second.replace (pattern, from.length (), to);
|
||||||
to +
|
|
||||||
it->second.substr (pattern + from.length (), std::string::npos);
|
|
||||||
++changes;
|
++changes;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changes)
|
original.setAnnotations (annotations);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Perform first description substitution.
|
||||||
|
if ((pattern = description.find (from)) != std::string::npos)
|
||||||
|
{
|
||||||
|
description.replace (pattern, from.length (), to);
|
||||||
|
original.setDescription (description);
|
||||||
|
++changes;
|
||||||
|
}
|
||||||
|
// Failing that, perform the first annotation substitution.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::map <time_t, std::string> annotations;
|
||||||
|
original.getAnnotations (annotations);
|
||||||
|
|
||||||
|
std::map <time_t, std::string>::iterator it;
|
||||||
|
for (it = annotations.begin (); it != annotations.end (); ++it)
|
||||||
|
{
|
||||||
|
if ((pattern = it->second.find (from)) != std::string::npos)
|
||||||
|
{
|
||||||
|
it->second.replace (pattern, from.length (), to);
|
||||||
|
++changes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
original.setAnnotations (annotations);
|
original.setAnnotations (annotations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -879,23 +906,6 @@ std::string handleAppend (TDB& tdb, T& task, Config& conf)
|
|||||||
++changes;
|
++changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string from;
|
|
||||||
std::string to;
|
|
||||||
task.getSubstitution (from, to);
|
|
||||||
if (from != "")
|
|
||||||
{
|
|
||||||
std::string description = original.getDescription ();
|
|
||||||
size_t pattern = description.find (from);
|
|
||||||
if (pattern != std::string::npos)
|
|
||||||
{
|
|
||||||
description = description.substr (0, pattern) +
|
|
||||||
to +
|
|
||||||
description.substr (pattern + from.length (), std::string::npos);
|
|
||||||
original.setDescription (description);
|
|
||||||
++changes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changes)
|
if (changes)
|
||||||
{
|
{
|
||||||
tdb.modifyT (original);
|
tdb.modifyT (original);
|
||||||
|
|||||||
@@ -348,7 +348,8 @@ static bool validCommand (std::string& input)
|
|||||||
static bool validSubstitution (
|
static bool validSubstitution (
|
||||||
std::string& input,
|
std::string& input,
|
||||||
std::string& from,
|
std::string& from,
|
||||||
std::string& to)
|
std::string& to,
|
||||||
|
bool& global)
|
||||||
{
|
{
|
||||||
size_t first = input.find ('/');
|
size_t first = input.find ('/');
|
||||||
if (first != std::string::npos)
|
if (first != std::string::npos)
|
||||||
@@ -362,10 +363,17 @@ static bool validSubstitution (
|
|||||||
if (first == 0 &&
|
if (first == 0 &&
|
||||||
first < second &&
|
first < second &&
|
||||||
second < third &&
|
second < third &&
|
||||||
third == input.length () - 1)
|
(third == input.length () - 1 ||
|
||||||
|
third == input.length () - 2))
|
||||||
{
|
{
|
||||||
from = input.substr (first + 1, second - first - 1);
|
from = input.substr (first + 1, second - first - 1);
|
||||||
to = input.substr (second + 1, third - second - 1);
|
to = input.substr (second + 1, third - second - 1);
|
||||||
|
|
||||||
|
global = false;
|
||||||
|
if (third == input.length () - 2 &&
|
||||||
|
input.find ('g', third + 1) != std::string::npos)
|
||||||
|
global = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,6 +419,7 @@ void parse (
|
|||||||
size_t colon; // Pointer to colon in argument.
|
size_t colon; // Pointer to colon in argument.
|
||||||
std::string from;
|
std::string from;
|
||||||
std::string to;
|
std::string to;
|
||||||
|
bool global;
|
||||||
|
|
||||||
// An id is the first argument found that contains all digits.
|
// An id is the first argument found that contains all digits.
|
||||||
if (lowerCase (command) != "add" && // "add" doesn't require an ID
|
if (lowerCase (command) != "add" && // "add" doesn't require an ID
|
||||||
@@ -451,9 +460,9 @@ void parse (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Substitution of description text.
|
// Substitution of description text.
|
||||||
else if (validSubstitution (arg, from, to))
|
else if (validSubstitution (arg, from, to, global))
|
||||||
{
|
{
|
||||||
task.setSubstitution (from, to);
|
task.setSubstitution (from, to, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command.
|
// Command.
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Test::More tests => 5;
|
use Test::More tests => 7;
|
||||||
|
|
||||||
# Create the rc file.
|
# Create the rc file.
|
||||||
if (open my $fh, '>', 'subst.rc')
|
if (open my $fh, '>', 'subst.rc')
|
||||||
@@ -39,16 +39,24 @@ if (open my $fh, '>', 'subst.rc')
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Test the substitution command.
|
# Test the substitution command.
|
||||||
qx{../task rc:subst.rc add foo};
|
qx{../task rc:subst.rc add foo foo foo};
|
||||||
qx{../task rc:subst.rc 1 /foo/FOO/};
|
qx{../task rc:subst.rc 1 /foo/FOO/};
|
||||||
my $output = qx{../task rc:subst.rc info 1};
|
my $output = qx{../task rc:subst.rc info 1};
|
||||||
like ($output, qr/FOO/, 'substitution in description');
|
like ($output, qr/FOO foo foo/, 'substitution in description');
|
||||||
|
|
||||||
|
qx{../task rc:subst.rc 1 /foo/FOO/g};
|
||||||
|
my $output = qx{../task rc:subst.rc info 1};
|
||||||
|
like ($output, qr/FOO FOO FOO/, 'global substitution in description');
|
||||||
|
|
||||||
# Test the substitution command on annotations.
|
# Test the substitution command on annotations.
|
||||||
qx{../task rc:subst.rc annotate 1 bar};
|
qx{../task rc:subst.rc annotate 1 bar bar bar};
|
||||||
qx{../task rc:subst.rc 1 /bar/BAR/};
|
qx{../task rc:subst.rc 1 /bar/BAR/};
|
||||||
$output = qx{../task rc:subst.rc info 1};
|
$output = qx{../task rc:subst.rc info 1};
|
||||||
like ($output, qr/BAR/, 'substitution in annotation');
|
like ($output, qr/BAR bar bar/, 'substitution in annotation');
|
||||||
|
|
||||||
|
qx{../task rc:subst.rc 1 /bar/BAR/g};
|
||||||
|
$output = qx{../task rc:subst.rc info 1};
|
||||||
|
like ($output, qr/BAR BAR BAR/, 'global substitution in annotation');
|
||||||
|
|
||||||
# Cleanup.
|
# Cleanup.
|
||||||
unlink 'pending.data';
|
unlink 'pending.data';
|
||||||
|
|||||||
Reference in New Issue
Block a user