Add Locale-based line sort feature

Fix partially:

Fix #13456, fix #927, fix #8481, fix #11261, fix #16406, fix #16409, close #16490
This commit is contained in:
Randy Fellmy 2025-04-25 09:50:11 -07:00 committed by Don Ho
parent be00dd5544
commit a9d8dca832
10 changed files with 396 additions and 0 deletions

View File

@ -137,6 +137,8 @@ Translation note:
<Item id="42060" name="Sort Lines Lexicographically Descending"/>
<Item id="42080" name="Sort Lines Lex. Ascending Ignoring Case"/>
<Item id="42081" name="Sort Lines Lex. Descending Ignoring Case"/>
<Item id="42100" name="Sort Lines In Locale Order Ascending"/>
<Item id="42101" name="Sort Lines In Locale Order Descending"/>
<Item id="42061" name="Sort Lines As Integers Ascending"/>
<Item id="42062" name="Sort Lines As Integers Descending"/>
<Item id="42063" name="Sort Lines As Decimals (Comma) Ascending"/>
@ -1468,6 +1470,9 @@ Your settings on cloud will be canceled. Please reset a coherent value via Prefe
<DroppingFolderAsProjectModeWarning title="Invalid action" message="You can only drop files or folders but not both, because you're in dropping Folder as Project mode.
You have to enable &quot;Open all files of folder instead of launching Folder as Workspace on folder dropping&quot; in &quot;Default Directory&quot; section of Preferences dialog to make this operation work."/>
<SortingError title="Sorting Error" message="Unable to perform numeric sorting due to line $INT_REPLACE$."/><!-- HowToReproduce: this message prevents from system failure. It's hard to reproduce. -->
<SortLocaleMultiple title="Sort not performed" message="Sorting multiple selections is not supported."/><!-- HowToReproduce: Make a multiple selection and choose Edit | Line Operations | Sort Lines In Locale Order. -->
<SortLocaleUnknown title="Sort Failed" message="The reason the sort failed cannot be determined."/><!-- HowToReproduce: This condition is theoretical; it is unknown what could cause it. -->
<SortLocaleExcept title="Sort Failed" message="$STR_REPLACE$"/><!-- HowToReproduce: Open a large file, e.g. 500MB / 90k lines, in 32-bit Notepad++ and choose Edit | Line Operations | Sort Lines In Locale Order. -->
<ColumnModeTip title="Column Mode Tip" message="
There are 3 ways to switch to column-select mode:

View File

@ -137,6 +137,8 @@ Translation note:
<Item id="42060" name="Sort Lines Lexicographically Descending"/>
<Item id="42080" name="Sort Lines Lex. Ascending Ignoring Case"/>
<Item id="42081" name="Sort Lines Lex. Descending Ignoring Case"/>
<Item id="42100" name="Sort Lines In Locale Order Ascending"/>
<Item id="42101" name="Sort Lines In Locale Order Descending"/>
<Item id="42061" name="Sort Lines As Integers Ascending"/>
<Item id="42062" name="Sort Lines As Integers Descending"/>
<Item id="42063" name="Sort Lines As Decimals (Comma) Ascending"/>
@ -1468,6 +1470,9 @@ Your settings on cloud will be canceled. Please reset a coherent value via Prefe
<DroppingFolderAsProjectModeWarning title="Invalid action" message="You can only drop files or folders but not both, because you're in dropping Folder as Project mode.
You have to enable &quot;Open all files of folder instead of launching Folder as Workspace on folder dropping&quot; in &quot;Default Directory&quot; section of Preferences dialog to make this operation work."/>
<SortingError title="Sorting Error" message="Unable to perform numeric sorting due to line $INT_REPLACE$."/><!-- HowToReproduce: this message prevents from system failure. It's hard to reproduce. -->
<SortLocaleMultiple title="Sort not performed" message="Sorting multiple selections is not supported."/><!-- HowToReproduce: Make a multiple selection and choose Edit | Line Operations | Sort Lines In Locale Order. -->
<SortLocaleUnknown title="Sort Failed" message="The reason the sort failed cannot be determined."/><!-- HowToReproduce: This condition is theoretical; it is unknown what could cause it. -->
<SortLocaleExcept title="Sort Failed" message="$STR_REPLACE$"/><!-- HowToReproduce: Open a large file, e.g. 500MB / 90k lines, in 32-bit Notepad++ and choose Edit | Line Operations | Sort Lines In Locale Order. -->
<ColumnModeTip title="Column Mode Tip" message="
There are 3 ways to switch to column-select mode:

