Enhance info provided in Sel portion of main status bar

No selection:
Example: Pos : 1,234
Meaning: Single caret is at position 1233 in document (user position 1234)

Single stream selection (no change to existing behavior):
Example: Sel : 27 | 2
Meaning: 27 characters selected on 2 lines

Multiple stream selections (this PR behavior):
Example: Sel 3 : 72 | 6
Meaning: 3 selections of 72 characters on 6 lines

Rectangular selection with no virtual space in column block (this PR behavior):
Example: Sel : 2x4 = 8
Meaning: selection of 2 rows(lines) by 4 columns; 8 characters in that selection

Rectangular selection with some virtual space in column block (this PR behavior):
Example: Sel : 2x4 🡢 6
Meaning: selection of 2 rows(lines) by 4 columns; 6 real characters in that selection

Close #8524, close #8780
This commit is contained in:
Scott Sumner 2020-08-29 08:06:43 -04:00 committed by Don HO
parent 3fd3e85a54
commit 4ca25503bc
4 changed files with 129 additions and 57 deletions

View File

@ -3235,33 +3235,65 @@ int Notepad_plus::wordCount()
void Notepad_plus::updateStatusBar()
{
TCHAR strLnCol[128];
TCHAR strLnCol[128];
TCHAR strSel[64];
int selByte = 0;
int selLine = 0;
_pEditView->getSelectedCount(selByte, selLine);
int selCount = static_cast<int>(_pEditView->execute(SCI_GETSELECTIONS));
long selected_length = _pEditView->getUnicodeSelectedLength();
if (selected_length != -1)
wsprintf(strSel, TEXT("Sel : %s | %s"), commafyInt(selected_length).c_str(), commafyInt(selLine).c_str());
const int maxSelsToProcessLineCount = 99; // limit the number of selections to process, for performance reasons
const std::pair<int, int> selCharsAndLines = _pEditView->getSelectedCharsAndLinesCount(maxSelsToProcessLineCount);
if (_pEditView->execute(SCI_SELECTIONISRECTANGLE))
{
int rectAnchor = static_cast<int>(_pEditView->execute(SCI_GETCOLUMN, _pEditView->execute(SCI_GETRECTANGULARSELECTIONANCHOR)));
rectAnchor += static_cast<int>(_pEditView->execute(SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE));
int rectCaret = static_cast<int>(_pEditView->execute(SCI_GETCOLUMN, _pEditView->execute(SCI_GETRECTANGULARSELECTIONCARET)));
rectCaret += static_cast<int>(_pEditView->execute(SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE));
int rectWidth = std::abs(rectCaret - rectAnchor);
bool hasVirtualSpace = selCharsAndLines.first != selCount * rectWidth;
wsprintf(strSel, TEXT("Sel : %sx%s %s %s"),
commafyInt(selCount).c_str(),
commafyInt(rectWidth).c_str(),
hasVirtualSpace ? TEXT("🡢") : TEXT("="),
commafyInt(selCharsAndLines.first).c_str());
}
else if (selCount > 1)
{
wsprintf(strSel, TEXT("Sel %s : %s | %s"),
commafyInt(selCount).c_str(),
commafyInt(selCharsAndLines.first).c_str(),
selCount <= maxSelsToProcessLineCount ?
commafyInt(selCharsAndLines.second).c_str() :
TEXT("")); // show ellipsis for line count if too many selections are active
}
else if (selCharsAndLines.first > 0)
{
wsprintf(strSel, TEXT("Sel : %s | %s"),
commafyInt(selCharsAndLines.first).c_str(),
commafyInt(selCharsAndLines.second).c_str());
}
else
wsprintf(strSel, TEXT("Sel : %s"), TEXT("N/A"));
{
int curPos = static_cast<int>(_pEditView->execute(SCI_GETCURRENTPOS));
wsprintf(strSel, TEXT("Pos : %s"), commafyInt(curPos + 1).c_str());
}
wsprintf(strLnCol, TEXT("Ln : %s Col : %s %s"),
commafyInt(_pEditView->getCurrentLineNumber() + 1).c_str(),
commafyInt(_pEditView->getCurrentColumnNumber() + 1).c_str(),
strSel);
_statusBar.setText(strLnCol, STATUSBAR_CUR_POS);
_statusBar.setText(strLnCol, STATUSBAR_CUR_POS);
TCHAR strDocLen[256];
TCHAR strDocLen[256];
wsprintf(strDocLen, TEXT("length : %s lines : %s"),
commafyInt(_pEditView->getCurrentDocLen()).c_str(),
commafyInt(_pEditView->execute(SCI_GETLINECOUNT)).c_str());
_statusBar.setText(strDocLen, STATUSBAR_DOC_SIZE);
_statusBar.setText(_pEditView->execute(SCI_GETOVERTYPE) ? TEXT("OVR") : TEXT("INS"), STATUSBAR_TYPING_MODE);
_statusBar.setText(strDocLen, STATUSBAR_DOC_SIZE);
_statusBar.setText(_pEditView->execute(SCI_GETOVERTYPE) ? TEXT("OVR") : TEXT("INS"), STATUSBAR_TYPING_MODE);
}
void Notepad_plus::dropFiles(HDROP hdrop)

