From 4d8e731d3e51df0138eb35c80294954143c6ce74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 17 May 2015 19:09:21 +0200 Subject: [PATCH 01/10] Add const to NativeLangSpeaker::messageBox(). --- PowerEditor/src/localization.cpp | 2 +- PowerEditor/src/localization.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PowerEditor/src/localization.cpp b/PowerEditor/src/localization.cpp index aa95947f0..237a225a0 100644 --- a/PowerEditor/src/localization.cpp +++ b/PowerEditor/src/localization.cpp @@ -1071,7 +1071,7 @@ generic_string NativeLangSpeaker::getAttrNameStr(const TCHAR *defaultStr, const return defaultStr; } -int NativeLangSpeaker::messageBox(const char *msgBoxTagName, HWND hWnd, TCHAR *defaultMessage, TCHAR *defaultTitle, int msgBoxType, int intInfo, TCHAR *strInfo) +int NativeLangSpeaker::messageBox(const char *msgBoxTagName, HWND hWnd, const TCHAR *defaultMessage, const TCHAR *defaultTitle, int msgBoxType, int intInfo, const TCHAR *strInfo) { generic_string msg, title; size_t index; diff --git a/PowerEditor/src/localization.h b/PowerEditor/src/localization.h index 16e24a85c..e436909e9 100644 --- a/PowerEditor/src/localization.h +++ b/PowerEditor/src/localization.h @@ -76,7 +76,7 @@ public: generic_string getProjectPanelLangMenuStr(const char * nodeName, int cmdID, const TCHAR *defaultStr) const; //generic_string getFunctionListPanelLangStr(const char *nodeName, const TCHAR *defaultStr) const; generic_string getAttrNameStr(const TCHAR *defaultStr, const char *nodeL1Name, const char *nodeL2Name = NULL) const; - int messageBox(const char *msgBoxTagName, HWND hWnd, TCHAR *message, TCHAR *title, int msgBoxType, int intInfo = 0, TCHAR *strInfo = NULL); + int messageBox(const char *msgBoxTagName, HWND hWnd, const TCHAR *message, const TCHAR *title, int msgBoxType, int intInfo = 0, const TCHAR *strInfo = NULL); private: TiXmlNodeA *_nativeLangA; int _nativeLangEncoding; From d0bafb7fba9c3929e7ef23b187ee6da037da102e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 17 May 2015 19:18:43 +0200 Subject: [PATCH 02/10] Add more options for sorting. User can now choose between lexicographic, integer and decimal sorting. For decimal sorting there are two further options: decimal point ('.') or decimal comma (','). When doing integer/decimal sort, the parsing is not as strict as before. E.g during integer sorting the program will interpret "123abc" as 123. Performance of integer sorting has been improved by 30%. The implementation of sorting is delegated to classes which implement the new "ISorter" interface. Unfortunately due to template issues most of the code had to go in the header file. --- PowerEditor/src/MISC/Common/Common.cpp | 127 +---------- PowerEditor/src/MISC/Common/Common.h | 7 +- PowerEditor/src/MISC/Common/Sorters.h | 210 ++++++++++++++++++ PowerEditor/src/Notepad_plus.rc | 25 ++- PowerEditor/src/NppCommands.cpp | 59 ++++- PowerEditor/src/Parameters.cpp | 10 +- .../ScitillaComponent/ScintillaEditView.cpp | 16 +- .../src/ScitillaComponent/ScintillaEditView.h | 4 +- PowerEditor/src/menuCmdID.h | 10 +- 9 files changed, 318 insertions(+), 150 deletions(-) create mode 100644 PowerEditor/src/MISC/Common/Sorters.h diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index ec16d2cbe..37a825c13 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -749,131 +749,16 @@ generic_string stringJoin(const std::vector& strings, const gene return joined; } -long long stollStrict(const generic_string& input) +generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable) { - if (input.empty()) + // Find first non-admissable character in "input", and remove everything after it. + size_t idx = input.find_first_not_of(admissable); + if (idx == std::string::npos) { - throw std::invalid_argument("Empty input."); + return input; } else { - // Check minus characters. - const int minuses = std::count(input.begin(), input.end(), TEXT('-')); - if (minuses > 1) - { - throw std::invalid_argument("More than one minus sign."); - } - else if (minuses == 1 && input[0] != TEXT('-')) - { - throw std::invalid_argument("Minus sign must be first."); - } - - // Check for other characters which are not allowed. - if (input.find_first_not_of(TEXT("-0123456789")) != std::string::npos) - { - throw std::invalid_argument("Invalid character found."); - } - - return std::stoll(input); + return input.substr(0, idx); } -} - -bool allLinesAreNumericOrEmpty(const std::vector& lines) -{ - for (const generic_string& line : lines) - { - try - { - if (!line.empty()) - { - stollStrict(line); - } - } - catch (std::invalid_argument&) - { - return false; - } - catch (std::out_of_range&) - { - return false; - } - } - return true; -} - -std::vector repeatString(const generic_string& text, const size_t count) -{ - std::vector output; - output.reserve(count); - for (size_t i = 0; i < count; ++i) - { - output.push_back(text); - } - assert(output.size() == count); - return output; -} - -std::vector lexicographicSort(std::vector input, bool isDescending) -{ - std::sort(input.begin(), input.end(), [isDescending](generic_string a, generic_string b) - { - if (isDescending) - { - return a.compare(b) > 0; - } - else - { - return a.compare(b) < 0; - } - }); - return input; -} - -std::vector numericSort(std::vector input, bool isDescending) -{ - // Pre-condition: all strings in "input" are either empty or convertible to int with stoiStrict. - // Note that empty lines are filtered out and added back manually to the output at the end. - std::vector nonEmptyInputAsNumbers; - size_t nofEmptyLines = 0; - nonEmptyInputAsNumbers.reserve(input.size()); - for (const generic_string& line : input) - { - if (line.empty()) - { - ++nofEmptyLines; - } - else - { - nonEmptyInputAsNumbers.push_back(stollStrict(line)); - } - } - assert(nonEmptyInputAsNumbers.size() + nofEmptyLines == input.size()); - std::sort(nonEmptyInputAsNumbers.begin(), nonEmptyInputAsNumbers.end(), [isDescending](long long a, long long b) - { - if (isDescending) - { - return a > b; - } - else - { - return a < b; - } - }); - std::vector output; - output.reserve(input.size()); - const std::vector empties = repeatString(TEXT(""), nofEmptyLines); - if (!isDescending) - { - output.insert(output.end(), empties.begin(), empties.end()); - } - for (const long long& sortedNumber : nonEmptyInputAsNumbers) - { - output.push_back(std::to_wstring(sortedNumber)); - } - if (isDescending) - { - output.insert(output.end(), empties.begin(), empties.end()); - } - assert(output.size() == input.size()); - return output; } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 2e90fea69..78180d050 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -190,11 +190,6 @@ generic_string stringToUpper(generic_string strToConvert); generic_string stringReplace(generic_string subject, const generic_string& search, const generic_string& replace); std::vector stringSplit(const generic_string& input, const generic_string& delimiter); generic_string stringJoin(const std::vector& strings, const generic_string& separator); -long long stollStrict(const generic_string& input); -bool allLinesAreNumericOrEmpty(const std::vector& lines); -std::vector repeatString(const generic_string& text, const size_t count); - -std::vector numericSort(std::vector input, bool isDescending); -std::vector lexicographicSort(std::vector input, bool isDescending); +generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable); #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h new file mode 100644 index 000000000..5ab4cad27 --- /dev/null +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -0,0 +1,210 @@ +// This file is part of Notepad++ project +// Copyright (C)2003 Don HO +// +// 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 2 of the License, or (at your option) any later version. +// +// Note that the GPL places important restrictions on "derived works", yet +// it does not provide a detailed definition of that term. To avoid +// misunderstandings, we consider an application to constitute a +// "derivative work" for the purpose of this license if it does any of the +// following: +// 1. Integrates source code from Notepad++. +// 2. Integrates/includes/aggregates Notepad++ into a proprietary executable +// installer, such as those produced by InstallShield. +// 3. Links to a library or executes a program that does any of the above. +// +// 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +#ifndef M30_IDE_SORTERS_H +#define M30_IDE_SORTERS_H + +// Base interface for line sorting. +class ISorter +{ +private: + bool _isDescending; + +protected: + bool isDescending() const + { + return _isDescending; + } + +public: + ISorter(bool isDescending) + { + _isDescending = isDescending; + }; + virtual ~ISorter() { }; + virtual std::vector sort(std::vector lines) = 0; +}; + +// Implementation of lexicographic sorting of lines. +class LexicographicSorter : public ISorter +{ +public: + LexicographicSorter(bool isDescending) : ISorter(isDescending) { }; + + std::vector sort(std::vector lines) override + { + const bool descending = isDescending(); + std::sort(lines.begin(), lines.end(), [descending](generic_string a, generic_string b) + { + if (descending) + { + return a.compare(b) > 0; + } + else + { + return a.compare(b) < 0; + } + }); + return lines; + } +}; + +// Convert each line to a number (somehow - see stringToNumber) and then sort. +template +class NumericSorter : public ISorter +{ +public: + NumericSorter(bool isDescending) : ISorter(isDescending) { }; + + std::vector sort(std::vector lines) override + { + // Note that empty lines are filtered out and added back manually to the output at the end. + std::vector> nonEmptyInputAsNumbers; + std::vector empties; + nonEmptyInputAsNumbers.reserve(lines.size()); + for (size_t lineIndex = 0; lineIndex < lines.size(); ++lineIndex) + { + generic_string line = prepareStringForConversion(lines[lineIndex]); + if (considerStringEmpty(line)) + { + empties.push_back(line); + } + else + { + try + { + nonEmptyInputAsNumbers.push_back(make_pair(lineIndex, convertStringToNumber(line))); + } + catch (...) + { + throw lineIndex; + } + } + } + assert(nonEmptyInputAsNumbers.size() + empties.size() == lines.size()); + const bool descending = isDescending(); + std::sort(nonEmptyInputAsNumbers.begin(), nonEmptyInputAsNumbers.end(), [descending](std::pair a, std::pair b) + { + if (descending) + { + return a.second > b.second; + } + else + { + return a.second < b.second; + } + }); + std::vector output; + output.reserve(lines.size()); + if (!isDescending()) + { + output.insert(output.end(), empties.begin(), empties.end()); + } + for (const std::pair& sortedNumber : nonEmptyInputAsNumbers) + { + output.push_back(lines[sortedNumber.first]); + } + if (isDescending()) + { + output.insert(output.end(), empties.begin(), empties.end()); + } + assert(output.size() == lines.size()); + return output; + } + +protected: + bool considerStringEmpty(const generic_string& input) + { + // String has something else than just whitespace. + return input.find_first_not_of(TEXT(" \t\r\n")) == std::string::npos; + } + + // Prepare the string for conversion to number. + virtual generic_string prepareStringForConversion(const generic_string& input) = 0; + + // Should convert the input string to a number of the correct type. + // If unable to convert, throw either std::invalid_argument or std::out_of_range. + virtual T_Num convertStringToNumber(const generic_string& input) = 0; +}; + +// Converts lines to long long before sorting. +class IntegerSorter : public NumericSorter +{ +public: + IntegerSorter(bool isDescending) : NumericSorter(isDescending) { }; + +protected: + virtual generic_string prepareStringForConversion(const generic_string& input) + { + return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789")); + } + + long long convertStringToNumber(const generic_string& input) override + { + return std::stoll(input); + } +}; + +// Converts lines to double before sorting (assumes decimal comma). +class DecimalCommaSorter : public NumericSorter +{ +public: + DecimalCommaSorter(bool isDescending) : NumericSorter(isDescending) { }; + +protected: + generic_string prepareStringForConversion(const generic_string& input) override + { + generic_string admissablePart = stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789,")); + return stringReplace(admissablePart, TEXT(","), TEXT(".")); + } + + double convertStringToNumber(const generic_string& input) override + { + return std::stod(input); + } +}; + +// Converts lines to double before sorting (assumes decimal dot). +class DecimalDotSorter : public NumericSorter +{ +public: + DecimalDotSorter(bool isDescending) : NumericSorter(isDescending) { }; + +protected: + generic_string prepareStringForConversion(const generic_string& input) override + { + return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789.")); + } + + double convertStringToNumber(const generic_string& input) override + { + return std::stod(input); + } +}; + +#endif //M30_IDE_SORTERS_H diff --git a/PowerEditor/src/Notepad_plus.rc b/PowerEditor/src/Notepad_plus.rc index 292bf99d7..66b1b5b07 100644 --- a/PowerEditor/src/Notepad_plus.rc +++ b/PowerEditor/src/Notepad_plus.rc @@ -274,8 +274,29 @@ BEGIN MENUITEM "Duplicate Current Line", IDM_EDIT_DUP_LINE MENUITEM "Split Lines", IDM_EDIT_SPLIT_LINES MENUITEM "Join Lines", IDM_EDIT_JOIN_LINES - MENUITEM "Sort Lines in Ascending Order", IDM_EDIT_SORTLINES_ASCENDING - MENUITEM "Sort Lines in Descending Order", IDM_EDIT_SORTLINES_DESCENDING + POPUP "Sort Lines" + BEGIN + POPUP "Lexicographic" + BEGIN + MENUITEM "Ascending", IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING + MENUITEM "Descending", IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING + END + POPUP "Integer" + BEGIN + MENUITEM "Ascending", IDM_EDIT_SORTLINES_INTEGER_ASCENDING + MENUITEM "Descending", IDM_EDIT_SORTLINES_INTEGER_DESCENDING + END + POPUP "Decimal (comma)" + BEGIN + MENUITEM "Ascending", IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING + MENUITEM "Descending", IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING + END + POPUP "Decimal (dot)" + BEGIN + MENUITEM "Ascending", IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING + MENUITEM "Descending", IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING + END + END MENUITEM "Move Up Current Line", IDM_EDIT_LINE_UP MENUITEM "Move Down Current Line", IDM_EDIT_LINE_DOWN MENUITEM "Remove Empty Lines", IDM_EDIT_REMOVEEMPTYLINES diff --git a/PowerEditor/src/NppCommands.cpp b/PowerEditor/src/NppCommands.cpp index 0dbd252c1..dde770068 100644 --- a/PowerEditor/src/NppCommands.cpp +++ b/PowerEditor/src/NppCommands.cpp @@ -35,6 +35,7 @@ #include "VerticalFileSwitcher.h" #include "documentMap.h" #include "functionListPanel.h" +#include "Sorters.h" void Notepad_plus::macroPlayback(Macro macro) @@ -344,8 +345,14 @@ void Notepad_plus::command(int id) } break; - case IDM_EDIT_SORTLINES_ASCENDING: - case IDM_EDIT_SORTLINES_DESCENDING: + case IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING: + case IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING: + case IDM_EDIT_SORTLINES_INTEGER_ASCENDING: + case IDM_EDIT_SORTLINES_INTEGER_DESCENDING: + case IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING: + case IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING: + case IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING: + case IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING: { // default: no selection size_t fromLine = 0; @@ -374,8 +381,44 @@ void Notepad_plus::command(int id) toLine = lineRange.second; } + bool isDescending = id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING || + id == IDM_EDIT_SORTLINES_INTEGER_DESCENDING || + id == IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING || + id == IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING; + _pEditView->execute(SCI_BEGINUNDOACTION); - _pEditView->sortLines(fromLine, toLine, id == IDM_EDIT_SORTLINES_DESCENDING); + std::unique_ptr pSorter; + if (id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING || id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING) + { + pSorter = std::unique_ptr(new LexicographicSorter(isDescending)); + } + else if (id == IDM_EDIT_SORTLINES_INTEGER_DESCENDING || id == IDM_EDIT_SORTLINES_INTEGER_ASCENDING) + { + pSorter = std::unique_ptr(new IntegerSorter(isDescending)); + } + else if (id == IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING || id == IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING) + { + pSorter = std::unique_ptr(new DecimalCommaSorter(isDescending)); + } + else + { + pSorter = std::unique_ptr(new DecimalDotSorter(isDescending)); + } + try + { + _pEditView->sortLines(fromLine, toLine, pSorter.get()); + } + catch (size_t& failedLineIndex) + { + generic_string lineNo = std::to_wstring(1 + fromLine + failedLineIndex); + _nativeLangSpeaker.messageBox("SortingError", + _pPublicInterface->getHSelf(), + TEXT("Unable to perform numeric sort due to line $STR_REPLACE$."), + TEXT("Sorting Error"), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, + 0, + lineNo.c_str()); // We don't use intInfo since it would require casting size_t -> int. + } _pEditView->execute(SCI_ENDUNDOACTION); if (hasSelection) // there was 1 selection, so we restore it @@ -2598,8 +2641,14 @@ void Notepad_plus::command(int id) case IDM_EDIT_RTL : case IDM_EDIT_LTR : case IDM_EDIT_BEGINENDSELECT: - case IDM_EDIT_SORTLINES_ASCENDING: - case IDM_EDIT_SORTLINES_DESCENDING: + case IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING: + case IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING: + case IDM_EDIT_SORTLINES_INTEGER_ASCENDING: + case IDM_EDIT_SORTLINES_INTEGER_DESCENDING: + case IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING: + case IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING: + case IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING: + case IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING: case IDM_EDIT_BLANKLINEABOVECURRENT: case IDM_EDIT_BLANKLINEBELOWCURRENT: case IDM_VIEW_FULLSCREENTOGGLE : diff --git a/PowerEditor/src/Parameters.cpp b/PowerEditor/src/Parameters.cpp index 23a07ebc1..dc5435507 100644 --- a/PowerEditor/src/Parameters.cpp +++ b/PowerEditor/src/Parameters.cpp @@ -127,8 +127,14 @@ WinMenuKeyDefinition winKeyDefs[] = { {VK_SPACE, IDM_EDIT_FUNCCALLTIP, true, false, true, NULL}, {VK_R, IDM_EDIT_RTL, true, true, false, NULL}, {VK_L, IDM_EDIT_LTR, true, true, false, NULL}, - {VK_NULL, IDM_EDIT_SORTLINES_ASCENDING, false, false, false, NULL}, - {VK_NULL, IDM_EDIT_SORTLINES_DESCENDING, false, false, false, NULL}, + {VK_NULL, IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING, false, false, false, NULL }, + {VK_NULL, IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING, false, false, false, NULL }, + {VK_NULL, IDM_EDIT_SORTLINES_INTEGER_ASCENDING, false, false, false, NULL }, + {VK_NULL, IDM_EDIT_SORTLINES_INTEGER_DESCENDING, false, false, false, NULL }, + {VK_NULL, IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING, false, false, false, NULL }, + {VK_NULL, IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING, false, false, false, NULL }, + {VK_NULL, IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING, false, false, false, NULL }, + {VK_NULL, IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING, false, false, false, NULL }, {VK_RETURN, IDM_EDIT_BLANKLINEABOVECURRENT, true, true, false, NULL}, {VK_RETURN, IDM_EDIT_BLANKLINEBELOWCURRENT, true, true, true, NULL}, {VK_F, IDM_SEARCH_FIND, true, false, false, NULL}, diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 91cad99a3..95defe0c9 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -29,6 +29,7 @@ #include "precompiledHeaders.h" #include "ScintillaEditView.h" #include "Parameters.h" +#include "Sorters.h" #include "TCHAR.h" @@ -2947,7 +2948,7 @@ void ScintillaEditView::insertNewLineBelowCurrentLine() execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line + 1)); } -void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescending) +void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, ISorter *pSort) { if (fromLine >= toLine) { @@ -2968,23 +2969,16 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend } } assert(toLine - fromLine + 1 == splitText.size()); - const bool isNumericSort = allLinesAreNumericOrEmpty(splitText); - std::vector sortedText; - if (isNumericSort) - { - sortedText = numericSort(splitText, isDescending); - } - else - { - sortedText = lexicographicSort(splitText, isDescending); - } + const std::vector sortedText = pSort->sort(splitText); const generic_string joined = stringJoin(sortedText, getEOLString()); if (sortEntireDocument) { + assert(joined.length() == text.length()); replaceTarget(joined.c_str(), startPos, endPos); } else { + assert(joined.length() + getEOLString().length() == text.length()); replaceTarget((joined + getEOLString()).c_str(), startPos, endPos); } } diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index 0dcf90aeb..ec42f52f8 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -197,6 +197,8 @@ struct LanguageName { int lexerID; }; +class ISorter; + class ScintillaEditView : public Window { friend class Finder; @@ -636,7 +638,7 @@ public: }; void scrollPosToCenter(int pos); generic_string getEOLString(); - void sortLines(size_t fromLine, size_t toLine, bool isDescending); + void sortLines(size_t fromLine, size_t toLine, ISorter *pSort); void changeTextDirection(bool isRTL); bool isTextDirectionRTL() const; diff --git a/PowerEditor/src/menuCmdID.h b/PowerEditor/src/menuCmdID.h index 7ca353762..125fcb7bf 100644 --- a/PowerEditor/src/menuCmdID.h +++ b/PowerEditor/src/menuCmdID.h @@ -112,8 +112,14 @@ #define IDM_EDIT_REMOVEEMPTYLINESWITHBLANK (IDM_EDIT + 56) #define IDM_EDIT_BLANKLINEABOVECURRENT (IDM_EDIT + 57) #define IDM_EDIT_BLANKLINEBELOWCURRENT (IDM_EDIT + 58) - #define IDM_EDIT_SORTLINES_ASCENDING (IDM_EDIT + 59) - #define IDM_EDIT_SORTLINES_DESCENDING (IDM_EDIT + 60) + #define IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING (IDM_EDIT + 59) + #define IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING (IDM_EDIT + 60) + #define IDM_EDIT_SORTLINES_INTEGER_ASCENDING (IDM_EDIT + 61) + #define IDM_EDIT_SORTLINES_INTEGER_DESCENDING (IDM_EDIT + 62) + #define IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING (IDM_EDIT + 63) + #define IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING (IDM_EDIT + 64) + #define IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING (IDM_EDIT + 65) + #define IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING (IDM_EDIT + 66) // Menu macro #define IDM_MACRO_STARTRECORDINGMACRO (IDM_EDIT + 18) From ad2cc85c0e9b70417a09ef725fd8e369942a074c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 17 May 2015 19:29:43 +0200 Subject: [PATCH 03/10] Simplify NativeLangSpeaker::messageBox. --- PowerEditor/src/localization.cpp | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/PowerEditor/src/localization.cpp b/PowerEditor/src/localization.cpp index 237a225a0..77b8a0f44 100644 --- a/PowerEditor/src/localization.cpp +++ b/PowerEditor/src/localization.cpp @@ -1074,38 +1074,17 @@ generic_string NativeLangSpeaker::getAttrNameStr(const TCHAR *defaultStr, const int NativeLangSpeaker::messageBox(const char *msgBoxTagName, HWND hWnd, const TCHAR *defaultMessage, const TCHAR *defaultTitle, int msgBoxType, int intInfo, const TCHAR *strInfo) { generic_string msg, title; - size_t index; - TCHAR int2Write[256]; - TCHAR intPlaceHolderSymbol[] = TEXT("$INT_REPLACE$"); - TCHAR strPlaceHolderSymbol[] = TEXT("$STR_REPLACE$"); - - size_t intPlaceHolderLen = lstrlen(intPlaceHolderSymbol); - size_t strPlaceHolderLen = lstrlen(strPlaceHolderSymbol); - - generic_sprintf(int2Write, TEXT("%d"), intInfo); - if (!getMsgBoxLang(msgBoxTagName, title, msg)) { title = defaultTitle; msg = defaultMessage; } - index = title.find(intPlaceHolderSymbol); - if (index != string::npos) - title.replace(index, intPlaceHolderLen, int2Write); - - index = msg.find(intPlaceHolderSymbol); - if (index != string::npos) - msg.replace(index, intPlaceHolderLen, int2Write); - + title = stringReplace(title, TEXT("$INT_REPLACE$"), std::to_wstring(intInfo)); + msg = stringReplace(msg, TEXT("$INT_REPLACE$"), std::to_wstring(intInfo)); if (strInfo) { - index = title.find(strPlaceHolderSymbol); - if (index != string::npos) - title.replace(index, strPlaceHolderLen, strInfo); - - index = msg.find(strPlaceHolderSymbol); - if (index != string::npos) - msg.replace(index, strPlaceHolderLen, strInfo); + title = stringReplace(title, TEXT("$STR_REPLACE$"), strInfo); + msg = stringReplace(msg, TEXT("$STR_REPLACE$"), strInfo); } return ::MessageBox(hWnd, msg.c_str(), title.c_str(), msgBoxType); } \ No newline at end of file From 0e42d3348aa8dc48e4fba4dbe4a4b7a390dd4498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 17 May 2015 20:05:25 +0200 Subject: [PATCH 04/10] Fix handling of negative numbers + empty lines. --- PowerEditor/src/MISC/Common/Sorters.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h index 5ab4cad27..a2d136a8b 100644 --- a/PowerEditor/src/MISC/Common/Sorters.h +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -89,16 +89,17 @@ public: nonEmptyInputAsNumbers.reserve(lines.size()); for (size_t lineIndex = 0; lineIndex < lines.size(); ++lineIndex) { - generic_string line = prepareStringForConversion(lines[lineIndex]); - if (considerStringEmpty(line)) + const generic_string originalLine = lines[lineIndex]; + const generic_string preparedLine = prepareStringForConversion(originalLine); + if (considerStringEmpty(preparedLine)) { - empties.push_back(line); + empties.push_back(originalLine); } else { try { - nonEmptyInputAsNumbers.push_back(make_pair(lineIndex, convertStringToNumber(line))); + nonEmptyInputAsNumbers.push_back(make_pair(lineIndex, convertStringToNumber(preparedLine))); } catch (...) { @@ -161,7 +162,7 @@ public: protected: virtual generic_string prepareStringForConversion(const generic_string& input) { - return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789")); + return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789-")); } long long convertStringToNumber(const generic_string& input) override @@ -179,7 +180,7 @@ public: protected: generic_string prepareStringForConversion(const generic_string& input) override { - generic_string admissablePart = stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789,")); + generic_string admissablePart = stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789,-")); return stringReplace(admissablePart, TEXT(","), TEXT(".")); } @@ -198,7 +199,7 @@ public: protected: generic_string prepareStringForConversion(const generic_string& input) override { - return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789.")); + return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789.-")); } double convertStringToNumber(const generic_string& input) override From be230c1a29fd87e6759bdca439598f117aef3c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 17 May 2015 21:23:08 +0200 Subject: [PATCH 05/10] Add a version of std::stod which takes locale. We need a string-to-double conversion function which acts the same on all computers, irrespective of which locale is running. We need to guarantee that the function expects '.' as the decimal point, and not ','. The choice of en-US is more or less arbitrary. --- PowerEditor/src/MISC/Common/Common.cpp | 16 ++++++++++++++++ PowerEditor/src/MISC/Common/Common.h | 1 + PowerEditor/src/MISC/Common/Sorters.h | 18 +++++++++++++++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 37a825c13..e52364751 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -761,4 +761,20 @@ generic_string stringTakeWhileAdmissable(const generic_string& input, const gene { return input.substr(0, idx); } +} + +double stodLocale(const generic_string& str, _locale_t loc, size_t* idx) +{ + // Copied from the std::stod implementation but uses _wcstod_l instead of wcstod. + const wchar_t* ptr = str.c_str(); + errno = 0; + wchar_t* eptr; + double ans = ::_wcstod_l(ptr, &eptr, loc); + if (ptr == eptr) + throw new std::invalid_argument("invalid stod argument"); + if (errno == ERANGE) + throw new std::out_of_range("stod argument out of range"); + if (idx != NULL) + *idx = (size_t)(eptr - ptr); + return ans; } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 78180d050..44b1c1ce1 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -191,5 +191,6 @@ generic_string stringReplace(generic_string subject, const generic_string& searc std::vector stringSplit(const generic_string& input, const generic_string& delimiter); generic_string stringJoin(const std::vector& strings, const generic_string& separator); generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable); +double stodLocale(const generic_string& str, _locale_t loc, size_t* idx = NULL); #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h index a2d136a8b..2e758772a 100644 --- a/PowerEditor/src/MISC/Common/Sorters.h +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -79,7 +79,15 @@ template class NumericSorter : public ISorter { public: - NumericSorter(bool isDescending) : ISorter(isDescending) { }; + NumericSorter(bool isDescending) : ISorter(isDescending) + { + _usLocale = ::_wcreate_locale(LC_NUMERIC, TEXT("en-US")); + }; + + ~NumericSorter() + { + ::_free_locale(_usLocale); + } std::vector sort(std::vector lines) override { @@ -151,6 +159,10 @@ protected: // Should convert the input string to a number of the correct type. // If unable to convert, throw either std::invalid_argument or std::out_of_range. virtual T_Num convertStringToNumber(const generic_string& input) = 0; + + // We need a fixed locale so we get the same string-to-double behavior across all computers. + // This is the "enUS" locale. + _locale_t _usLocale; }; // Converts lines to long long before sorting. @@ -186,7 +198,7 @@ protected: double convertStringToNumber(const generic_string& input) override { - return std::stod(input); + return stodLocale(input, _usLocale); } }; @@ -204,7 +216,7 @@ protected: double convertStringToNumber(const generic_string& input) override { - return std::stod(input); + return stodLocale(input, _usLocale); } }; From 91da641adc1323d4647526a095c25b2d92ddee88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 17 May 2015 21:50:06 +0200 Subject: [PATCH 06/10] Use initializer list in ISorter. --- PowerEditor/src/MISC/Common/Sorters.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h index 2e758772a..b6a1c29bc 100644 --- a/PowerEditor/src/MISC/Common/Sorters.h +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -42,10 +42,7 @@ protected: } public: - ISorter(bool isDescending) - { - _isDescending = isDescending; - }; + ISorter(bool isDescending) : _isDescending(isDescending) { }; virtual ~ISorter() { }; virtual std::vector sort(std::vector lines) = 0; }; From 7b9c342bdac7349396fad73cd676d5ad5751978e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 18 May 2015 09:32:24 +0200 Subject: [PATCH 07/10] Fix outdated comment. --- PowerEditor/src/MISC/Common/Sorters.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h index b6a1c29bc..4873f8386 100644 --- a/PowerEditor/src/MISC/Common/Sorters.h +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -71,7 +71,8 @@ public: } }; -// Convert each line to a number (somehow - see stringToNumber) and then sort. +// Convert each line to a number and then sort. +// The conversion must be implemented in classes which inherit from this, see prepareStringForConversion and convertStringToNumber. template class NumericSorter : public ISorter { From 626dc02c4cb5f18bfb31f315faff5d95ae19dfb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Wed, 20 May 2015 08:25:14 +0200 Subject: [PATCH 08/10] Use old-style loop to be compatible with VS2010. --- PowerEditor/src/MISC/Common/Sorters.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h index 4873f8386..68e0393ff 100644 --- a/PowerEditor/src/MISC/Common/Sorters.h +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -132,9 +132,9 @@ public: { output.insert(output.end(), empties.begin(), empties.end()); } - for (const std::pair& sortedNumber : nonEmptyInputAsNumbers) + for (auto it = nonEmptyInputAsNumbers.begin(); it != nonEmptyInputAsNumbers.end(); ++it) { - output.push_back(lines[sortedNumber.first]); + output.push_back(lines[it->first]); } if (isDescending()) { From 7c3376ae6bbdd2ab7b2079a8ab61072a777ef219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Thu, 21 May 2015 15:53:48 +0200 Subject: [PATCH 09/10] Use a rectangular selection as sort key. --- PowerEditor/src/MISC/Common/Sorters.h | 77 +++++++++++++++++++------- PowerEditor/src/NppCommands.cpp | 78 +++++++++++++++++---------- 2 files changed, 108 insertions(+), 47 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h index 68e0393ff..822904385 100644 --- a/PowerEditor/src/MISC/Common/Sorters.h +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -34,6 +34,7 @@ class ISorter { private: bool _isDescending; + size_t _fromColumn, _toColumn; protected: bool isDescending() const @@ -41,8 +42,28 @@ protected: return _isDescending; } + generic_string getSortKey(const generic_string& input) + { + if (isSortingSpecificColumns()) + { + return input.substr(_fromColumn, 1 + _toColumn - _fromColumn); + } + else + { + return input; + } + } + + bool isSortingSpecificColumns() + { + return _fromColumn != 0 && _toColumn != 0; + } + public: - ISorter(bool isDescending) : _isDescending(isDescending) { }; + ISorter(bool isDescending, size_t fromColumn, size_t toColumn) : _isDescending(isDescending), _fromColumn(fromColumn), _toColumn(toColumn) + { + assert(_fromColumn <= _toColumn); + }; virtual ~ISorter() { }; virtual std::vector sort(std::vector lines) = 0; }; @@ -51,22 +72,42 @@ public: class LexicographicSorter : public ISorter { public: - LexicographicSorter(bool isDescending) : ISorter(isDescending) { }; + LexicographicSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { }; std::vector sort(std::vector lines) override { - const bool descending = isDescending(); - std::sort(lines.begin(), lines.end(), [descending](generic_string a, generic_string b) + // Note that both branches here are equivalent in the sense that they give always give the same answer. + // However, if we are *not* sorting specific columns, then we get a 40% speed improvement by not calling + // getSortKey() so many times. + if (isSortingSpecificColumns()) { - if (descending) + std::sort(lines.begin(), lines.end(), [this](generic_string a, generic_string b) { - return a.compare(b) > 0; - } - else + if (isDescending()) + { + return getSortKey(a).compare(getSortKey(b)) > 0; + + } + else + { + return getSortKey(a).compare(getSortKey(b)) < 0; + } + }); + } + else + { + std::sort(lines.begin(), lines.end(), [this](generic_string a, generic_string b) { - return a.compare(b) < 0; - } - }); + if (isDescending()) + { + return a.compare(b) > 0; + } + else + { + return a.compare(b) < 0; + } + }); + } return lines; } }; @@ -77,7 +118,7 @@ template class NumericSorter : public ISorter { public: - NumericSorter(bool isDescending) : ISorter(isDescending) + NumericSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { _usLocale = ::_wcreate_locale(LC_NUMERIC, TEXT("en-US")); }; @@ -167,12 +208,12 @@ protected: class IntegerSorter : public NumericSorter { public: - IntegerSorter(bool isDescending) : NumericSorter(isDescending) { }; + IntegerSorter(bool isDescending, size_t fromColumn, size_t toColumn) : NumericSorter(isDescending, fromColumn, toColumn) { }; protected: virtual generic_string prepareStringForConversion(const generic_string& input) { - return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789-")); + return stringTakeWhileAdmissable(getSortKey(input), TEXT(" \t\r\n0123456789-")); } long long convertStringToNumber(const generic_string& input) override @@ -185,12 +226,12 @@ protected: class DecimalCommaSorter : public NumericSorter { public: - DecimalCommaSorter(bool isDescending) : NumericSorter(isDescending) { }; + DecimalCommaSorter(bool isDescending, size_t fromColumn, size_t toColumn) : NumericSorter(isDescending, fromColumn, toColumn) { }; protected: generic_string prepareStringForConversion(const generic_string& input) override { - generic_string admissablePart = stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789,-")); + generic_string admissablePart = stringTakeWhileAdmissable(getSortKey(input), TEXT(" \t\r\n0123456789,-")); return stringReplace(admissablePart, TEXT(","), TEXT(".")); } @@ -204,12 +245,12 @@ protected: class DecimalDotSorter : public NumericSorter { public: - DecimalDotSorter(bool isDescending) : NumericSorter(isDescending) { }; + DecimalDotSorter(bool isDescending, size_t fromColumn, size_t toColumn) : NumericSorter(isDescending, fromColumn, toColumn) { }; protected: generic_string prepareStringForConversion(const generic_string& input) override { - return stringTakeWhileAdmissable(input, TEXT(" \t\r\n0123456789.-")); + return stringTakeWhileAdmissable(getSortKey(input), TEXT(" \t\r\n0123456789.-")); } double convertStringToNumber(const generic_string& input) override diff --git a/PowerEditor/src/NppCommands.cpp b/PowerEditor/src/NppCommands.cpp index dde770068..068e920fb 100644 --- a/PowerEditor/src/NppCommands.cpp +++ b/PowerEditor/src/NppCommands.cpp @@ -354,31 +354,51 @@ void Notepad_plus::command(int id) case IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING: case IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING: { - // default: no selection - size_t fromLine = 0; - size_t toLine = _pEditView->execute(SCI_GETLINECOUNT) - 1; + size_t fromLine = 0, toLine = 0; + size_t fromColumn = 0, toColumn = 0; - // multi-selection is not allowed - if (_pEditView->execute(SCI_GETSELECTIONS) > 1) - return; - - // retangle-selection is not allowed - if (_pEditView->execute(SCI_SELECTIONISRECTANGLE)) - return; - - int selStart = _pEditView->execute(SCI_GETSELECTIONSTART); - int selEnd = _pEditView->execute(SCI_GETSELECTIONEND); - bool hasSelection = selStart != selEnd; - - pair lineRange = _pEditView->getSelectionLinesRange(); - - if (hasSelection) + bool hasLineSelection = false; + if (_pEditView->execute(SCI_GETSELECTIONS) > 1) { - // one single line selection is not allowed - if ((lineRange.second - lineRange.first) == 0) + if (_pEditView->execute(SCI_SELECTIONISRECTANGLE)) + { + ColumnModeInfos colInfos = _pEditView->getColumnModeSelectInfo(); + int leftPos = colInfos.begin()->_selLpos; + int rightPos = colInfos.rbegin()->_selRpos; + int startPos = min(leftPos, rightPos); + int endPos = max(leftPos, rightPos); + fromLine = _pEditView->execute(SCI_LINEFROMPOSITION, startPos); + toLine = _pEditView->execute(SCI_LINEFROMPOSITION, endPos); + fromColumn = _pEditView->execute(SCI_GETCOLUMN, leftPos); + toColumn = _pEditView->execute(SCI_GETCOLUMN, rightPos); + } + else + { return; - fromLine = lineRange.first; - toLine = lineRange.second; + } + } + else + { + int selStart = _pEditView->execute(SCI_GETSELECTIONSTART); + int selEnd = _pEditView->execute(SCI_GETSELECTIONEND); + hasLineSelection = selStart != selEnd; + if (hasLineSelection) + { + pair lineRange = _pEditView->getSelectionLinesRange(); + // One single line selection is not allowed. + if (lineRange.first == lineRange.second) + { + return; + } + fromLine = lineRange.first; + toLine = lineRange.second; + } + else + { + // No selection. + fromLine = 0; + toLine = _pEditView->execute(SCI_GETLINECOUNT) - 1; + } } bool isDescending = id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING || @@ -390,19 +410,19 @@ void Notepad_plus::command(int id) std::unique_ptr pSorter; if (id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING || id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING) { - pSorter = std::unique_ptr(new LexicographicSorter(isDescending)); + pSorter = std::unique_ptr(new LexicographicSorter(isDescending, fromColumn, toColumn)); } else if (id == IDM_EDIT_SORTLINES_INTEGER_DESCENDING || id == IDM_EDIT_SORTLINES_INTEGER_ASCENDING) { - pSorter = std::unique_ptr(new IntegerSorter(isDescending)); + pSorter = std::unique_ptr(new IntegerSorter(isDescending, fromColumn, toColumn)); } else if (id == IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING || id == IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING) { - pSorter = std::unique_ptr(new DecimalCommaSorter(isDescending)); + pSorter = std::unique_ptr(new DecimalCommaSorter(isDescending, fromColumn, toColumn)); } else { - pSorter = std::unique_ptr(new DecimalDotSorter(isDescending)); + pSorter = std::unique_ptr(new DecimalDotSorter(isDescending, fromColumn, toColumn)); } try { @@ -421,10 +441,10 @@ void Notepad_plus::command(int id) } _pEditView->execute(SCI_ENDUNDOACTION); - if (hasSelection) // there was 1 selection, so we restore it + if (hasLineSelection) // there was 1 selection, so we restore it { - int posStart = _pEditView->execute(SCI_POSITIONFROMLINE, lineRange.first); - int posEnd = _pEditView->execute(SCI_GETLINEENDPOSITION, lineRange.second); + int posStart = _pEditView->execute(SCI_POSITIONFROMLINE, fromLine); + int posEnd = _pEditView->execute(SCI_GETLINEENDPOSITION, toLine); _pEditView->execute(SCI_SETSELECTIONSTART, posStart); _pEditView->execute(SCI_SETSELECTIONEND, posEnd); } From f43c9875b33579160eec8b32d6281ec2c2978d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 25 May 2015 20:50:57 +0200 Subject: [PATCH 10/10] Fix menu options. --- PowerEditor/src/Notepad_plus.rc | 36 +++++++++++---------------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/PowerEditor/src/Notepad_plus.rc b/PowerEditor/src/Notepad_plus.rc index 66b1b5b07..79fbb8ec2 100644 --- a/PowerEditor/src/Notepad_plus.rc +++ b/PowerEditor/src/Notepad_plus.rc @@ -274,36 +274,24 @@ BEGIN MENUITEM "Duplicate Current Line", IDM_EDIT_DUP_LINE MENUITEM "Split Lines", IDM_EDIT_SPLIT_LINES MENUITEM "Join Lines", IDM_EDIT_JOIN_LINES - POPUP "Sort Lines" - BEGIN - POPUP "Lexicographic" - BEGIN - MENUITEM "Ascending", IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING - MENUITEM "Descending", IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING - END - POPUP "Integer" - BEGIN - MENUITEM "Ascending", IDM_EDIT_SORTLINES_INTEGER_ASCENDING - MENUITEM "Descending", IDM_EDIT_SORTLINES_INTEGER_DESCENDING - END - POPUP "Decimal (comma)" - BEGIN - MENUITEM "Ascending", IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING - MENUITEM "Descending", IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING - END - POPUP "Decimal (dot)" - BEGIN - MENUITEM "Ascending", IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING - MENUITEM "Descending", IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING - END - END MENUITEM "Move Up Current Line", IDM_EDIT_LINE_UP MENUITEM "Move Down Current Line", IDM_EDIT_LINE_DOWN MENUITEM "Remove Empty Lines", IDM_EDIT_REMOVEEMPTYLINES MENUITEM "Remove Empty Lines (Containing Blank characters)", IDM_EDIT_REMOVEEMPTYLINESWITHBLANK MENUITEM "Insert Blank Line Above Current", IDM_EDIT_BLANKLINEABOVECURRENT MENUITEM "Insert Blank Line Below Current", IDM_EDIT_BLANKLINEBELOWCURRENT - END + MENUITEM SEPARATOR + MENUITEM "Sort Lines Lexicographically Ascending", IDM_EDIT_SORTLINES_LEXICOGRAPHIC_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 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 + END + MENUITEM SEPARATOR POPUP "Comment/Uncomment" BEGIN MENUITEM "Toggle Single Line Comment", IDM_EDIT_BLOCK_COMMENT