mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-08 04:07:40 +02:00
[PowerRename] Introduce advanced counter functionality (#27895)
This commit is contained in:
46
src/modules/powerrename/lib/Enumerating.cpp
Normal file
46
src/modules/powerrename/lib/Enumerating.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <pch.h>
|
||||
|
||||
#include "Enumerating.h"
|
||||
|
||||
#include <common\utils\string_utils.h>
|
||||
|
||||
std::vector<EnumOptions> parseEnumOptions(const std::wstring& replaceWith)
|
||||
{
|
||||
static const std::wregex enumStartRegex(LR"(start=(\d+))");
|
||||
static const std::wregex enumIncrementRegex(LR"(increment=(-?\d+))");
|
||||
static const std::wregex enumPaddingRegex(LR"(padding=(\d+))");
|
||||
|
||||
std::string buf;
|
||||
std::vector<EnumOptions> options;
|
||||
std::wregex enumGroupRegex(LR"(\$\{.*?\})");
|
||||
for (std::wsregex_iterator i{ begin(replaceWith), end(replaceWith), enumGroupRegex }, end; i != end; ++i)
|
||||
{
|
||||
std::wsmatch match = *i;
|
||||
std::wstring matchString = match.str();
|
||||
|
||||
EnumOptions option;
|
||||
option.replaceStrSpan.offset = match.position();
|
||||
option.replaceStrSpan.length = match.length();
|
||||
|
||||
std::wsmatch subMatch;
|
||||
if (std::regex_search(matchString, subMatch, enumStartRegex))
|
||||
{
|
||||
buf = unwide(subMatch[1].str());
|
||||
std::from_chars(buf.data(), buf.data() + buf.size(), option.start.emplace());
|
||||
}
|
||||
if (std::regex_search(matchString, subMatch, enumIncrementRegex))
|
||||
{
|
||||
buf = unwide(subMatch[1].str());
|
||||
std::from_chars(buf.data(), buf.data() + buf.size(), option.increment.emplace());
|
||||
}
|
||||
if (std::regex_search(matchString, subMatch, enumPaddingRegex))
|
||||
{
|
||||
buf = unwide(subMatch[1].str());
|
||||
std::from_chars(buf.data(), buf.data() + buf.size(), option.padding.emplace());
|
||||
}
|
||||
|
||||
options.emplace_back(std::move(option));
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
55
src/modules/powerrename/lib/Enumerating.h
Normal file
55
src/modules/powerrename/lib/Enumerating.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
struct EnumSpan
|
||||
{
|
||||
size_t offset = 0;
|
||||
size_t length = 0;
|
||||
};
|
||||
|
||||
struct EnumOptions
|
||||
{
|
||||
std::optional<int> start;
|
||||
std::optional<int> increment;
|
||||
std::optional<uint32_t> padding;
|
||||
|
||||
EnumSpan replaceStrSpan;
|
||||
|
||||
std::strong_ordering operator<=>(const EnumOptions& rhs) const noexcept
|
||||
{
|
||||
return std::make_tuple(start, increment, padding) <=> std::make_tuple(rhs.start, rhs.increment, rhs.padding);
|
||||
}
|
||||
|
||||
bool operator==(const EnumOptions& rhs) const noexcept
|
||||
{
|
||||
return std::make_tuple(start, increment, padding) == std::make_tuple(rhs.start, rhs.increment, rhs.padding);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<EnumOptions> parseEnumOptions(const std::wstring& replaceWith);
|
||||
|
||||
struct Enumerator
|
||||
{
|
||||
inline Enumerator(EnumOptions options) :
|
||||
start{ options.start.value_or(0) }, increment{ options.increment.value_or(1) }, padding{ options.padding.value_or(0) }, replaceStrSpan{ options.replaceStrSpan }
|
||||
{
|
||||
}
|
||||
|
||||
inline int32_t enumerate(const unsigned long index) const { return start + static_cast<int32_t>(index * increment); }
|
||||
|
||||
inline size_t printTo(wchar_t* buf, const size_t bufSize, const unsigned long index) const
|
||||
{
|
||||
const int32_t enumeratedIndex = enumerate(index);
|
||||
wchar_t format[32];
|
||||
swprintf_s(format, sizeof(format) / sizeof(wchar_t), L"%%0%ud", padding);
|
||||
return swprintf_s(buf, bufSize, format, enumeratedIndex);
|
||||
}
|
||||
|
||||
EnumSpan replaceStrSpan;
|
||||
|
||||
private:
|
||||
int start;
|
||||
int increment;
|
||||
uint32_t padding;
|
||||
};
|
||||
@@ -188,7 +188,7 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
|
||||
{
|
||||
hr = StringCchCopy(result, cchMax, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (flags & Capitalized)
|
||||
{
|
||||
if (!(flags & ExtensionOnly))
|
||||
@@ -234,15 +234,13 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool isFileTimeUsed(_In_ PCWSTR source)
|
||||
bool isFileTimeUsed(_In_ PCWSTR source)
|
||||
{
|
||||
bool used = false;
|
||||
std::wstring patterns[] = { L"(([^\\$]|^)(\\$\\$)*)\\$Y", L"(([^\\$]|^)(\\$\\$)*)\\$M", L"(([^\\$]|^)(\\$\\$)*)\\$D",
|
||||
L"(([^\\$]|^)(\\$\\$)*)\\$h", L"(([^\\$]|^)(\\$\\$)*)\\$m", L"(([^\\$]|^)(\\$\\$)*)\\$s", L"(([^\\$]|^)(\\$\\$)*)\\$f" };
|
||||
size_t patternsLength = ARRAYSIZE(patterns);
|
||||
for (size_t i = 0; !used && i < patternsLength; i++)
|
||||
static const std::array patterns = { std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$Y" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$M" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$D" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$h" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$m" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$s" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$f" } };
|
||||
for (size_t i = 0; !used && i < patterns.size(); i++)
|
||||
{
|
||||
if (std::regex_search(source, std::wregex(patterns[i])))
|
||||
if (std::regex_search(source, patterns[i]))
|
||||
{
|
||||
used = true;
|
||||
}
|
||||
@@ -253,7 +251,7 @@ bool isFileTimeUsed(_In_ PCWSTR source)
|
||||
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME fileTime)
|
||||
{
|
||||
std::locale::global(std::locale(""));
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
if (source && wcslen(source) > 0)
|
||||
{
|
||||
std::wstring res(source);
|
||||
@@ -274,17 +272,17 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", (fileTime.wYear % 10));
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$Y"), replaceTerm);
|
||||
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &fileTime, L"MMMM", formattedDate, MAX_PATH, NULL);
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMMM"), replaceTerm);
|
||||
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &fileTime, L"MMM", formattedDate, MAX_PATH, NULL);
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMM"), replaceTerm);
|
||||
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMonth);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MM"), replaceTerm);
|
||||
|
||||
@@ -295,7 +293,7 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$DDDD"), replaceTerm);
|
||||
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &fileTime, L"ddd", formattedDate, MAX_PATH, NULL);
|
||||
formattedDate[0] = towupper(formattedDate[0]);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
|
||||
@@ -328,10 +326,10 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%03d"), L"$01", fileTime.wMilliseconds);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$fff"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMilliseconds/10);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMilliseconds / 10);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$ff"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", fileTime.wMilliseconds/100);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", fileTime.wMilliseconds / 100);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$f"), replaceTerm);
|
||||
|
||||
hr = StringCchCopy(result, cchMax, res.c_str());
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
IFACEMETHOD(PutFlags)(_In_ DWORD flags) = 0;
|
||||
IFACEMETHOD(PutFileTime)(_In_ SYSTEMTIME fileTime) = 0;
|
||||
IFACEMETHOD(ResetFileTime)() = 0;
|
||||
IFACEMETHOD(Replace)(_In_ PCWSTR source, _Outptr_ PWSTR* result) = 0;
|
||||
IFACEMETHOD(Replace)(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex) = 0;
|
||||
};
|
||||
|
||||
interface __declspec(uuid("C7F59201-4DE1-4855-A3A2-26FC3279C8A5")) IPowerRenameItem : public IUnknown
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Enumerating.h" />
|
||||
<ClInclude Include="Helpers.h" />
|
||||
<ClInclude Include="MRUListHandler.h" />
|
||||
<ClInclude Include="PowerRenameEnum.h" />
|
||||
@@ -47,6 +48,7 @@
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Enumerating.cpp" />
|
||||
<ClCompile Include="Helpers.cpp" />
|
||||
<ClCompile Include="MRUListHandler.cpp" />
|
||||
<ClCompile Include="PowerRenameEnum.cpp" />
|
||||
|
||||
@@ -923,7 +923,7 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
|
||||
winrt::check_hresult(pwtd->spsrm->GetRenameRegEx(&spRenameRegEx));
|
||||
|
||||
UINT itemCount = 0;
|
||||
unsigned long itemEnumIndex = 1;
|
||||
unsigned long itemEnumIndex = 0;
|
||||
winrt::check_hresult(pwtd->spsrm->GetItemCount(&itemCount));
|
||||
|
||||
for (UINT u = 0; u < itemCount; u++)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "PowerRenameRegEx.h"
|
||||
#include "Enumerating.h"
|
||||
#include "Settings.h"
|
||||
#include <regex>
|
||||
#include <string>
|
||||
@@ -7,15 +8,17 @@
|
||||
#include <boost/regex.hpp>
|
||||
#include <helpers.h>
|
||||
|
||||
using namespace std;
|
||||
using std::conditional_t;
|
||||
using std::regex_error;
|
||||
|
||||
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::AddRef()
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
CPowerRenameRegEx::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::Release()
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
CPowerRenameRegEx::Release()
|
||||
{
|
||||
long refCount = InterlockedDecrement(&m_refCount);
|
||||
|
||||
@@ -127,6 +130,26 @@ IFACEMETHODIMP CPowerRenameRegEx::GetReplaceTerm(_Outptr_ PWSTR* replaceTerm)
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameRegEx::_OnEnumerateItemsChanged()
|
||||
{
|
||||
m_enumerators.clear();
|
||||
const auto options = parseEnumOptions(m_RawReplaceTerm);
|
||||
for (const auto e : options)
|
||||
m_enumerators.emplace_back(e);
|
||||
|
||||
m_replaceWithEnumeratorOffsets.clear();
|
||||
std::wstring replaceWith{ m_RawReplaceTerm };
|
||||
// Remove counter expressions and calculate their offsets in replaceWith string.
|
||||
int32_t offset = 0;
|
||||
for (const auto& e : options)
|
||||
{
|
||||
replaceWith.erase(e.replaceStrSpan.offset + offset, e.replaceStrSpan.length);
|
||||
m_replaceWithEnumeratorOffsets.push_back(offset);
|
||||
offset -= static_cast<int32_t>(e.replaceStrSpan.length);
|
||||
}
|
||||
return SHStrDup(replaceWith.data(), &m_replaceTerm);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP CPowerRenameRegEx::PutReplaceTerm(_In_ PCWSTR replaceTerm, bool forceRenaming)
|
||||
{
|
||||
bool changed = false || forceRenaming;
|
||||
@@ -134,11 +157,16 @@ IFACEMETHODIMP CPowerRenameRegEx::PutReplaceTerm(_In_ PCWSTR replaceTerm, bool f
|
||||
if (replaceTerm)
|
||||
{
|
||||
CSRWExclusiveAutoLock lock(&m_lock);
|
||||
if (m_replaceTerm == nullptr || lstrcmp(replaceTerm, m_replaceTerm) != 0)
|
||||
if (m_replaceTerm == nullptr || lstrcmp(replaceTerm, m_RawReplaceTerm.c_str()) != 0)
|
||||
{
|
||||
changed = true;
|
||||
CoTaskMemFree(m_replaceTerm);
|
||||
hr = SHStrDup(replaceTerm, &m_replaceTerm);
|
||||
m_RawReplaceTerm = replaceTerm;
|
||||
|
||||
if (m_flags & EnumerateItems)
|
||||
hr = _OnEnumerateItemsChanged();
|
||||
else
|
||||
hr = SHStrDup(replaceTerm, &m_replaceTerm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +188,20 @@ IFACEMETHODIMP CPowerRenameRegEx::PutFlags(_In_ DWORD flags)
|
||||
{
|
||||
if (m_flags != flags)
|
||||
{
|
||||
const bool newEnumerate = flags & EnumerateItems;
|
||||
const bool refreshReplaceTerm = !!(m_flags & EnumerateItems) != newEnumerate;
|
||||
m_flags = flags;
|
||||
if (refreshReplaceTerm)
|
||||
{
|
||||
CSRWExclusiveAutoLock lock(&m_lock);
|
||||
if (newEnumerate)
|
||||
_OnEnumerateItemsChanged();
|
||||
else
|
||||
{
|
||||
CoTaskMemFree(m_replaceTerm);
|
||||
SHStrDup(m_RawReplaceTerm.c_str(), &m_replaceTerm);
|
||||
}
|
||||
}
|
||||
_OnFlagsChanged();
|
||||
}
|
||||
return S_OK;
|
||||
@@ -202,7 +243,7 @@ HRESULT CPowerRenameRegEx::s_CreateInstance(_Outptr_ IPowerRenameRegEx** renameR
|
||||
{
|
||||
*renameRegEx = nullptr;
|
||||
|
||||
CPowerRenameRegEx *newRenameRegEx = new CPowerRenameRegEx();
|
||||
CPowerRenameRegEx* newRenameRegEx = new CPowerRenameRegEx();
|
||||
HRESULT hr = E_OUTOFMEMORY;
|
||||
if (newRenameRegEx)
|
||||
{
|
||||
@@ -228,7 +269,20 @@ CPowerRenameRegEx::~CPowerRenameRegEx()
|
||||
CoTaskMemFree(m_replaceTerm);
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
template<bool Std, class Regex = conditional_t<Std, std::wregex, boost::wregex>, class Options = decltype(Regex::icase)>
|
||||
static std::wstring RegexReplaceEx(const std::wstring& source, const std::wstring& searchTerm, const std::wstring& replaceTerm, const bool matchAll, const bool caseInsensitive)
|
||||
{
|
||||
Regex pattern(searchTerm, Options::ECMAScript | (caseInsensitive ? Options::icase : Options{}));
|
||||
|
||||
using Flags = conditional_t<Std, std::regex_constants::match_flag_type, boost::regex_constants::match_flags>;
|
||||
const auto flags = matchAll ? Flags::match_default : Flags::format_first_only;
|
||||
|
||||
return regex_replace(source, pattern, replaceTerm, flags);
|
||||
}
|
||||
|
||||
static constexpr std::array RegexReplaceDispatch = { RegexReplaceEx<true>, RegexReplaceEx<false> };
|
||||
|
||||
HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex)
|
||||
{
|
||||
*result = nullptr;
|
||||
|
||||
@@ -238,7 +292,7 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
wstring res = source;
|
||||
std::wstring res = source;
|
||||
try
|
||||
{
|
||||
// TODO: creating the regex could be costly. May want to cache this.
|
||||
@@ -250,47 +304,49 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
fileTimeErrorOccurred = true;
|
||||
}
|
||||
|
||||
std::wstring sourceToUse(source);
|
||||
std::wstring sourceToUse;
|
||||
std::wstring originalSource;
|
||||
sourceToUse.reserve(MAX_PATH);
|
||||
originalSource.reserve(MAX_PATH);
|
||||
sourceToUse = source;
|
||||
originalSource = sourceToUse;
|
||||
|
||||
std::wstring searchTerm(m_searchTerm);
|
||||
std::wstring replaceTerm(L"");
|
||||
std::wstring replaceTerm;
|
||||
if (m_useFileTime && !fileTimeErrorOccurred)
|
||||
{
|
||||
replaceTerm = wstring(newReplaceTerm);
|
||||
replaceTerm = newReplaceTerm;
|
||||
}
|
||||
else if (m_replaceTerm)
|
||||
{
|
||||
replaceTerm = wstring(m_replaceTerm);
|
||||
replaceTerm = m_replaceTerm;
|
||||
}
|
||||
|
||||
replaceTerm = regex_replace(replaceTerm, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$[0]"), L"$1$$$0");
|
||||
replaceTerm = regex_replace(replaceTerm, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$([1-9])"), L"$1$0$4");
|
||||
static const std::wregex zeroGroupRegex(L"(([^\\$]|^)(\\$\\$)*)\\$[0]");
|
||||
static const std::wregex otherGroupsRegex(L"(([^\\$]|^)(\\$\\$)*)\\$([1-9])");
|
||||
|
||||
if (m_flags & EnumerateItems)
|
||||
{
|
||||
std::array<wchar_t, MAX_PATH> buffer;
|
||||
int32_t offset = 0;
|
||||
|
||||
for (size_t ei = 0; ei < m_enumerators.size(); ++ei)
|
||||
{
|
||||
const auto& e = m_enumerators[ei];
|
||||
const auto replacementLength = static_cast<int32_t>(e.printTo(buffer.data(), buffer.size(), enumIndex));
|
||||
replaceTerm.insert(e.replaceStrSpan.offset + offset + m_replaceWithEnumeratorOffsets[ei], buffer.data());
|
||||
offset += replacementLength;
|
||||
}
|
||||
}
|
||||
|
||||
bool replacedSomething = false;
|
||||
if (m_flags & UseRegularExpressions)
|
||||
{
|
||||
if (_useBoostLib)
|
||||
{
|
||||
boost::wregex pattern(m_searchTerm, (!(m_flags & CaseSensitive)) ? boost::regex::icase | boost::regex::ECMAScript : boost::regex::ECMAScript);
|
||||
if (m_flags & MatchAllOccurrences)
|
||||
{
|
||||
res = boost::regex_replace(wstring(source), pattern, replaceTerm);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = boost::regex_replace(wstring(source), pattern, replaceTerm, boost::regex_constants::format_first_only);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wregex pattern(m_searchTerm, (!(m_flags & CaseSensitive)) ? regex_constants::icase | regex_constants::ECMAScript : regex_constants::ECMAScript);
|
||||
if (m_flags & MatchAllOccurrences)
|
||||
{
|
||||
res = regex_replace(wstring(source), pattern, replaceTerm);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = regex_replace(wstring(source), pattern, replaceTerm, regex_constants::format_first_only);
|
||||
}
|
||||
}
|
||||
replaceTerm = regex_replace(replaceTerm, zeroGroupRegex, L"$1$$$0");
|
||||
replaceTerm = regex_replace(replaceTerm, otherGroupsRegex, L"$1$0$4");
|
||||
|
||||
res = RegexReplaceDispatch[_useBoostLib](source, m_searchTerm, replaceTerm, m_flags & MatchAllOccurrences, !(m_flags & CaseSensitive));
|
||||
replacedSomething = originalSource != res;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -303,16 +359,17 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
|
||||
{
|
||||
res = sourceToUse.replace(pos, searchTerm.length(), replaceTerm);
|
||||
pos += replaceTerm.length();
|
||||
replacedSomething = true;
|
||||
}
|
||||
|
||||
if (!(m_flags & MatchAllOccurrences))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (pos != std::string::npos);
|
||||
}
|
||||
|
||||
hr = SHStrDup(res.c_str(), result);
|
||||
if (replacedSomething)
|
||||
enumIndex++;
|
||||
}
|
||||
catch (regex_error e)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "srwlock.h"
|
||||
|
||||
#include "Enumerating.h"
|
||||
#include "PowerRenameInterfaces.h"
|
||||
|
||||
#define DEFAULT_FLAGS 0
|
||||
@@ -12,7 +11,7 @@ class CPowerRenameRegEx : public IPowerRenameRegEx
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
|
||||
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
@@ -27,9 +26,9 @@ public:
|
||||
IFACEMETHODIMP PutFlags(_In_ DWORD flags);
|
||||
IFACEMETHODIMP PutFileTime(_In_ SYSTEMTIME fileTime);
|
||||
IFACEMETHODIMP ResetFileTime();
|
||||
IFACEMETHODIMP Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result);
|
||||
IFACEMETHODIMP Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex);
|
||||
|
||||
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegEx **renameRegEx);
|
||||
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegEx** renameRegEx);
|
||||
|
||||
protected:
|
||||
CPowerRenameRegEx();
|
||||
@@ -39,6 +38,7 @@ protected:
|
||||
void _OnReplaceTermChanged();
|
||||
void _OnFlagsChanged();
|
||||
void _OnFileTimeChanged();
|
||||
HRESULT _OnEnumerateItemsChanged();
|
||||
|
||||
size_t _Find(std::wstring data, std::wstring toSearch, bool caseInsensitive, size_t pos);
|
||||
|
||||
@@ -46,8 +46,9 @@ protected:
|
||||
DWORD m_flags = DEFAULT_FLAGS;
|
||||
PWSTR m_searchTerm = nullptr;
|
||||
PWSTR m_replaceTerm = nullptr;
|
||||
std::wstring m_RawReplaceTerm;
|
||||
|
||||
SYSTEMTIME m_fileTime = {0};
|
||||
SYSTEMTIME m_fileTime = { 0 };
|
||||
bool m_useFileTime = false;
|
||||
|
||||
CSRWLock m_lock;
|
||||
@@ -55,6 +56,9 @@ protected:
|
||||
|
||||
DWORD m_cookie = 0;
|
||||
|
||||
std::vector<Enumerator> m_enumerators;
|
||||
std::vector<int32_t> m_replaceWithEnumeratorOffsets;
|
||||
|
||||
struct RENAME_REGEX_EVENT
|
||||
{
|
||||
IPowerRenameRegExEvents* pEvents;
|
||||
|
||||
@@ -86,7 +86,7 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
|
||||
|
||||
// Failure here means we didn't match anything or had nothing to match
|
||||
// Call put_newName with null in that case to reset it
|
||||
winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName));
|
||||
winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName, itemEnumIndex));
|
||||
|
||||
if (useFileTime)
|
||||
{
|
||||
@@ -166,17 +166,6 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
|
||||
newNameToUse = nullptr;
|
||||
}
|
||||
|
||||
wchar_t uniqueName[MAX_PATH] = { 0 };
|
||||
if (newNameToUse != nullptr && (flags & EnumerateItems))
|
||||
{
|
||||
unsigned long countUsed = 0;
|
||||
if (GetEnumeratedFileName(uniqueName, ARRAYSIZE(uniqueName), newNameToUse, nullptr, itemEnumIndex, &countUsed))
|
||||
{
|
||||
newNameToUse = uniqueName;
|
||||
}
|
||||
itemEnumIndex++;
|
||||
}
|
||||
|
||||
spItem->PutStatus(PowerRenameItemRenameStatus::ShouldRename);
|
||||
if (newNameToUse != nullptr)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
#include <shlwapi.h>
|
||||
#include <ShlObj_core.h>
|
||||
#include <filesystem>
|
||||
#include <compare>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <charconv>
|
||||
#include <string>
|
||||
|
||||
#include <ProjectTelemetry.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user