From 4ca25503bc855b8a1c9232e990bf7daa668c05fa Mon Sep 17 00:00:00 2001 From: Scott Sumner <30118311+sasumner@users.noreply.github.com> Date: Sat, 29 Aug 2020 08:06:43 -0400 Subject: [PATCH] Enhance info provided in Sel portion of main status bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- PowerEditor/src/Notepad_plus.cpp | 56 ++++++++--- PowerEditor/src/NppCommands.cpp | 4 +- .../ScitillaComponent/ScintillaEditView.cpp | 93 ++++++++++++++++--- .../src/ScitillaComponent/ScintillaEditView.h | 33 +------ 4 files changed, 129 insertions(+), 57 deletions(-) diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index c056e9965..6c5b29f5c 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -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(_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 selCharsAndLines = _pEditView->getSelectedCharsAndLinesCount(maxSelsToProcessLineCount); + + if (_pEditView->execute(SCI_SELECTIONISRECTANGLE)) + { + int rectAnchor = static_cast(_pEditView->execute(SCI_GETCOLUMN, _pEditView->execute(SCI_GETRECTANGULARSELECTIONANCHOR))); + rectAnchor += static_cast(_pEditView->execute(SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE)); + int rectCaret = static_cast(_pEditView->execute(SCI_GETCOLUMN, _pEditView->execute(SCI_GETRECTANGULARSELECTIONCARET))); + rectCaret += static_cast(_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(_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) diff --git a/PowerEditor/src/NppCommands.cpp b/PowerEditor/src/NppCommands.cpp index feec82d84..f1383d082 100644 --- a/PowerEditor/src/NppCommands.cpp +++ b/PowerEditor/src/NppCommands.cpp @@ -1484,9 +1484,9 @@ void Notepad_plus::command(int id) case IDM_EDIT_SPLIT_LINES: { - pair lineRange = _pEditView->getSelectionLinesRange(); - if (lineRange.first != -1) + if (_pEditView->execute(SCI_GETSELECTIONS) == 1) { + pair 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); diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 1c11ff13a..528d97ca7 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -2787,27 +2787,36 @@ void ScintillaEditView::setMultiSelections(const ColumnModeInfos & cmi) } } -// Get selection range : (fromLine, toLine) -// return (-1, -1) if multi-selection -pair ScintillaEditView::getSelectionLinesRange() const +// Get selection range (fromLine, toLine) for the specified selection +// specify selectionNumber = -1 for the MAIN selection +pair ScintillaEditView::getSelectionLinesRange(int selectionNumber /* = -1 */) const { - pair range(-1, -1); - if (execute(SCI_GETSELECTIONS) > 1) // multi-selection - return range; - int32_t start = static_cast(execute(SCI_GETSELECTIONSTART)); - int32_t end = static_cast(execute(SCI_GETSELECTIONEND)); + int numSelections = static_cast(execute(SCI_GETSELECTIONS)); - range.first = static_cast(execute(SCI_LINEFROMPOSITION, start)); - range.second = static_cast(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(execute(SCI_GETSELECTIONSTART)); + end_pos = static_cast(execute(SCI_GETSELECTIONEND)); + } + else + { + start_pos = static_cast(execute(SCI_GETSELECTIONNSTART, selectionNumber)); + end_pos = static_cast(execute(SCI_GETSELECTIONNEND, selectionNumber)); + } + + int line1 = static_cast(execute(SCI_LINEFROMPOSITION, start_pos)); + int line2 = static_cast(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(line1, line2); } void ScintillaEditView::currentLinesUp() const @@ -3713,3 +3722,61 @@ void ScintillaEditView::getFoldColor(COLORREF& fgColor, COLORREF& bgColor, COLOR activeFgColor = style._fgColor; } } + +pair ScintillaEditView::getSelectedCharsAndLinesCount(int maxSelectionsForLineCount /* = -1 */) const +{ + pair selectedCharsAndLines(0, 0); + + selectedCharsAndLines.first = getUnicodeSelectedLength(); + + int numSelections = static_cast(execute(SCI_GETSELECTIONS)); + + if (numSelections == 1) + { + pair 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 > 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(execute(SCI_GETSELECTIONS)); + + for (int s = 0; s < numSelections; ++s) + { + int start = static_cast(execute(SCI_GETSELECTIONNSTART, s)); + int end = static_cast(execute(SCI_GETSELECTIONNEND, s)); + length += static_cast(execute(SCI_COUNTCHARACTERS, start, end)); + } + + return length; +}; diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index ba374160e..9cdc25f38 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -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 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 getSelectionLinesRange() const; + std::pair getSelectionLinesRange(int selectionNumber = -1) const; void currentLinesUp() const; void currentLinesDown() const;