View File

@ -1484,9 +1484,9 @@ void Notepad_plus::command(int id)
case IDM_EDIT_SPLIT_LINES:
{
pair<int, int> lineRange = _pEditView->getSelectionLinesRange();
if (lineRange.first != -1)
if (_pEditView->execute(SCI_GETSELECTIONS) == 1)
{
pair<int, int> lineRange = _pEditView->getSelectionLinesRange();
auto anchorPos = _pEditView->execute(SCI_POSITIONFROMLINE, lineRange.first);
auto caretPos = _pEditView->execute(SCI_GETLINEENDPOSITION, lineRange.second);
_pEditView->execute(SCI_SETSELECTION, caretPos, anchorPos);

View File

@ -2787,27 +2787,36 @@ void ScintillaEditView::setMultiSelections(const ColumnModeInfos & cmi)
}
}
// Get selection range : (fromLine, toLine)
// return (-1, -1) if multi-selection
pair<int, int> ScintillaEditView::getSelectionLinesRange() const
// Get selection range (fromLine, toLine) for the specified selection
// specify selectionNumber = -1 for the MAIN selection
pair<int, int> ScintillaEditView::getSelectionLinesRange(int selectionNumber /* = -1 */) const
{
pair<int, int> range(-1, -1);
if (execute(SCI_GETSELECTIONS) > 1) // multi-selection
return range;
int32_t start = static_cast<int32_t>(execute(SCI_GETSELECTIONSTART));
int32_t end = static_cast<int32_t>(execute(SCI_GETSELECTIONEND));
int numSelections = static_cast<int>(execute(SCI_GETSELECTIONS));
range.first = static_cast<int32_t>(execute(SCI_LINEFROMPOSITION, start));
range.second = static_cast<int32_t>(execute(SCI_LINEFROMPOSITION, end));
int start_pos, end_pos;
if ((range.first != range.second) && (execute(SCI_POSITIONFROMLINE, range.second) == end))
if ((selectionNumber < 0) || (selectionNumber >= numSelections))
{
start_pos = static_cast<int>(execute(SCI_GETSELECTIONSTART));
end_pos = static_cast<int>(execute(SCI_GETSELECTIONEND));
}
else
{
start_pos = static_cast<int>(execute(SCI_GETSELECTIONNSTART, selectionNumber));
end_pos = static_cast<int>(execute(SCI_GETSELECTIONNEND, selectionNumber));
}
int line1 = static_cast<int>(execute(SCI_LINEFROMPOSITION, start_pos));
int line2 = static_cast<int>(execute(SCI_LINEFROMPOSITION, end_pos));
if ((line1 != line2) && (execute(SCI_POSITIONFROMLINE, line2) == end_pos))
{
// if the end of the selection includes the line-ending,
// then don't include the following line in the range
--range.second;
--line2;
}
return range;
return pair<int, int>(line1, line2);
}
void ScintillaEditView::currentLinesUp() const
@ -3713,3 +3722,61 @@ void ScintillaEditView::getFoldColor(COLORREF& fgColor, COLORREF& bgColor, COLOR
activeFgColor = style._fgColor;
}
}
pair<int, int> ScintillaEditView::getSelectedCharsAndLinesCount(int maxSelectionsForLineCount /* = -1 */) const
{
pair<int, int> selectedCharsAndLines(0, 0);
selectedCharsAndLines.first = getUnicodeSelectedLength();
int numSelections = static_cast<int>(execute(SCI_GETSELECTIONS));
if (numSelections == 1)
{
pair<int, int> lineRange = getSelectionLinesRange();
selectedCharsAndLines.second = lineRange.second - lineRange.first + 1;
}
else if ((maxSelectionsForLineCount == -1) || // -1 means process ALL of the selections
(numSelections <= maxSelectionsForLineCount))
{
// selections are obtained from Scintilla in the order user creates them,
// not in a lowest-to-highest position-based order;
// to be able to get a line-count that can't count the same line more than once,
// we have to reorder the lines touched
// by selection into low-to-high line number order before processing them further
vector< pair <int, int> > v;
for (int s = 0; s < numSelections; ++s)
{
v.push_back(getSelectionLinesRange(s));
}
sort(v.begin(), v.end());
int previousSecondLine = -1;
for (auto lineRange : v)
{
selectedCharsAndLines.second += lineRange.second - lineRange.first;
if (lineRange.first != previousSecondLine)
{
++selectedCharsAndLines.second;
}
previousSecondLine = lineRange.second;
}
}
return selectedCharsAndLines;
};
int ScintillaEditView::getUnicodeSelectedLength() const
{
int length = 0;
int numSelections = static_cast<int>(execute(SCI_GETSELECTIONS));
for (int s = 0; s < numSelections; ++s)
{
int start = static_cast<int>(execute(SCI_GETSELECTIONNSTART, s));
int end = static_cast<int>(execute(SCI_GETSELECTIONNEND, s));
length += static_cast<int>(execute(SCI_COUNTCHARACTERS, start, end));
}
return length;
};

View File

@ -459,36 +459,9 @@ public:
return long(execute(SCI_GETCOLUMN, execute(SCI_GETCURRENTPOS)));
};
bool getSelectedCount(int & selByte, int & selLine) const {
// return false if it's multi-selection or rectangle selection
if ((execute(SCI_GETSELECTIONS) > 1) || execute(SCI_SELECTIONISRECTANGLE))
return false;
long pStart = long(execute(SCI_GETSELECTIONSTART));
long pEnd = long(execute(SCI_GETSELECTIONEND));
selByte = pEnd - pStart;
long lStart = long(execute(SCI_LINEFROMPOSITION, pStart));
long lEnd = long(execute(SCI_LINEFROMPOSITION, pEnd));
selLine = lEnd - lStart;
if (selLine || selByte)
++selLine;
return true;
};
long getUnicodeSelectedLength() const
{
// return -1 if it's multi-selection or rectangle selection
if ((execute(SCI_GETSELECTIONS) > 1) || execute(SCI_SELECTIONISRECTANGLE))
return -1;
long start = long(execute(SCI_GETSELECTIONSTART));
long end = long(execute(SCI_GETSELECTIONEND));
long length = long(execute(SCI_COUNTCHARACTERS, start, end));
return length;
};
std::pair<int, int> getSelectedCharsAndLinesCount(int maxSelectionsForLineCount = -1) const;
int getUnicodeSelectedLength() const;
long getLineLength(int line) const {
return long(execute(SCI_GETLINEENDPOSITION, line) - execute(SCI_POSITIONFROMLINE, line));
@ -531,7 +504,7 @@ public:
void expand(size_t& line, bool doExpand, bool force = false, int visLevels = 0, int level = -1);
std::pair<int, int> getSelectionLinesRange() const;
std::pair<int, int> getSelectionLinesRange(int selectionNumber = -1) const;
void currentLinesUp() const;
void currentLinesDown() const;