Use a rectangular selection as sort key.
This commit is contained in:
parent
626dc02c4c
commit
7c3376ae6b
@ -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,22 +72,42 @@ 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)
|
||||||
{
|
{
|
||||||
return a.compare(b) > 0;
|
if (isDescending())
|
||||||
}
|
{
|
||||||
else
|
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;
|
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
|
||||||
|
@ -354,31 +354,51 @@ 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))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int selStart = _pEditView->execute(SCI_GETSELECTIONSTART);
|
|
||||||
int selEnd = _pEditView->execute(SCI_GETSELECTIONEND);
|
|
||||||
bool hasSelection = selStart != selEnd;
|
|
||||||
|
|
||||||
pair<int, int> lineRange = _pEditView->getSelectionLinesRange();
|
|
||||||
|
|
||||||
if (hasSelection)
|
|
||||||
{
|
{
|
||||||
// one single line selection is not allowed
|
if (_pEditView->execute(SCI_SELECTIONISRECTANGLE))
|
||||||
if ((lineRange.second - lineRange.first) == 0)
|
{
|
||||||
|
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;
|
||||||
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<int, int> 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 ||
|
bool isDescending = id == IDM_EDIT_SORTLINES_LEXICOGRAPHIC_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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user