Add "Multi-Select Next Occurence" feature
* Added Ctrl+Shift+D to select next occurence of selection * Left and right movement works for multiple cursors * Enter/return a new line works for multiple cursors Close #5322, close #5399
This commit is contained in:
parent
0c5a42153b
commit
455fcb2da4
@ -1570,6 +1570,103 @@ void Notepad_plus::command(int id)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IDM_EDIT_SELECTNEXTOCCURENCE:
|
||||||
|
{
|
||||||
|
// Get the selected text length of the first selection
|
||||||
|
int textLen = abs(int(_pEditView->execute(SCI_GETSELECTIONNANCHOR, 0)) - int(_pEditView->execute(SCI_GETSELECTIONNCARET, 0)));
|
||||||
|
if (!textLen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get selected text
|
||||||
|
char* selectedText = new char[textLen + 1];
|
||||||
|
_pEditView->getSelectedText(selectedText, textLen + 1);
|
||||||
|
|
||||||
|
// Get current position of the last selection
|
||||||
|
int numSelections = int(_pEditView->execute(SCI_GETSELECTIONS));
|
||||||
|
int currentPos = int(_pEditView->execute(SCI_GETSELECTIONNCARET, numSelections - 1));
|
||||||
|
int selectonEnd = max(int(_pEditView->execute(SCI_GETSELECTIONNANCHOR, numSelections - 1)), currentPos);
|
||||||
|
int docLength = int(_pEditView->execute(SCI_GETLENGTH));
|
||||||
|
|
||||||
|
// Convert char to TCHAR
|
||||||
|
WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance();
|
||||||
|
UINT cp = static_cast<UINT>(_pEditView->execute(SCI_GETCODEPAGE));
|
||||||
|
const TCHAR* textToFind = wmc->char2wchar(selectedText, cp);
|
||||||
|
|
||||||
|
// Find position of next occurence
|
||||||
|
int posFound = _pEditView->searchInTarget(textToFind, textLen, currentPos + 1, docLength);
|
||||||
|
|
||||||
|
if (posFound > currentPos)
|
||||||
|
{
|
||||||
|
int start = posFound + textLen;
|
||||||
|
int end = posFound;
|
||||||
|
|
||||||
|
// Detect if selection happened the other way
|
||||||
|
if (currentPos != selectonEnd)
|
||||||
|
{
|
||||||
|
start = posFound;
|
||||||
|
end = posFound + textLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pEditView->execute(SCI_ADDSELECTION, start, end);
|
||||||
|
|
||||||
|
// Keep the main selection the first one
|
||||||
|
_pEditView->execute(SCI_SETMAINSELECTION, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDM_EDIT_MULTICHARLEFT:
|
||||||
|
_pEditView->multiCursorLeftOrRight(-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDM_EDIT_MULTICHARLEFTEXTEND:
|
||||||
|
_pEditView->multiCursorLeftOrRight(-1, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDM_EDIT_MULTICHARRIGHT:
|
||||||
|
_pEditView->multiCursorLeftOrRight(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDM_EDIT_MULTICHARRIGHTEXTEND:
|
||||||
|
_pEditView->multiCursorLeftOrRight(1, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDM_EDIT_MULTINEWLINE:
|
||||||
|
{
|
||||||
|
// Get the number of selection
|
||||||
|
int numSelections = int(_pEditView->execute(SCI_GETSELECTIONS));
|
||||||
|
|
||||||
|
// Keep an array of the new positions
|
||||||
|
std::vector<int> selectionPositions;
|
||||||
|
|
||||||
|
// Loop through each selection
|
||||||
|
for (int i = 0; i < numSelections; ++i)
|
||||||
|
{
|
||||||
|
// Get the current caret position of the seleciton
|
||||||
|
int currentPos = int(_pEditView->execute(SCI_GETSELECTIONNCARET, i));
|
||||||
|
|
||||||
|
// Add the new position to the array
|
||||||
|
selectionPositions.push_back(currentPos + i * 2 + 2);
|
||||||
|
|
||||||
|
// New line caret adjustment
|
||||||
|
_pEditView->execute(SCI_SETSELECTIONNCARET, i, currentPos + i * 2);
|
||||||
|
_pEditView->execute(SCI_SETSELECTIONNANCHOR, i, currentPos + i * 2);
|
||||||
|
|
||||||
|
// Set the current selection to main
|
||||||
|
_pEditView->execute(SCI_SETMAINSELECTION, i);
|
||||||
|
|
||||||
|
// Execute the new line command on the selection
|
||||||
|
_pEditView->execute(SCI_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all of the cursors back where they should be
|
||||||
|
for (int i = 0; i < (static_cast<signed int>(selectionPositions.size()) - 1); ++i)
|
||||||
|
{
|
||||||
|
_pEditView->execute(SCI_ADDSELECTION, selectionPositions[i], selectionPositions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case IDM_SEARCH_CUTMARKEDLINES :
|
case IDM_SEARCH_CUTMARKEDLINES :
|
||||||
cutMarkedLines();
|
cutMarkedLines();
|
||||||
break;
|
break;
|
||||||
|
@ -141,6 +141,12 @@ static const WinMenuKeyDefinition winKeyDefs[] =
|
|||||||
{ VK_NULL, IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING, false, false, false, nullptr },
|
{ VK_NULL, IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING, false, false, false, nullptr },
|
||||||
{ VK_NULL, IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING, false, false, false, nullptr },
|
{ VK_NULL, IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING, false, false, false, nullptr },
|
||||||
{ VK_NULL, IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING, false, false, false, nullptr },
|
{ VK_NULL, IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING, false, false, false, nullptr },
|
||||||
|
{ VK_D, IDM_EDIT_SELECTNEXTOCCURENCE, true, false, true, nullptr },
|
||||||
|
{ VK_LEFT, IDM_EDIT_MULTICHARLEFT, false, false, false, nullptr },
|
||||||
|
{ VK_LEFT, IDM_EDIT_MULTICHARLEFTEXTEND, false, false, true, nullptr },
|
||||||
|
{ VK_RIGHT, IDM_EDIT_MULTICHARRIGHT, false, false, false, nullptr },
|
||||||
|
{ VK_RIGHT, IDM_EDIT_MULTICHARRIGHTEXTEND, false, false, true, nullptr },
|
||||||
|
{ VK_RETURN, IDM_EDIT_MULTINEWLINE, false, false, false, nullptr },
|
||||||
{ VK_Q, IDM_EDIT_BLOCK_COMMENT, true, false, false, nullptr },
|
{ VK_Q, IDM_EDIT_BLOCK_COMMENT, true, false, false, nullptr },
|
||||||
{ VK_K, IDM_EDIT_BLOCK_COMMENT_SET, true, false, false, nullptr },
|
{ VK_K, IDM_EDIT_BLOCK_COMMENT_SET, true, false, false, nullptr },
|
||||||
{ VK_K, IDM_EDIT_BLOCK_UNCOMMENT, true, false, true, nullptr },
|
{ VK_K, IDM_EDIT_BLOCK_UNCOMMENT, true, false, true, nullptr },
|
||||||
@ -420,7 +426,6 @@ static const ScintillaKeyDefinition scintKeyDefs[] =
|
|||||||
{TEXT(""), SCI_UNDO, false, true, false, VK_BACK, 0},
|
{TEXT(""), SCI_UNDO, false, true, false, VK_BACK, 0},
|
||||||
{TEXT("SCI_REDO"), SCI_REDO, true, false, false, VK_Y, IDM_EDIT_REDO},
|
{TEXT("SCI_REDO"), SCI_REDO, true, false, false, VK_Y, IDM_EDIT_REDO},
|
||||||
{TEXT(""), SCI_REDO, true, false, true, VK_Z, 0},
|
{TEXT(""), SCI_REDO, true, false, true, VK_Z, 0},
|
||||||
{TEXT("SCI_NEWLINE"), SCI_NEWLINE, false, false, false, VK_RETURN, 0},
|
|
||||||
{TEXT(""), SCI_NEWLINE, false, false, true, VK_RETURN, 0},
|
{TEXT(""), SCI_NEWLINE, false, false, true, VK_RETURN, 0},
|
||||||
{TEXT("SCI_TAB"), SCI_TAB, false, false, false, VK_TAB, IDM_EDIT_INS_TAB},
|
{TEXT("SCI_TAB"), SCI_TAB, false, false, false, VK_TAB, IDM_EDIT_INS_TAB},
|
||||||
{TEXT("SCI_BACKTAB"), SCI_BACKTAB, false, false, true, VK_TAB, IDM_EDIT_RMV_TAB},
|
{TEXT("SCI_BACKTAB"), SCI_BACKTAB, false, false, true, VK_TAB, IDM_EDIT_RMV_TAB},
|
||||||
@ -445,11 +450,7 @@ static const ScintillaKeyDefinition scintKeyDefs[] =
|
|||||||
{TEXT("SCI_PARADOWNEXTEND"), SCI_PARADOWNEXTEND, true, false, true, VK_OEM_6, 0},
|
{TEXT("SCI_PARADOWNEXTEND"), SCI_PARADOWNEXTEND, true, false, true, VK_OEM_6, 0},
|
||||||
{TEXT("SCI_PARAUP"), SCI_PARAUP, true, false, false, VK_OEM_4, 0},
|
{TEXT("SCI_PARAUP"), SCI_PARAUP, true, false, false, VK_OEM_4, 0},
|
||||||
{TEXT("SCI_PARAUPEXTEND"), SCI_PARAUPEXTEND, true, false, true, VK_OEM_4, 0},
|
{TEXT("SCI_PARAUPEXTEND"), SCI_PARAUPEXTEND, true, false, true, VK_OEM_4, 0},
|
||||||
{TEXT("SCI_CHARLEFT"), SCI_CHARLEFT, false, false, false, VK_LEFT, 0},
|
|
||||||
{TEXT("SCI_CHARLEFTEXTEND"), SCI_CHARLEFTEXTEND, false, false, true, VK_LEFT, 0},
|
|
||||||
{TEXT("SCI_CHARLEFTRECTEXTEND"), SCI_CHARLEFTRECTEXTEND, false, true, true, VK_LEFT, 0},
|
{TEXT("SCI_CHARLEFTRECTEXTEND"), SCI_CHARLEFTRECTEXTEND, false, true, true, VK_LEFT, 0},
|
||||||
{TEXT("SCI_CHARRIGHT"), SCI_CHARRIGHT, false, false, false, VK_RIGHT, 0},
|
|
||||||
{TEXT("SCI_CHARRIGHTEXTEND"), SCI_CHARRIGHTEXTEND, false, false, true, VK_RIGHT, 0},
|
|
||||||
{TEXT("SCI_CHARRIGHTRECTEXTEND"), SCI_CHARRIGHTRECTEXTEND, false, true, true, VK_RIGHT, 0},
|
{TEXT("SCI_CHARRIGHTRECTEXTEND"), SCI_CHARRIGHTRECTEXTEND, false, true, true, VK_RIGHT, 0},
|
||||||
{TEXT("SCI_WORDLEFT"), SCI_WORDLEFT, true, false, false, VK_LEFT, 0},
|
{TEXT("SCI_WORDLEFT"), SCI_WORDLEFT, true, false, false, VK_LEFT, 0},
|
||||||
{TEXT("SCI_WORDLEFTEXTEND"), SCI_WORDLEFTEXTEND, true, false, true, VK_LEFT, 0},
|
{TEXT("SCI_WORDLEFTEXTEND"), SCI_WORDLEFTEXTEND, true, false, true, VK_LEFT, 0},
|
||||||
|
@ -2589,6 +2589,108 @@ void ScintillaEditView::currentLinesDown() const
|
|||||||
execute(SCI_SCROLLRANGE, execute(SCI_GETSELECTIONEND), execute(SCI_GETSELECTIONSTART));
|
execute(SCI_SCROLLRANGE, execute(SCI_GETSELECTIONEND), execute(SCI_GETSELECTIONSTART));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScintillaEditView::multiCursorLeftOrRight(int direction, bool shouldExt) const
|
||||||
|
{
|
||||||
|
const int NUM_SELECTIONS_FOR_DEFAULT = 1;
|
||||||
|
|
||||||
|
// Get the number of selection
|
||||||
|
int numSelections = int(execute(SCI_GETSELECTIONS));
|
||||||
|
|
||||||
|
// Use default functions when there is one selection
|
||||||
|
if (numSelections == NUM_SELECTIONS_FOR_DEFAULT)
|
||||||
|
{
|
||||||
|
if (direction < 0 && !shouldExt)
|
||||||
|
{
|
||||||
|
execute(SCI_CHARLEFT);
|
||||||
|
}
|
||||||
|
else if (direction < 0 && shouldExt)
|
||||||
|
{
|
||||||
|
execute(SCI_CHARLEFTEXTEND);
|
||||||
|
}
|
||||||
|
else if (direction > 0 && !shouldExt)
|
||||||
|
{
|
||||||
|
execute(SCI_CHARRIGHT);
|
||||||
|
}
|
||||||
|
else if (direction > 0 && shouldExt)
|
||||||
|
{
|
||||||
|
execute(SCI_CHARRIGHTEXTEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the caret blinking so it stays on
|
||||||
|
execute(SCI_SETCARETPERIOD, 0);
|
||||||
|
|
||||||
|
// Loop through each selection
|
||||||
|
for (int i = 0; i < numSelections; ++i)
|
||||||
|
{
|
||||||
|
// Get the current caret position of the seleciton
|
||||||
|
int currentPos = int(execute(SCI_GETSELECTIONNCARET, i));
|
||||||
|
int docEnd = getCurrentDocLen();
|
||||||
|
|
||||||
|
int newPos = currentPos + direction;
|
||||||
|
|
||||||
|
// Cursor is at end, use virtual space
|
||||||
|
if ((currentPos >= docEnd && direction > 0))
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add virtual space
|
||||||
|
execute(SCI_SETSELECTIONNCARETVIRTUALSPACE, i, execute(SCI_GETSELECTIONNCARETVIRTUALSPACE, i) + 1);
|
||||||
|
|
||||||
|
if (!shouldExt)
|
||||||
|
{
|
||||||
|
execute(SCI_SETSELECTIONNANCHORVIRTUALSPACE, i, execute(SCI_GETSELECTIONNANCHORVIRTUALSPACE, i) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (currentPos > docEnd)
|
||||||
|
{
|
||||||
|
// Moving back, remove virtual space
|
||||||
|
execute(SCI_SETSELECTIONNCARETVIRTUALSPACE, i, execute(SCI_GETSELECTIONNCARETVIRTUALSPACE, i) - 1);
|
||||||
|
|
||||||
|
if (!shouldExt)
|
||||||
|
{
|
||||||
|
execute(SCI_SETSELECTIONNANCHORVIRTUALSPACE, i, execute(SCI_GETSELECTIONNANCHORVIRTUALSPACE, i) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (currentPos <= 0 && direction < 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the starting and ending position of the line
|
||||||
|
int lineStart = int(execute(SCI_POSITIONFROMLINE, int(execute(SCI_LINEFROMPOSITION, currentPos))));
|
||||||
|
int lineEnd = int(execute(SCI_POSITIONFROMLINE, int(execute(SCI_LINEFROMPOSITION, currentPos)) + 1)) - 1;
|
||||||
|
|
||||||
|
// Go back or forward another position because of new line
|
||||||
|
if (newPos < lineStart && direction < 0)
|
||||||
|
{
|
||||||
|
newPos--;
|
||||||
|
}
|
||||||
|
else if (newPos >= lineEnd && lineEnd + 1 != docEnd && direction > 0)
|
||||||
|
{
|
||||||
|
newPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current caret position to the new position
|
||||||
|
execute(SCI_SETSELECTIONNCARET, i, newPos);
|
||||||
|
|
||||||
|
if (!shouldExt)
|
||||||
|
{
|
||||||
|
execute(SCI_SETSELECTIONNANCHOR, i, newPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NppGUI& nppGUI = _pParameter->getNppGUI();
|
||||||
|
|
||||||
|
// Reset the caret period so it start blinking again
|
||||||
|
execute(SCI_SETCARETPERIOD, nppGUI._caretBlinkRate);
|
||||||
|
}
|
||||||
|
|
||||||
void ScintillaEditView::changeCase(__inout wchar_t * const strWToConvert, const int & nbChars, const TextCase & caseToConvert) const
|
void ScintillaEditView::changeCase(__inout wchar_t * const strWToConvert, const int & nbChars, const TextCase & caseToConvert) const
|
||||||
{
|
{
|
||||||
if (strWToConvert == nullptr || nbChars == NULL)
|
if (strWToConvert == nullptr || nbChars == NULL)
|
||||||
|
@ -538,6 +538,7 @@ public:
|
|||||||
std::pair<int, int> getSelectionLinesRange() const;
|
std::pair<int, int> getSelectionLinesRange() const;
|
||||||
void currentLinesUp() const;
|
void currentLinesUp() const;
|
||||||
void currentLinesDown() const;
|
void currentLinesDown() const;
|
||||||
|
void multiCursorLeftOrRight(int direction, bool shouldExt = false) const;
|
||||||
|
|
||||||
void changeCase(__inout wchar_t * const strWToConvert, const int & nbChars, const TextCase & caseToConvert) const;
|
void changeCase(__inout wchar_t * const strWToConvert, const int & nbChars, const TextCase & caseToConvert) const;
|
||||||
void convertSelectedTextTo(const TextCase & caseToConvert);
|
void convertSelectedTextTo(const TextCase & caseToConvert);
|
||||||
|
@ -130,6 +130,12 @@
|
|||||||
#define IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING (IDM_EDIT + 64)
|
#define IDM_EDIT_SORTLINES_DECIMALCOMMA_DESCENDING (IDM_EDIT + 64)
|
||||||
#define IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING (IDM_EDIT + 65)
|
#define IDM_EDIT_SORTLINES_DECIMALDOT_ASCENDING (IDM_EDIT + 65)
|
||||||
#define IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING (IDM_EDIT + 66)
|
#define IDM_EDIT_SORTLINES_DECIMALDOT_DESCENDING (IDM_EDIT + 66)
|
||||||
|
#define IDM_EDIT_SELECTNEXTOCCURENCE (IDM_EDIT + 78)
|
||||||
|
#define IDM_EDIT_MULTICHARLEFT (IDM_EDIT + 79)
|
||||||
|
#define IDM_EDIT_MULTICHARLEFTEXTEND (IDM_EDIT + 80)
|
||||||
|
#define IDM_EDIT_MULTICHARRIGHT (IDM_EDIT + 81)
|
||||||
|
#define IDM_EDIT_MULTICHARRIGHTEXTEND (IDM_EDIT + 82)
|
||||||
|
#define IDM_EDIT_MULTINEWLINE (IDM_EDIT + 83)
|
||||||
|
|
||||||
#define IDM_EDIT_OPENASFILE (IDM_EDIT + 73)
|
#define IDM_EDIT_OPENASFILE (IDM_EDIT + 73)
|
||||||
#define IDM_EDIT_OPENINFOLDER (IDM_EDIT + 74)
|
#define IDM_EDIT_OPENINFOLDER (IDM_EDIT + 74)
|
||||||
|
Loading…
Reference in New Issue
Block a user