mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-08 12:18:50 +02:00
[PowerRename] Using File Attributes Update (#5250)
* Use only fff for milliseconds * Refactor * Handle double $ signs. Move isFileAttributes check to Helpers. Move File Attributes to perform before regex operation * Fix typo * Format date/time test * Disable problematic features. Add comments * Fix month/day names * Add tests * Add line between tests * Add local month/day names support * Make sure month/date names are capitalized * Fix formatting
This commit is contained in:
committed by
GitHub
parent
69cb20e1cd
commit
64106cba82
@@ -169,56 +169,105 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool isFileAttributesUsed(_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++)
|
||||
{
|
||||
if (std::regex_search(source, std::wregex(patterns[i])))
|
||||
{
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME LocalTime)
|
||||
{
|
||||
std::locale::global(std::locale(""));
|
||||
HRESULT hr = (source && wcslen(source) > 0) ? S_OK : E_INVALIDARG;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
std::wregex pattern(L"\\$YYYY");
|
||||
std::wstring res(source);
|
||||
wchar_t replaceTerm[MAX_PATH] = {0};
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%d"),LocalTime.wYear);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
wchar_t replaceTerm[MAX_PATH] = { 0 };
|
||||
wchar_t formattedDate[MAX_PATH] = { 0 };
|
||||
|
||||
pattern = L"\\$SSS";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%03d"), LocalTime.wMilliseconds);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
|
||||
if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
|
||||
{
|
||||
StringCchCopy(localeName, LOCALE_NAME_MAX_LENGTH, L"en_US");
|
||||
}
|
||||
|
||||
pattern = L"\\$MMM";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%03d"), LocalTime.wMilliseconds);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%04d"), L"$01", LocalTime.wYear);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$YYYY"), replaceTerm);
|
||||
|
||||
pattern = L"\\$mmm";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%03d"), LocalTime.wMilliseconds);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", (LocalTime.wYear % 100));
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$YY"), replaceTerm);
|
||||
|
||||
pattern = L"\\$fff";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%03d"), LocalTime.wMilliseconds);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", (LocalTime.wYear % 10));
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$Y"), replaceTerm);
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &LocalTime, 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, &LocalTime, 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", LocalTime.wMonth);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MM"), replaceTerm);
|
||||
|
||||
pattern = L"\\$FFF";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%03d"), LocalTime.wMilliseconds);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", LocalTime.wMonth);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$M"), replaceTerm);
|
||||
|
||||
pattern = L"\\$MM" ;
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%02d"), LocalTime.wMonth);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
GetDateFormatEx(localeName, NULL, &LocalTime, L"dddd", 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"(([^\\$]|^)(\\$\\$)*)\\$DDDD"), replaceTerm);
|
||||
|
||||
GetDateFormatEx(localeName, NULL, &LocalTime, L"ddd", 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"(([^\\$]|^)(\\$\\$)*)\\$DDD"), replaceTerm);
|
||||
|
||||
pattern = L"\\$DD";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%02d"), LocalTime.wDay);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", LocalTime.wDay);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$DD"), replaceTerm);
|
||||
|
||||
pattern = L"\\$hh";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%02d"), LocalTime.wHour);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", LocalTime.wDay);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$D"), replaceTerm);
|
||||
|
||||
pattern = L"\\$mm";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%02d"), LocalTime.wMinute);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", LocalTime.wHour);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$hh"), replaceTerm);
|
||||
|
||||
pattern = L"\\$ss";
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%02d"), LocalTime.wSecond);
|
||||
res = regex_replace(res, pattern, replaceTerm);
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", LocalTime.wHour);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$h"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", LocalTime.wMinute);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$mm"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", LocalTime.wMinute);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$m"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", LocalTime.wSecond);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$ss"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", LocalTime.wSecond);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$s"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%03d"), L"$01", LocalTime.wMilliseconds);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$fff"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", LocalTime.wMilliseconds/10);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$ff"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", LocalTime.wMilliseconds/100);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$f"), replaceTerm);
|
||||
|
||||
hr = StringCchCopy(result, cchMax, res.c_str());
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
HRESULT GetTrimmedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source);
|
||||
HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, DWORD flags);
|
||||
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME LocalTime);
|
||||
bool isFileAttributesUsed(_In_ PCWSTR source);
|
||||
bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource);
|
||||
HRESULT EnumerateDataObject(_In_ IUnknown* pdo, _In_ IPowerRenameManager* psrm);
|
||||
BOOL GetEnumeratedFileName(
|
||||
|
||||
@@ -764,11 +764,28 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
|
||||
StringCchCopy(sourceName, ARRAYSIZE(sourceName), originalName);
|
||||
}
|
||||
|
||||
wchar_t newReplaceTerm[MAX_PATH] = { 0 };
|
||||
PWSTR replaceTerm = nullptr;
|
||||
SYSTEMTIME LocalTime;
|
||||
|
||||
if (SUCCEEDED(spRenameRegEx->get_replaceTerm(&replaceTerm)) && isFileAttributesUsed(replaceTerm))
|
||||
{
|
||||
if (SUCCEEDED(spItem->get_date(&LocalTime)))
|
||||
{
|
||||
if (SUCCEEDED(GetDatedFileName(newReplaceTerm, ARRAYSIZE(newReplaceTerm), replaceTerm, LocalTime)))
|
||||
{
|
||||
spRenameRegEx->put_replaceTerm(newReplaceTerm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PWSTR newName = nullptr;
|
||||
// Failure here means we didn't match anything or had nothing to match
|
||||
// Call put_newName with null in that case to reset it
|
||||
spRenameRegEx->Replace(sourceName, &newName);
|
||||
|
||||
spRenameRegEx->put_replaceTerm(replaceTerm);
|
||||
|
||||
wchar_t resultName[MAX_PATH] = { 0 };
|
||||
|
||||
PWSTR newNameToUse = nullptr;
|
||||
@@ -812,35 +829,6 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
|
||||
{
|
||||
newNameToUse = trimmedName;
|
||||
}
|
||||
|
||||
bool isDateAttributeUsed = false;
|
||||
wchar_t datedName[MAX_PATH] = { 0 };
|
||||
std::wstring patterns[] = { L"$YYYY", L"$SSS", L"$MMM", L"$mmm", L"$FFF", L"$fff",
|
||||
L"$MM", L"$DD", L"$hh", L"$mm", L"$ss" };
|
||||
size_t patternsLength = ARRAYSIZE(patterns);
|
||||
SYSTEMTIME LocalTime;
|
||||
|
||||
if (newNameToUse != nullptr)
|
||||
{
|
||||
for (size_t i = 0; !isDateAttributeUsed && i < patternsLength; i++)
|
||||
{
|
||||
std::wstring source(newNameToUse);
|
||||
if (source.find(patterns[i]) != std::string::npos)
|
||||
{
|
||||
isDateAttributeUsed = true;
|
||||
}
|
||||
}
|
||||
if (isDateAttributeUsed)
|
||||
{
|
||||
if (SUCCEEDED(spItem->get_date(&LocalTime)))
|
||||
{
|
||||
if (SUCCEEDED(GetDatedFileName(datedName, ARRAYSIZE(datedName), newNameToUse, LocalTime)))
|
||||
{
|
||||
newNameToUse = datedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t transformedName[MAX_PATH] = { 0 };
|
||||
if (newNameToUse != nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase))
|
||||
@@ -879,6 +867,7 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
|
||||
}
|
||||
|
||||
CoTaskMemFree(newName);
|
||||
CoTaskMemFree(replaceTerm);
|
||||
CoTaskMemFree(currentNewName);
|
||||
CoTaskMemFree(originalName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user