mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-30 09:14:39 +02:00
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:
parent
be00dd5544
commit
a9d8dca832
@ -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 "Open all files of folder instead of launching Folder as Workspace on folder dropping" in "Default Directory" 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:
|
||||
|
||||
|
@ -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 "Open all files of folder instead of launching Folder as Workspace on folder dropping" in "Default Directory" 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:
|
||||
|
||||
|
@ -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
|
||||
|
320
PowerEditor/src/MISC/Common/SortLocale.cpp
Normal file
320
PowerEditor/src/MISC/Common/SortLocale.cpp
Normal 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;
|
||||
|
||||
}
|
39
PowerEditor/src/MISC/Common/SortLocale.h
Normal file
39
PowerEditor/src/MISC/Common/SortLocale.h
Normal 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;
|
||||
};
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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)
|
||||
|
@ -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" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user