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:
Paul Beckingham 2009-04-12 02:01:08 -04:00
parent a39261f82d
commit e0fd39db7b
8 changed files with 106 additions and 55 deletions

View file

@ -40,6 +40,9 @@ T::T ()
mTags.clear ();
mAttributes.clear ();
mDescription = "";
mFrom = "";
mTo = "";
mGlobal = false;
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;
to = mTo;
from = mFrom;
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;
mTo = to;
mFrom = from;
mTo = to;
mGlobal = global;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -58,8 +58,8 @@ public:
void setDescription (const std::string& description) { mDescription = description; }
int getAnnotationCount () const { return mAnnotations.size (); }
void getSubstitution (std::string&, std::string&) const;
void setSubstitution (const std::string&, const std::string&);
void getSubstitution (std::string&, std::string&, bool&) const;
void setSubstitution (const std::string&, const std::string&, bool);
bool hasTag (const std::string&) const;
@ -101,6 +101,7 @@ private:
std::map<std::string, std::string> mAttributes;
std::string mFrom;
std::string mTo;
bool mGlobal;
std::map <time_t, std::string> mAnnotations;
};

View file

@ -756,40 +756,67 @@ std::string handleModify (TDB& tdb, T& task, Config& conf)
std::string from;
std::string to;
task.getSubstitution (from, to);
bool global;
task.getSubstitution (from, to, global);
if (from != "")
{
std::string description = original.getDescription ();
size_t pattern = description.find (from);
if (pattern != std::string::npos)
size_t pattern;
if (global)
{
description = description.substr (0, pattern) +
to +
description.substr (pattern + from.length (), std::string::npos);
// Perform all subs on description.
while ((pattern = description.find (from)) != std::string::npos)
{
description.replace (pattern, from.length (), to);
++changes;
}
original.setDescription (description);
++changes;
}
else
{
// Perform all subs on annotations.
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)
{
size_t pattern = it->second.find (from);
if (pattern != std::string::npos)
while ((pattern = it->second.find (from)) != std::string::npos)
{
it->second = it->second.substr (0, pattern) +
to +
it->second.substr (pattern + from.length (), std::string::npos);
it->second.replace (pattern, from.length (), to);
++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);
}
}
}
@ -879,23 +906,6 @@ std::string handleAppend (TDB& tdb, T& task, Config& conf)
++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)
{
tdb.modifyT (original);

View file

@ -348,7 +348,8 @@ static bool validCommand (std::string& input)
static bool validSubstitution (
std::string& input,
std::string& from,
std::string& to)
std::string& to,
bool& global)
{
size_t first = input.find ('/');
if (first != std::string::npos)
@ -362,10 +363,17 @@ static bool validSubstitution (
if (first == 0 &&
first < second &&
second < third &&
third == input.length () - 1)
(third == input.length () - 1 ||
third == input.length () - 2))
{
from = input.substr (first + 1, second - first - 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;
}
}
@ -411,6 +419,7 @@ void parse (
size_t colon; // Pointer to colon in argument.
std::string from;
std::string to;
bool global;
// An id is the first argument found that contains all digits.
if (lowerCase (command) != "add" && // "add" doesn't require an ID
@ -451,9 +460,9 @@ void parse (
}
// 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.

View file

@ -28,7 +28,7 @@
use strict;
use warnings;
use Test::More tests => 5;
use Test::More tests => 7;
# Create the rc file.
if (open my $fh, '>', 'subst.rc')
@ -39,16 +39,24 @@ if (open my $fh, '>', 'subst.rc')
}
# 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/};
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.
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/};
$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.
unlink 'pending.data';