diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index fd48ee32f..6b5a92f29 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -590,6 +590,10 @@ class EE_API TextDocument { void addCursorBelow(); + size_t getTopMostCursorIndex(); + + size_t getBottomMostCursorIndex(); + TextRange getTopMostCursor(); TextRange getBottomMostCursor(); diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index d5f69f031..7dd46d4d1 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -448,6 +448,10 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void moveToNextLine(); + void addCursorAbove(); + + void addCursorBelow(); + void moveToPreviousPage(); void moveToNextPage(); diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 9b1e77a4b..5d40e2938 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -4634,6 +4634,34 @@ void TextDocument::initializeCommands() { } } +size_t TextDocument::getTopMostCursorIndex() { + if ( mSelection.size() == 1 ) + return 0; + TextRange topMost( mSelection[0] ); + size_t topMostIndex = 0; + for ( size_t i = 1; i < mSelection.size(); ++i ) { + if ( mSelection[i] < topMost ) { + topMost = mSelection[i]; + topMostIndex = i; + } + } + return topMostIndex; +} + +size_t TextDocument::getBottomMostCursorIndex() { + if ( mSelection.size() == 1 ) + return 0; + TextRange bottomMost( mSelection[0] ); + size_t bottomMostIndex = 0; + for ( size_t i = 1; i < mSelection.size(); ++i ) { + if ( mSelection[i] > bottomMost ) { + bottomMost = mSelection[i]; + bottomMostIndex = i; + } + } + return bottomMostIndex; +} + TextRange TextDocument::getTopMostCursor() { if ( mSelection.size() == 1 ) return mSelection.front(); diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index ca73e9f52..57dd6af80 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -2652,7 +2652,7 @@ Float UICodeEditor::getTextWidth( const StringType& line, bool fromMonospaceLine Vector2d UICodeEditor::getTextPositionOffsetSanitized( TextPosition position, std::optional lineHeight ) const { position.setLine( eeclamp( position.line(), 0L, mDoc->linesCount() - 1 ) ); - // This is different from sanitizePosition, sinze allows the last character. + // This is different from sanitizePosition, since allows the last character. position.setColumn( eeclamp( position.column(), 0L, eemax( 0, position.line() < static_cast( mDoc->linesCount() ) @@ -3423,6 +3423,24 @@ void UICodeEditor::moveToNextPage() { jumpLinesDown( getViewPortLineCount().y ); } +void UICodeEditor::addCursorAbove() { + size_t cursorIdx = mDoc->getTopMostCursorIndex(); + TextPosition curPos = mDoc->getSelections()[cursorIdx].start(); + if ( curPos.line() == 0 ) + return; + auto newPos( moveToLineOffset( curPos, -1, cursorIdx ) ); + mDoc->addSelection( { newPos, newPos } ); +} + +void UICodeEditor::addCursorBelow() { + size_t cursorIdx = mDoc->getBottomMostCursorIndex(); + TextPosition curPos = mDoc->getSelections()[cursorIdx].start(); + if ( curPos.line() >= (Int64)mDoc->linesCount() - 1 ) + return; + auto newPos( moveToLineOffset( curPos, 1, cursorIdx ) ); + mDoc->addSelection( { newPos, newPos } ); +} + void UICodeEditor::moveToStartOfLine() { for ( size_t i = 0; i < mDoc->getSelections().size(); ++i ) { auto selection = mDoc->getSelectionIndex( i ); @@ -4545,6 +4563,12 @@ void UICodeEditor::registerCommands() { if ( !editor->mLink.empty() ) Engine::instance()->openURI( editor->mLink ); } ); + mDoc->setCommand( "add-cursor-above", []( Client* client ) { + static_cast( client )->addCursorAbove(); + } ); + mDoc->setCommand( "add-cursor-below", []( Client* client ) { + static_cast( client )->addCursorBelow(); + } ); mUnlockedCmd.insert( { "copy", "select-all", "open-containing-folder", "copy-containing-folder-path", "copy-file-path",