Enhance multi-edit paste and Enter key type
Also disable auto-indent during multi-editing. Ref: https://github.com/notepad-plus-plus/notepad-plus-plus/pull/14338#issuecomment-1809045648 Close #14355
This commit is contained in:
parent
05f339b0cf
commit
1764758669
|
@ -356,6 +356,10 @@ LRESULT Notepad_plus::init(HWND hwnd)
|
|||
_mainEditView.execute(SCI_SETMULTIPASTE, SC_MULTIPASTE_EACH);
|
||||
_subEditView.execute(SCI_SETMULTIPASTE, SC_MULTIPASTE_EACH);
|
||||
|
||||
// Turn auto-completion into each multi-select on
|
||||
_mainEditView.execute(SCI_AUTOCSETMULTI, SC_MULTIAUTOC_EACH);
|
||||
_subEditView.execute(SCI_AUTOCSETMULTI, SC_MULTIAUTOC_EACH);
|
||||
|
||||
// allow user to start selecting as a stream block, then switch to a column block by adding Alt keypress
|
||||
_mainEditView.execute(SCI_SETMOUSESELECTIONRECTANGULARSWITCH, true);
|
||||
_subEditView.execute(SCI_SETMOUSESELECTIONRECTANGULARSWITCH, true);
|
||||
|
@ -4218,8 +4222,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))
|
||||
{
|
||||
|
@ -4241,7 +4245,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);
|
||||
|
@ -4265,7 +4269,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());
|
||||
|
@ -4276,9 +4280,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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -603,7 +604,6 @@ LRESULT ScintillaEditView::scintillaNew_Proc(HWND hwnd, UINT Message, WPARAM wPa
|
|||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -3092,43 +3092,101 @@ void ScintillaEditView::showIndentGuideLine(bool willBeShowed)
|
|||
|
||||
void ScintillaEditView::setLineIndent(size_t line, size_t indent) const
|
||||
{
|
||||
Sci_CharacterRangeFull crange = getSelection();
|
||||
int64_t posBefore = execute(SCI_GETLINEINDENTPOSITION, line);
|
||||
execute(SCI_SETLINEINDENTATION, line, indent);
|
||||
int64_t posAfter = execute(SCI_GETLINEINDENTPOSITION, line);
|
||||
long long posDifference = posAfter - posBefore;
|
||||
if (posAfter > posBefore)
|
||||
{
|
||||
// Move selection on
|
||||
if (crange.cpMin >= posBefore)
|
||||
{
|
||||
crange.cpMin += static_cast<Sci_Position>(posDifference);
|
||||
}
|
||||
if (crange.cpMax >= posBefore)
|
||||
{
|
||||
crange.cpMax += static_cast<Sci_Position>(posDifference);
|
||||
}
|
||||
}
|
||||
else if (posAfter < posBefore)
|
||||
{
|
||||
// Move selection back
|
||||
if (crange.cpMin >= posAfter)
|
||||
{
|
||||
if (crange.cpMin >= posBefore)
|
||||
crange.cpMin += static_cast<Sci_Position>(posDifference);
|
||||
else
|
||||
crange.cpMin = static_cast<Sci_Position>(posAfter);
|
||||
}
|
||||
size_t nbSelections = execute(SCI_GETSELECTIONS);
|
||||
|
||||
if (crange.cpMax >= posAfter)
|
||||
if (nbSelections == 1)
|
||||
{
|
||||
Sci_CharacterRangeFull crange = getSelection();
|
||||
int64_t posBefore = execute(SCI_GETLINEINDENTPOSITION, line);
|
||||
execute(SCI_SETLINEINDENTATION, line, indent);
|
||||
int64_t posAfter = execute(SCI_GETLINEINDENTPOSITION, line);
|
||||
long long posDifference = posAfter - posBefore;
|
||||
if (posAfter > posBefore)
|
||||
{
|
||||
// Move selection on
|
||||
if (crange.cpMin >= posBefore)
|
||||
{
|
||||
crange.cpMin += static_cast<Sci_Position>(posDifference);
|
||||
}
|
||||
if (crange.cpMax >= posBefore)
|
||||
{
|
||||
crange.cpMax += static_cast<Sci_Position>(posDifference);
|
||||
else
|
||||
crange.cpMax = static_cast<Sci_Position>(posAfter);
|
||||
}
|
||||
}
|
||||
else if (posAfter < posBefore)
|
||||
{
|
||||
// Move selection back
|
||||
if (crange.cpMin >= posAfter)
|
||||
{
|
||||
if (crange.cpMin >= posBefore)
|
||||
crange.cpMin += static_cast<Sci_Position>(posDifference);
|
||||
else
|
||||
crange.cpMin = static_cast<Sci_Position>(posAfter);
|
||||
}
|
||||
|
||||
if (crange.cpMax >= posAfter)
|
||||
{
|
||||
if (crange.cpMax >= posBefore)
|
||||
crange.cpMax += static_cast<Sci_Position>(posDifference);
|
||||
else
|
||||
crange.cpMax = static_cast<Sci_Position>(posAfter);
|
||||
}
|
||||
}
|
||||
execute(SCI_SETSEL, crange.cpMin, crange.cpMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
execute(SCI_BEGINUNDOACTION);
|
||||
for (size_t i = 0; i < nbSelections; ++i)
|
||||
{
|
||||
LRESULT posStart = execute(SCI_GETSELECTIONNSTART, i);
|
||||
LRESULT posEnd = execute(SCI_GETSELECTIONNEND, i);
|
||||
|
||||
|
||||
size_t l = execute(SCI_LINEFROMPOSITION, posStart);
|
||||
|
||||
int64_t posBefore = execute(SCI_GETLINEINDENTPOSITION, l);
|
||||
execute(SCI_SETLINEINDENTATION, l, indent);
|
||||
int64_t posAfter = execute(SCI_GETLINEINDENTPOSITION, l);
|
||||
|
||||
long long posDifference = posAfter - posBefore;
|
||||
if (posAfter > posBefore)
|
||||
{
|
||||
// Move selection on
|
||||
if (posStart >= posBefore)
|
||||
{
|
||||
posStart += static_cast<Sci_Position>(posDifference);
|
||||
}
|
||||
if (posEnd >= posBefore)
|
||||
{
|
||||
posEnd += static_cast<Sci_Position>(posDifference);
|
||||
}
|
||||
}
|
||||
else if (posAfter < posBefore)
|
||||
{
|
||||
// Move selection back
|
||||
if (posStart >= posAfter)
|
||||
{
|
||||
if (posStart >= posBefore)
|
||||
posStart += static_cast<Sci_Position>(posDifference);
|
||||
else
|
||||
posStart = static_cast<Sci_Position>(posAfter);
|
||||
}
|
||||
|
||||
if (posEnd >= posAfter)
|
||||
{
|
||||
if (posEnd >= posBefore)
|
||||
posEnd += static_cast<Sci_Position>(posDifference);
|
||||
else
|
||||
posEnd = static_cast<Sci_Position>(posAfter);
|
||||
}
|
||||
}
|
||||
|
||||
execute(SCI_SETSELECTIONNSTART, i, posStart);
|
||||
execute(SCI_SETSELECTIONNEND, i, posEnd);
|
||||
}
|
||||
execute(SCI_ENDUNDOACTION);
|
||||
}
|
||||
execute(SCI_SETSEL, crange.cpMin, crange.cpMax);
|
||||
}
|
||||
|
||||
void ScintillaEditView::updateLineNumberWidth()
|
||||
|
@ -3199,11 +3257,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);
|
||||
|
@ -4243,19 +4301,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;
|
||||
|
@ -4264,7 +4322,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));
|
||||
}
|
||||
|
@ -4287,9 +4345,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);
|
||||
|
@ -4451,8 +4509,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
|
||||
|
@ -4468,19 +4526,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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue