mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
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:
parent
a39261f82d
commit
e0fd39db7b
8 changed files with 106 additions and 55 deletions
23
src/T.cpp
23
src/T.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
5
src/T.h
5
src/T.h
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue