Skip to content

Commit

Permalink
Enhance multi-edit paste and Enter key type
Browse files Browse the repository at this point in the history
Also disable auto-indent during multi-editing.

Ref: notepad-plus-plus#14338 (comment)
  • Loading branch information
donho committed Nov 14, 2023
1 parent 812745d commit 99364ff
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 31 deletions.
12 changes: 6 additions & 6 deletions PowerEditor/src/Notepad_plus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4218,8 +4218,8 @@ void Notepad_plus::updateStatusBar()

TCHAR strSel[64];

size_t numSelections = _pEditView->execute(SCI_GETSELECTIONS);
if (numSelections == 1)
size_t nbSelections = _pEditView->execute(SCI_GETSELECTIONS);
if (nbSelections == 1)
{
if (_pEditView->execute(SCI_GETSELECTIONEMPTY))
{
Expand All @@ -4241,7 +4241,7 @@ void Notepad_plus::updateStatusBar()
bool sameCharCountOnEveryLine = true;
size_t maxLineCharCount = 0;

for (size_t sel = 0; sel < numSelections; ++sel)
for (size_t sel = 0; sel < nbSelections; ++sel)
{
size_t start = _pEditView->execute(SCI_GETSELECTIONNSTART, sel);
size_t end = _pEditView->execute(SCI_GETSELECTIONNEND, sel);
Expand All @@ -4265,7 +4265,7 @@ void Notepad_plus::updateStatusBar()
}

wsprintf(strSel, TEXT("Sel : %sx%s %s %s"),
commafyInt(numSelections).c_str(), // lines (rows) in rectangular selection
commafyInt(nbSelections).c_str(), // lines (rows) in rectangular selection
commafyInt(maxLineCharCount).c_str(), // show maximum width for columns
sameCharCountOnEveryLine ? TEXT("=") : TEXT("->"),
commafyInt(rectSelCharsAndLines.first).c_str());
Expand All @@ -4276,9 +4276,9 @@ void Notepad_plus::updateStatusBar()
const std::pair<size_t, size_t> multipleSelCharsAndLines = _pEditView->getSelectedCharsAndLinesCount(maxSelsToProcessLineCount);

wsprintf(strSel, TEXT("Sel %s : %s | %s"),
commafyInt(numSelections).c_str(),
commafyInt(nbSelections).c_str(),
commafyInt(multipleSelCharsAndLines.first).c_str(),
numSelections <= maxSelsToProcessLineCount ?
nbSelections <= maxSelsToProcessLineCount ?
commafyInt(multipleSelCharsAndLines.second).c_str() :
TEXT("...")); // show ellipsis for line count if too many selections are active
}
Expand Down
8 changes: 4 additions & 4 deletions PowerEditor/src/NppCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,10 @@ void Notepad_plus::command(int id)
{
std::lock_guard<std::mutex> lock(command_mutex);

size_t numSelections = _pEditView->execute(SCI_GETSELECTIONS);
size_t nbSelections = _pEditView->execute(SCI_GETSELECTIONS);
Buffer* buf = getCurrentBuffer();
bool isRO = buf->isReadOnly();
if (numSelections > 1 && !isRO)
if (nbSelections > 1 && !isRO)
{
bool isPasteDone = _pEditView->pasteToMultiSelection();
if (isPasteDone)
Expand Down Expand Up @@ -1783,10 +1783,10 @@ void Notepad_plus::command(int id)
bool forwards = id == IDM_EDIT_INS_TAB;
size_t selStartPos = _pEditView->execute(SCI_GETSELECTIONSTART);
size_t lineNumber = _pEditView->execute(SCI_LINEFROMPOSITION, selStartPos);
size_t numSelections = _pEditView->execute(SCI_GETSELECTIONS);
size_t nbSelections = _pEditView->execute(SCI_GETSELECTIONS);
size_t selEndPos = _pEditView->execute(SCI_GETSELECTIONEND);
size_t selEndLineNumber = _pEditView->execute(SCI_LINEFROMPOSITION, selEndPos);
if ((numSelections > 1) || (lineNumber != selEndLineNumber))
if ((nbSelections > 1) || (lineNumber != selEndLineNumber))
{
// multiple-selection or multi-line selection; use Scintilla SCI_TAB / SCI_BACKTAB behavior
_pEditView->execute(forwards ? SCI_TAB : SCI_BACKTAB);
Expand Down
3 changes: 2 additions & 1 deletion PowerEditor/src/NppNotification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,8 @@ BOOL Notepad_plus::notify(SCNotification *notification)
{
const NppGUI & nppGui = NppParameters::getInstance().getNppGUI();
bool indentMaintain = nppGui._maitainIndent;
if (indentMaintain)
size_t nbSelections = _pEditView->execute(SCI_GETSELECTIONS);
if (indentMaintain && nbSelections <= 1) // No auto-indent if multi-edit is active
maintainIndentation(static_cast<TCHAR>(notification->ch));

Buffer* currentBuf = _pEditView->getCurrentBuffer();
Expand Down
72 changes: 52 additions & 20 deletions PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ LRESULT ScintillaEditView::scintillaNew_Proc(HWND hwnd, UINT Message, WPARAM wPa
case VK_DOWN:
case VK_HOME:
case VK_END:
case VK_RETURN:
execute(SCI_SETSELECTIONMODE, SC_SEL_STREAM); // When it's rectangular selection and the arrow keys are pressed, we switch the mode for having multiple carets.

execute(SCI_SETSELECTIONMODE, SC_SEL_STREAM); // the 2nd call for removing the unwanted selection while moving carets.
Expand Down Expand Up @@ -590,8 +591,8 @@ LRESULT ScintillaEditView::scintillaNew_Proc(HWND hwnd, UINT Message, WPARAM wPa
{
Buffer* buf = getCurrentBuffer();
bool isRO = buf->isReadOnly();
size_t numSelections = execute(SCI_GETSELECTIONS);
if (numSelections > 1 && !isRO)
size_t nbSelections = execute(SCI_GETSELECTIONS);
if (nbSelections > 1 && !isRO)
{
if (pasteToMultiSelection())
{
Expand Down Expand Up @@ -3199,11 +3200,11 @@ void ScintillaEditView::setMultiSelections(const ColumnModeInfos & cmi)
// specify selectionNumber = -1 for the MAIN selection
pair<size_t, size_t> ScintillaEditView::getSelectionLinesRange(intptr_t selectionNumber /* = -1 */) const
{
size_t numSelections = execute(SCI_GETSELECTIONS);
size_t nbSelections = execute(SCI_GETSELECTIONS);

size_t start_pos, end_pos;

if ((selectionNumber < 0) || (static_cast<size_t>(selectionNumber) >= numSelections))
if ((selectionNumber < 0) || (static_cast<size_t>(selectionNumber) >= nbSelections))
{
start_pos = execute(SCI_GETSELECTIONSTART);
end_pos = execute(SCI_GETSELECTIONEND);
Expand Down Expand Up @@ -4243,19 +4244,19 @@ pair<size_t, size_t> ScintillaEditView::getSelectedCharsAndLinesCount(long long

selectedCharsAndLines.first = getUnicodeSelectedLength();

size_t numSelections = execute(SCI_GETSELECTIONS);
size_t nbSelections = execute(SCI_GETSELECTIONS);

if (numSelections == 1)
if (nbSelections == 1)
{
pair<size_t, size_t> lineRange = getSelectionLinesRange();
selectedCharsAndLines.second = lineRange.second - lineRange.first + 1;
}
else if (execute(SCI_SELECTIONISRECTANGLE))
{
selectedCharsAndLines.second = numSelections;
selectedCharsAndLines.second = nbSelections;
}
else if ((maxSelectionsForLineCount == -1) || // -1 means process ALL of the selections
(numSelections <= static_cast<size_t>(maxSelectionsForLineCount)))
(nbSelections <= static_cast<size_t>(maxSelectionsForLineCount)))
{
// selections are obtained from Scintilla in the order user creates them,
// not in a lowest-to-highest position-based order;
Expand All @@ -4264,7 +4265,7 @@ pair<size_t, size_t> ScintillaEditView::getSelectedCharsAndLinesCount(long long
// by selection into low-to-high line number order before processing them further

vector< pair <size_t, size_t> > v;
for (size_t s = 0; s < numSelections; ++s)
for (size_t s = 0; s < nbSelections; ++s)
{
v.push_back(getSelectionLinesRange(s));
}
Expand All @@ -4287,9 +4288,9 @@ pair<size_t, size_t> ScintillaEditView::getSelectedCharsAndLinesCount(long long
size_t ScintillaEditView::getUnicodeSelectedLength() const
{
size_t length = 0;
size_t numSelections = execute(SCI_GETSELECTIONS);
size_t nbSelections = execute(SCI_GETSELECTIONS);

for (size_t s = 0; s < numSelections; ++s)
for (size_t s = 0; s < nbSelections; ++s)
{
size_t start = execute(SCI_GETSELECTIONNSTART, s);
size_t end = execute(SCI_GETSELECTIONNEND, s);
Expand Down Expand Up @@ -4451,8 +4452,8 @@ void ScintillaEditView::removeAnyDuplicateLines()

bool ScintillaEditView::pasteToMultiSelection() const
{
size_t numSelections = execute(SCI_GETSELECTIONS);
if (numSelections <= 1)
size_t nbSelections = execute(SCI_GETSELECTIONS);
if (nbSelections <= 1)
return false;

// "MSDEVColumnSelect" is column format from Scintilla
Expand All @@ -4468,19 +4469,50 @@ bool ScintillaEditView::pasteToMultiSelection() const
::GlobalUnlock(clipboardData);
::CloseClipboard();

vector<wstring> stringArray;
stringSplit(clipboardStr, getEOLString(), stringArray);
stringArray.erase(stringArray.cend() - 1); // remove the last empty string
vector<wstring> clipboardStrings;
stringSplit(clipboardStr, getEOLString(), clipboardStrings);
clipboardStrings.erase(clipboardStrings.cend() - 1); // remove the last empty string
size_t nbClipboardStr = clipboardStrings.size();

if (numSelections == stringArray.size())
if (nbSelections >= nbClipboardStr) // enough holes for every insertion, keep holes empty if there are some left
{
execute(SCI_BEGINUNDOACTION);
for (size_t i = 0; i < numSelections; ++i)
for (size_t i = 0; i < nbClipboardStr; ++i)
{
LRESULT posStart = execute(SCI_GETSELECTIONNSTART, i);
LRESULT posEnd = execute(SCI_GETSELECTIONNEND, i);
replaceTarget(stringArray[i].c_str(), posStart, posEnd);
posStart += stringArray[i].length();
replaceTarget(clipboardStrings[i].c_str(), posStart, posEnd);
posStart += clipboardStrings[i].length();
execute(SCI_SETSELECTIONNSTART, i, posStart);
execute(SCI_SETSELECTIONNEND, i, posStart);
}
execute(SCI_ENDUNDOACTION);
return true;
}
else if (nbSelections < nbClipboardStr) // not enough holes for insertion, every hole has several insertions
{
size_t nbStr2takeFromClipboard = nbClipboardStr / nbSelections;

execute(SCI_BEGINUNDOACTION);
size_t j = 0;
for (size_t i = 0; i < nbSelections; ++i)
{
LRESULT posStart = execute(SCI_GETSELECTIONNSTART, i);
LRESULT posEnd = execute(SCI_GETSELECTIONNEND, i);
wstring severalStr;
wstring eol = getEOLString();
for (size_t k = 0; k < nbStr2takeFromClipboard && j < nbClipboardStr; ++k)
{
severalStr += clipboardStrings[j];
severalStr += eol;
++j;
}

// remove the latest added EOL
severalStr.erase(severalStr.length() - eol.length());

replaceTarget(severalStr.c_str(), posStart, posEnd);
posStart += severalStr.length();
execute(SCI_SETSELECTIONNSTART, i, posStart);
execute(SCI_SETSELECTIONNEND, i, posStart);
}
Expand Down

0 comments on commit 99364ff

Please sign in to comment.