Use a rectangular selection as sort key.

This commit is contained in:
Andreas Jönsson 2015-05-21 15:53:48 +02:00
parent 626dc02c4c
commit 7c3376ae6b
2 changed files with 108 additions and 47 deletions

View File

@ -34,6 +34,7 @@ class ISorter
{ {
private: private:
bool _isDescending; bool _isDescending;
size_t _fromColumn, _toColumn;
protected: protected:
bool isDescending() const bool isDescending() const
@ -41,8 +42,28 @@ protected:
return _isDescending; 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: 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 ~ISorter() { };
virtual std::vector<generic_string> sort(std::vector<generic_string> lines) = 0; virtual std::vector<generic_string> sort(std::vector<generic_string> lines) = 0;
}; };
@ -51,14 +72,33 @@ public:
class LexicographicSorter : public ISorter class LexicographicSorter : public ISorter
{ {
public: public:
LexicographicSorter(bool isDescending) : ISorter(isDescending) { }; LexicographicSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { };
std::vector<generic_string> sort(std::vector<generic_string> lines) override std::vector<generic_string> sort(std::vector<generic_string> lines) override
{ {
const bool descending = isDescending(); // Note that both branches here are equivalent in the sense that they give always give the same answer.
std::sort(lines.begin(), lines.end(), [descending](generic_string a, generic_string b) // 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)
{
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)
{
if (isDescending())
{ {
return a.compare(b) > 0; return a.compare(b) > 0;
} }
@ -67,6 +107,7 @@ public:
return a.compare(b) < 0; return a.compare(b) < 0;
} }
}); });
}
return lines; return lines;
} }
}; };
@ -77,7 +118,7 @@ template<typename T_Num>
class NumericSorter : public ISorter class NumericSorter : public ISorter
{ {
public: 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")); _usLocale = ::_wcreate_locale(LC_NUMERIC, TEXT("en-US"));
}; };
@ -167,12 +208,12 @@ protected:
class IntegerSorter : public NumericSorter<long long> class IntegerSorter : public NumericSorter<long long>
{ {
public: public:
IntegerSorter(bool isDescending) : NumericSorter<long long>(isDescending) { }; IntegerSorter(bool isDescending, size_t fromColumn, size_t toColumn) : NumericSorter<long long>(isDescending, fromColumn, toColumn) { };
protected: protected:
virtual generic_string prepareStringForConversion(const generic_string& input) 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 long long convertStringToNumber(const generic_string& input) override
@ -185,12 +226,12 @@ protected:
class DecimalCommaSorter : public NumericSorter<double> class DecimalCommaSorter : public NumericSorter<double>
{ {
public: public:
DecimalCommaSorter(bool isDescending) : NumericSorter<double>(isDescending) { }; DecimalCommaSorter(bool isDescending, size_t fromColumn, size_t toColumn) : NumericSorter<double>(isDescending, fromColumn, toColumn) { };
protected: protected:
generic_string prepareStringForConversion(const generic_string& input) override 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(".")); return stringReplace(admissablePart, TEXT(","), TEXT("."));
} }
@ -204,12 +245,12 @@ protected:
class DecimalDotSorter : public NumericSorter<double> class DecimalDotSorter : public NumericSorter<double>
{ {
public: public:
DecimalDotSorter(bool isDescending) : NumericSorter<double>(isDescending) { }; DecimalDotSorter(bool isDescending, size_t fromColumn, size_t toColumn) : NumericSorter<double>(isDescending, fromColumn, toColumn) { };
protected: protected:
generic_string prepareStringForConversion(const generic_string& input) override 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 double convertStringToNumber(const generic_string& input) override

View File

@ -354,32 +354,52 @@ void Notepad_plus::command(int id)
case IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING: case IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING:
case IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING: case IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING:
{ {
// default: no selection size_t fromLine = 0, toLine = 0;
size_t fromLine = 0; size_t fromColumn = 0, toColumn = 0;
size_t toLine = _pEditView->execute(SCI_GETLINECOUNT) - 1;
// multi-selection is not allowed bool hasLineSelection = false;
if (_pEditView->execute(SCI_GETSELECTIONS) > 1) if (_pEditView->execute(SCI_GETSELECTIONS) > 1)
return; {
// retangle-selection is not allowed
if (_pEditView->execute(SCI_SELECTIONISRECTANGLE)) 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; return;
}
}
else
{
int selStart = _pEditView->execute(SCI_GETSELECTIONSTART); int selStart = _pEditView->execute(SCI_GETSELECTIONSTART);
int selEnd = _pEditView->execute(SCI_GETSELECTIONEND); int selEnd = _pEditView->execute(SCI_GETSELECTIONEND);
bool hasSelection = selStart != selEnd; hasLineSelection = selStart != selEnd;
if (hasLineSelection)
pair<int, int> lineRange = _pEditView->getSelectionLinesRange(); {
pair<int, int> lineRange = _pEditView->getSelectionLinesRange();
if (hasSelection) // One single line selection is not allowed.
if (lineRange.first == lineRange.second)
{ {
// one single line selection is not allowed
if ((lineRange.second - lineRange.first) == 0)
return; return;
}
fromLine = lineRange.first; fromLine = lineRange.first;
toLine = lineRange.second; toLine = lineRange.second;
} }
else
{
// No selection.
fromLine = 0;
toLine = _pEditView->execute(SCI_GETLINECOUNT) - 1;
}
}
bool isDescending = id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING || bool isDescending = id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING ||
id == IDM_EDIT_SORTLINES_INTEGER_DESCENDING || id == IDM_EDIT_SORTLINES_INTEGER_DESCENDING ||
@ -390,19 +410,19 @@ void Notepad_plus::command(int id)
std::unique_ptr<ISorter> pSorter; std::unique_ptr<ISorter> pSorter;
if (id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING || id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING) if (id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_DESCENDING || id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_ASCENDING)
{ {
pSorter = std::unique_ptr<ISorter>(new LexicographicSorter(isDescending)); pSorter = std::unique_ptr<ISorter>(new LexicographicSorter(isDescending, fromColumn, toColumn));
} }
else if (id == IDM_EDIT_SORTLINES_INTEGER_DESCENDING || id == IDM_EDIT_SORTLINES_INTEGER_ASCENDING) else if (id == IDM_EDIT_SORTLINES_INTEGER_DESCENDING || id == IDM_EDIT_SORTLINES_INTEGER_ASCENDING)
{ {
pSorter = std::unique_ptr<ISorter>(new IntegerSorter(isDescending)); pSorter = std::unique_ptr<ISorter>(new IntegerSorter(isDescending, fromColumn, toColumn));
} }
else if (id == IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING || id == IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING) else if (id == IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING || id == IDM_EDIT_SORTLINES_DECIMALCOMMA_ASCENDING)
{ {
pSorter = std::unique_ptr<ISorter>(new DecimalCommaSorter(isDescending)); pSorter = std::unique_ptr<ISorter>(new DecimalCommaSorter(isDescending, fromColumn, toColumn));
} }
else else
{ {
pSorter = std::unique_ptr<ISorter>(new DecimalDotSorter(isDescending)); pSorter = std::unique_ptr<ISorter>(new DecimalDotSorter(isDescending, fromColumn, toColumn));
} }
try try
{ {
@ -421,10 +441,10 @@ void Notepad_plus::command(int id)
} }
_pEditView->execute(SCI_ENDUNDOACTION); _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 posStart = _pEditView->execute(SCI_POSITIONFROMLINE, fromLine);
int posEnd = _pEditView->execute(SCI_GETLINEENDPOSITION, lineRange.second); int posEnd = _pEditView->execute(SCI_GETLINEENDPOSITION, toLine);
_pEditView->execute(SCI_SETSELECTIONSTART, posStart); _pEditView->execute(SCI_SETSELECTIONSTART, posStart);
_pEditView->execute(SCI_SETSELECTIONEND, posEnd); _pEditView->execute(SCI_SETSELECTIONEND, posEnd);
} }