View File

@ -91,6 +91,7 @@ SET(src_files
./ScintillaComponent/columnEditor.cpp
./MISC/Common/Common.cpp
./MISC/Common/FileInterface.cpp
./MISC/Common/SortLocale.cpp
./WinControls/ContextMenu/ContextMenu.cpp
./WinControls/OpenSaveFileDialog/CustomFileDialog.cpp
./WinControls/PluginsAdmin/pluginsAdmin.cpp

View File

@ -0,0 +1,320 @@
// This file is part of Notepad++ project
// Copyright (C)2025 Randall Joseph Fellmy <software@coises.com>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// at your option any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "SortLocale.h"
static const SortLocale::Result sortSuccess { 0, "0", L"0" };
static const SortLocale::Result sortNothing { 0, "SortLocaleNothing", L"Nothing to sort." };
static const SortLocale::Result warnMultiple { MB_ICONWARNING, "SortLocaleMultiple", L"Sorting multiple selections is not supported." };
static const SortLocale::Result errorUnknown { MB_ICONERROR, "SortLocaleUnknown", L"The reason the sort failed cannot be determined." };
// The error for exceptions, { MB_ICONERROR, "SortLocaleExcept", exception-message } is built dynamically;
// translations should use "$STR_REPLACE$" as the message, since the message is also passed as the string replacement.
SortLocale::Result SortLocale::sort(ScintillaEditView* sci, bool descending) const
{
DWORD options = LCMAP_SORTKEY | NORM_LINGUISTIC_CASING;
if (!caseSensitive) options |= LINGUISTIC_IGNORECASE;
if (digitsAsNumbers) options |= SORT_DIGITSASNUMBERS;
if (ignoreDiacritics) options |= LINGUISTIC_IGNOREDIACRITIC;
if (ignoreSymbols) options |= NORM_IGNORESYMBOLS;
LPCWSTR locale = localeName.empty() ? LOCALE_NAME_USER_DEFAULT : localeName.data();
UINT codepage = static_cast<UINT>(sci->execute(SCI_GETCODEPAGE));
intptr_t lines, startPos, topLine, endPos, bottomLine;
bool rectangular = false;
bool noselection = false;
bool forward = true;
bool missingEOL = false;
// Set:
// rectangular = true for rectangular and thin selections; false all other times
// noselection = true if nothing was selected; false all other times
// forward = false if caret is less than anchor; true all other times
// missingEOL = true if selection ends includes last line of document with no terminating line ending; otherwise false
// topLine and bottomLine = line indices to be sorted, bottomLine included
// startPos and endPos = text range of all lines to be sorted, endPos not included
// lines = number of lines to be sorted
//
// Return warnMultiple if there is a multiple stream selection or sortNothing if there is a selection covering fewer than two lines.
switch (sci->execute(SCI_GETSELECTIONMODE))
{
case SC_SEL_THIN :
case SC_SEL_RECTANGLE:
lines = sci->execute(SCI_GETSELECTIONS);
if (lines < 2) return sortNothing;
if (sci->execute(SCI_GETSELECTIONEMPTY)) noselection = true;
rectangular = true;
{
intptr_t rsa = sci->execute(SCI_GETRECTANGULARSELECTIONANCHOR);
intptr_t rsc = sci->execute(SCI_GETRECTANGULARSELECTIONCARET);
forward = rsc > rsa;
topLine = sci->execute(SCI_LINEFROMPOSITION, forward ? rsa : rsc);
bottomLine = sci->execute(SCI_LINEFROMPOSITION, forward ? rsc : rsa);
}
startPos = sci->execute(SCI_POSITIONFROMLINE, topLine);
if (bottomLine == sci->execute(SCI_GETLINECOUNT) - 1) // selection ends on last line of document
{
endPos = sci->execute(SCI_GETLENGTH);
missingEOL = true;
}
else
{
endPos = sci->execute(SCI_POSITIONFROMLINE, bottomLine + 1);
}
break;
default:
if (sci->execute(SCI_GETSELECTIONS) != 1) return warnMultiple;
intptr_t anchor = sci->execute(SCI_GETANCHOR);
intptr_t caret = sci->execute(SCI_GETCURRENTPOS);
if (anchor == caret)
{
noselection = true;
topLine = startPos = 0;
bottomLine = sci->execute(SCI_GETLINECOUNT) - 1;
endPos = sci->execute(SCI_GETLENGTH);
if (sci->execute(SCI_POSITIONFROMLINE, bottomLine) == endPos) // last line is empty; don't sort it
bottomLine--;
else // last line of document is not empty (no line ending)
missingEOL = true;
}
else
{
forward = anchor < caret;
topLine = sci->execute(SCI_LINEFROMPOSITION, forward ? anchor : caret);
startPos = sci->execute(SCI_POSITIONFROMLINE, topLine);
endPos = forward ? caret : anchor;
bottomLine = sci->execute(SCI_LINEFROMPOSITION, endPos);
if (sci->execute(SCI_POSITIONFROMLINE, bottomLine) == endPos) // selection ends at beginning of a line
{
bottomLine--;
}
else if (bottomLine == sci->execute(SCI_GETLINECOUNT) - 1) // selection ends in last line of document, with no line ending
{
missingEOL = true;
endPos = sci->execute(SCI_GETLENGTH);
}
else // move end position to include line ending
{
endPos = sci->execute(SCI_POSITIONFROMLINE, bottomLine + 1);
}
}
lines = bottomLine - topLine + 1;
if (lines < 2) return sortNothing;
}
// Extensive memory allocation which follows is enclosed in a try block, so failures can be intercepted.
// No changes are made to the Scintilla document within the try block; failure when changing the document
// should be caught by the ordinary Notepad++ error capture routines, since the document cannot be recovered.
// First declare some variables which will be required after the try block is finished.
std::string sortedText;
intptr_t cpAnchor = 0;
intptr_t cpCaret = 0;
intptr_t vsAnchor = 0;
intptr_t vsCaret = 0;
intptr_t lnCaret = 0;
try
{
// Build a vector which will contain the sort keys and pointers to the lines to be sorted.
struct SortLine {
std::string key;
std::string_view content;
intptr_t index = 0;
intptr_t lineStart = 0;
intptr_t lineLength = 0;
intptr_t keyStart = 0;
intptr_t keyLength = 0;
bool appendEOL = false;
};
std::vector<SortLine> sortLines(lines);
if (missingEOL) sortLines.back().appendEOL = true;
// Get the information we need from Scintilla.
intptr_t cpNextLine = endPos;
for (intptr_t n = lines - 1; n >= 0; --n)
{
SortLine& sl = sortLines[n];
if (rectangular)
{
sl.index = forward ? n : lines - 1 - n;
sl.lineStart = sci->execute(SCI_POSITIONFROMLINE, topLine + n);
sl.keyStart = sci->execute(SCI_GETSELECTIONNSTART, sl.index);
sl.keyLength =
(noselection ? sci->execute(SCI_GETLINEENDPOSITION, topLine + n) : sci->execute(SCI_GETSELECTIONNEND, sl.index))
- sl.keyStart;
}
else
{
sl.index = n;
sl.lineStart = sl.keyStart = sci->execute(SCI_POSITIONFROMLINE, topLine + n);
sl.keyLength = sci->execute(SCI_GETLINEENDPOSITION, topLine + n) - sl.keyStart;
}
sl.lineLength = cpNextLine - sl.lineStart;
cpNextLine = sl.lineStart;
}
std::string docEOL;
if (missingEOL)
{
auto eolMode = sci->execute(SCI_GETEOLMODE);
docEOL = eolMode == SC_EOL_CR ? "\r" : eolMode == SC_EOL_LF ? "\n" : "\r\n";
}
// Next, get a pointer into Scintilla's buffer for the range encompassing everything to be sorted.
// Note that this pointer becomes invalid as soon as we access Scintilla again.
// Then find the sort keys and content for each line, sort as requested, and build the replacement text.
const char* const textPointer = reinterpret_cast<const char*>(sci->execute(SCI_GETRANGEPOINTER, startPos, endPos - startPos));
for (SortLine& sl : sortLines)
{
sl.content = std::string_view(sl.lineStart - startPos + textPointer, sl.lineLength);
std::string_view keyText(sl.keyStart - startPos + textPointer, sl.keyLength);
if (!keyText.empty())
{
constexpr unsigned int safeSize = std::numeric_limits<int>::max() / 2;
size_t textLength = keyText.length();
int sortableLength = textLength > safeSize ? safeSize : static_cast<int>(textLength);
int wideLength = MultiByteToWideChar(codepage, 0, keyText.data(), sortableLength, 0, 0);
std::wstring wideText(wideLength, 0);
MultiByteToWideChar(codepage, 0, keyText.data(), sortableLength, wideText.data(), wideLength);
int m = LCMapStringEx(locale, options, wideText.data(), wideLength, 0, 0, 0, 0, 0);
sl.key.resize(m, 0);
LCMapStringEx(locale, options, wideText.data(), wideLength, reinterpret_cast<LPWSTR>(sl.key.data()), m, 0, 0, 0);
}
}
if (descending)
std::stable_sort(sortLines.begin(), sortLines.end(), [](const SortLine& a, const SortLine& b) { return a.key > b.key; });
else
std::stable_sort(sortLines.begin(), sortLines.end(), [](const SortLine& a, const SortLine& b) { return a.key < b.key; });
sortedText.reserve(endPos - startPos + docEOL.length());
for (SortLine& sl : sortLines)
{
sortedText.append(sl.content);
if (sl.appendEOL) sortedText.append(docEOL);
}
if (missingEOL) // if we added a line ending, remove line ending from last line of sorted text
{
if (sortedText.back() == '\n') sortedText.pop_back();
if (sortedText.back() == '\r') sortedText.pop_back();
}
// Before updating Scintilla, get information we will need to restore the selection (as best we can)
if (rectangular)
{
intptr_t ixTop = sortLines.front().index;
intptr_t ixBottom = sortLines.back().index;
intptr_t ixAnchor = forward ? ixTop : ixBottom;
intptr_t ixCaret = forward ? ixBottom : ixTop;
cpAnchor = sci->execute(SCI_GETSELECTIONNANCHOR, ixAnchor);
vsAnchor = sci->execute(SCI_GETSELECTIONNANCHORVIRTUALSPACE, ixAnchor);
cpCaret = sci->execute(SCI_GETSELECTIONNCARET, ixCaret);
vsCaret = sci->execute(SCI_GETSELECTIONNCARETVIRTUALSPACE, ixCaret);
cpAnchor -= sci->execute(SCI_POSITIONFROMLINE, sci->execute(SCI_LINEFROMPOSITION, cpAnchor));
cpCaret -= sci->execute(SCI_POSITIONFROMLINE, sci->execute(SCI_LINEFROMPOSITION, cpCaret));
}
else if (noselection)
{
cpCaret = sci->execute(SCI_GETCURRENTPOS);
lnCaret = sci->execute(SCI_LINEFROMPOSITION, cpCaret);
cpCaret -= sci->execute(SCI_POSITIONFROMLINE, lnCaret);
for (intptr_t n = 0; n < lines; ++n) if (sortLines[n].index == lnCaret)
{
lnCaret = n;
break;
}
}
}
catch (const std::exception& e)
{
try
{
int errlen = MultiByteToWideChar(CP_ACP, 0, e.what(), -1, 0, 0);
if (errlen < 2) return errorUnknown;
std::wstring errmsg(errlen - 1, 0);
MultiByteToWideChar(CP_ACP, 0, e.what(), -1, errmsg.data(), errlen);
return { MB_ICONERROR, "SortLocaleExcept", errmsg };
}
catch (...)
{
return errorUnknown;
}
}
catch (...)
{
return errorUnknown;
}
// Update Scintilla and restore position or selection
sci->execute(SCI_SETTARGETRANGE, startPos, endPos);
sci->execute(SCI_SETSTATUS, 0);
sci->execute(SCI_REPLACETARGET, sortedText.length(), reinterpret_cast<LPARAM>(sortedText.data()));
int replaceStatus = static_cast<int>(sci->execute(SCI_GETSTATUS));
sci->execute(SCI_SETSTATUS, 0);
if (replaceStatus != SC_STATUS_OK && replaceStatus < SC_STATUS_WARN_START)
{
struct ScintillaMemory : std::exception
{
const char* what() const noexcept override { return "Scintilla ran out of memory while updating the document."; }
};
struct ScintillaFail : std::exception
{
const char* what() const noexcept override { return "Scintilla was unable to update the document."; }
};
SendMessage(sci->getHSelf(), WM_SETREDRAW, FALSE, 0); // Without this, Scintilla can hang before message is displayed
if (replaceStatus == SC_STATUS_BADALLOC)
throw ScintillaMemory();
else
throw ScintillaFail();
}
if (rectangular)
{
cpAnchor += sci->execute(SCI_POSITIONFROMLINE, forward ? topLine : bottomLine);
cpCaret += sci->execute(SCI_POSITIONFROMLINE, forward ? bottomLine : topLine);
sci->execute(SCI_SETRECTANGULARSELECTIONANCHOR, cpAnchor);
sci->execute(SCI_SETRECTANGULARSELECTIONCARET, cpCaret);
sci->execute(SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE, vsAnchor);
sci->execute(SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE, vsCaret);
}
else if (noselection)
sci->execute(SCI_GOTOPOS, sci->execute(SCI_POSITIONFROMLINE, lnCaret) + cpCaret);
else if (forward)
sci->execute(SCI_SETSEL, sci->execute(SCI_GETTARGETSTART), sci->execute(SCI_GETTARGETEND));
else
sci->execute(SCI_SETSEL, sci->execute(SCI_GETTARGETEND), sci->execute(SCI_GETTARGETSTART));
return sortSuccess;
}

View File

@ -0,0 +1,39 @@
// This file is part of Notepad++ project
// Copyright (C)2025 Randall Joseph Fellmy <software@coises.com>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// at your option any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include <string>
#include <vector>
#include <../ScintillaComponent/ScintillaEditView.h>
class SortLocale
{
public:
struct Result
{
UINT status = 0; // Will be 0 (successful sort), MB_ICONWARNING or MB_ICONERROR
std::string tagName; // The tag name for translation
std::wstring message; // A message describing the status, if it isn't 0
};
std::wstring localeName;
bool caseSensitive = false;
bool digitsAsNumbers = true;
bool ignoreDiacritics = false;
bool ignoreSymbols = false;
Result sort(ScintillaEditView* sci, bool descending) const;
};

View File

@ -541,12 +541,14 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Sort Lines Lexicographically Ascending", IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING
MENUITEM "Sort Lines Lex. Ascending Ignoring Case", IDM_EDIT_SORTLINES_LEXICO_CASE_INSENS_ASCENDING
MENUITEM "Sort Lines In Locale Order Ascending", IDM_EDIT_SORTLINES_LOCALE_ASCENDING
MENUITEM "Sort Lines As Integers Ascending", IDM_EDIT_SORTLINES_INTEGER_ASCENDING
MENUITEM "Sort Lines As Decimals (Comma) Ascending", IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING
MENUITEM "Sort Lines As Decimals (Dot) Ascending", IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING
MENUITEM SEPARATOR
MENUITEM "Sort Lines Lexicographically Descending", IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING
MENUITEM "Sort Lines Lex. Descending Ignoring Case", IDM_EDIT_SORTLINES_LEXICO_CASE_INSENS_DESCENDING
MENUITEM "Sort Lines In Locale Order Descending", IDM_EDIT_SORTLINES_LOCALE_DESCENDING
MENUITEM "Sort Lines As Integers Descending", IDM_EDIT_SORTLINES_INTEGER_DESCENDING
MENUITEM "Sort Lines As Decimals (Comma) Descending", IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING
MENUITEM "Sort Lines As Decimals (Dot) Descending", IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING

View File

@ -35,6 +35,7 @@
#include "sha-256.h"
#include "calc_sha1.h"
#include "sha512.h"
#include "SortLocale.h"
using namespace std;
@ -852,6 +853,21 @@ void Notepad_plus::command(int id)
}
break;
case IDM_EDIT_SORTLINES_LOCALE_ASCENDING:
case IDM_EDIT_SORTLINES_LOCALE_DESCENDING:
{
std::lock_guard<std::mutex> lock(command_mutex);
SortLocale sortLocale;
auto result = sortLocale.sort(_pEditView, id == IDM_EDIT_SORTLINES_LOCALE_DESCENDING);
if (result.status)
_nativeLangSpeaker.messageBox(result.tagName.data(),
_pPublicInterface->getHSelf(),
result.message.data(),
result.status == MB_ICONERROR ? L"Sort Failed" : L"Sort not performed",
result.status | MB_OK | MB_APPLMODAL, 0, result.message.data());
}
break;
case IDM_EDIT_BLANKLINEABOVECURRENT:
{
_pEditView->insertNewLineAboveCurrentLine();
@ -4273,6 +4289,8 @@ void Notepad_plus::command(int id)
case IDM_EDIT_MULTISELECTNEXTMATCHCASEWHOLEWORD:
case IDM_EDIT_MULTISELECTUNDO:
case IDM_EDIT_MULTISELECTSSKIP:
case IDM_EDIT_SORTLINES_LOCALE_ASCENDING:
case IDM_EDIT_SORTLINES_LOCALE_DESCENDING:
_macro.push_back(recordedMacroStep(id));
break;

View File

@ -131,6 +131,8 @@ static const WinMenuKeyDefinition winKeyDefs[] =
{ VK_NULL, IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING, false, false, false, nullptr },
{ VK_NULL, IDM_EDIT_SORTLINES_LEXICO_CASE_INSENS_ASCENDING, false, false, false, nullptr },
{ VK_NULL, IDM_EDIT_SORTLINES_LEXICO_CASE_INSENS_DESCENDING, false, false, false, nullptr },
{ VK_NULL, IDM_EDIT_SORTLINES_LOCALE_ASCENDING, false, false, false, nullptr },
{ VK_NULL, IDM_EDIT_SORTLINES_LOCALE_DESCENDING, false, false, false, nullptr },
{ VK_NULL, IDM_EDIT_SORTLINES_INTEGER_ASCENDING, false, false, false, nullptr },
{ VK_NULL, IDM_EDIT_SORTLINES_INTEGER_DESCENDING, false, false, false, nullptr },
{ VK_NULL, IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING, false, false, false, nullptr },

View File

@ -182,6 +182,8 @@
#define IDM_EDIT_MULTISELECTNEXTMATCHCASEWHOLEWORD (IDM_EDIT + 97)
#define IDM_EDIT_MULTISELECTUNDO (IDM_EDIT + 98)
#define IDM_EDIT_MULTISELECTSSKIP (IDM_EDIT + 99)
#define IDM_EDIT_SORTLINES_LOCALE_ASCENDING (IDM_EDIT + 100)
#define IDM_EDIT_SORTLINES_LOCALE_DESCENDING (IDM_EDIT + 101)
#define IDM_EDIT_AUTOCOMPLETE (50000 + 0)
#define IDM_EDIT_AUTOCOMPLETE_CURRENTFILE (50000 + 1)

View File

@ -106,6 +106,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\src\DarkMode\DarkMode.cpp" />
<ClCompile Include="..\src\MISC\Common\SortLocale.cpp" />
<ClCompile Include="..\src\MISC\Common\verifySignedfile.cpp" />
<ClCompile Include="..\src\MISC\md5\md5Dlgs.cpp" />
<ClCompile Include="..\src\MISC\sha1\calc_sha1.cpp" />
@ -247,6 +248,7 @@
<ClInclude Include="..\src\keys.h" />
<ClInclude Include="..\src\localizationString.h" />
<ClInclude Include="..\src\MISC\Common\Sorters.h" />
<ClInclude Include="..\src\MISC\Common\SortLocale.h" />
<ClInclude Include="..\src\MISC\Common\verifySignedfile.h" />
<ClInclude Include="..\src\MISC\md5\md5.h" />
<ClInclude Include="..\src\MISC\md5\md5Dlgs.h" />