diff --git a/include/eepp/ui/doc/documentview.hpp b/include/eepp/ui/doc/documentview.hpp index 2e441fe55..af134543f 100644 --- a/include/eepp/ui/doc/documentview.hpp +++ b/include/eepp/ui/doc/documentview.hpp @@ -73,7 +73,7 @@ class EE_API DocumentView { LineWrapMode mode, bool keepIndentation, Uint32 tabWidth = 4 ); - static Float computeOffsets( const String& string, const FontStyleConfig& fontStyle, + static Float computeOffsets( const String::View& string, const FontStyleConfig& fontStyle, Uint32 tabWidth ); DocumentView( std::shared_ptr doc, FontStyleConfig fontStyle, Config config ); @@ -134,9 +134,9 @@ class EE_API DocumentView { FontStyleConfig mFontStyle; Config mConfig; Float mMaxWidth{ 0 }; - std::vector mWrappedLines; - std::vector mWrappedLinesOffset; - std::vector mWrappedLineToIndex; + std::vector mVisibleLines; + std::vector mVisibleLinesOffset; + std::vector mDocLineToVisibleIndex; bool mPendingReconstruction{ false }; bool mUnderConstruction{ false }; }; diff --git a/src/eepp/ui/doc/documentview.cpp b/src/eepp/ui/doc/documentview.cpp index b8baeb9d3..a2856a6c3 100644 --- a/src/eepp/ui/doc/documentview.cpp +++ b/src/eepp/ui/doc/documentview.cpp @@ -43,12 +43,13 @@ std::string DocumentView::fromLineWrapType( LineWrapType type ) { } } -Float DocumentView::computeOffsets( const String& string, const FontStyleConfig& fontStyle, +Float DocumentView::computeOffsets( const String::View& string, const FontStyleConfig& fontStyle, Uint32 tabWidth ) { - auto nonIndentPos = string.find_first_not_of( " \t\n\v\f\r" ); - if ( nonIndentPos != String::InvalidPos ) - return Text::getTextWidth( string.view().substr( 0, nonIndentPos ), fontStyle, tabWidth ); + static const String sepSpaces = " \t\n\v\f\r"; + auto nonIndentPos = string.find_first_not_of( sepSpaces.data() ); + if ( nonIndentPos != String::View::npos ) + return Text::getTextWidth( string.substr( 0, nonIndentPos ), fontStyle, tabWidth ); return 0.f; } @@ -62,13 +63,8 @@ DocumentView::LineWrapInfo DocumentView::computeLineBreaks( const String::View& if ( string.empty() || nullptr == fontStyle.Font || mode == LineWrapMode::NoWrap ) return info; - if ( keepIndentation ) { - static const String nofOf = " \t\n\v\f\r"; - auto nonIndentPos = string.find_first_not_of( nofOf.data() ); - if ( nonIndentPos != String::InvalidPos ) - info.paddingStart = - Text::getTextWidth( string.substr( 0, nonIndentPos ), fontStyle, tabWidth ); - } + if ( keepIndentation ) + info.paddingStart = computeOffsets( string, fontStyle, tabWidth ); Float xoffset = 0.f; Float lastWidth = 0.f; @@ -177,17 +173,17 @@ void DocumentView::setLineWrapMode( LineWrapMode mode ) { } TextPosition DocumentView::getVisibleIndexPosition( VisibleIndex visibleIndex ) const { - if ( mConfig.mode == LineWrapMode::NoWrap || mWrappedLines.empty() ) + if ( mConfig.mode == LineWrapMode::NoWrap || mVisibleLines.empty() ) return { static_cast( visibleIndex ), 0 }; - return mWrappedLines[eeclamp( static_cast( visibleIndex ), 0ll, - eemax( static_cast( mWrappedLines.size() ) - 1, 0ll ) )]; + return mVisibleLines[eeclamp( static_cast( visibleIndex ), 0ll, + eemax( static_cast( mVisibleLines.size() ) - 1, 0ll ) )]; } Float DocumentView::getLinePadding( Int64 docIdx ) const { - if ( mConfig.mode == LineWrapMode::NoWrap || mWrappedLinesOffset.empty() ) + if ( mConfig.mode == LineWrapMode::NoWrap || mVisibleLinesOffset.empty() ) return 0; - return mWrappedLinesOffset[eeclamp( - docIdx, 0ll, eemax( static_cast( mWrappedLinesOffset.size() ) - 1, 0ll ) )]; + return mVisibleLinesOffset[eeclamp( + docIdx, 0ll, eemax( static_cast( mVisibleLinesOffset.size() ) - 1, 0ll ) )]; } void DocumentView::setConfig( Config config ) { @@ -208,32 +204,32 @@ void DocumentView::invalidateCache() { BoolScopedOp op( mUnderConstruction, true ); - mWrappedLines.clear(); - mWrappedLineToIndex.clear(); - mWrappedLinesOffset.clear(); + mVisibleLines.clear(); + mDocLineToVisibleIndex.clear(); + mVisibleLinesOffset.clear(); if ( mConfig.mode == LineWrapMode::NoWrap ) return; Int64 linesCount = mDoc->linesCount(); - mWrappedLines.reserve( linesCount ); - mWrappedLinesOffset.reserve( linesCount ); + mVisibleLines.reserve( linesCount ); + mVisibleLinesOffset.reserve( linesCount ); for ( auto i = 0; i < linesCount; i++ ) { auto lb = computeLineBreaks( *mDoc, i, mFontStyle, mMaxWidth, mConfig.mode, mConfig.keepIndentation, mConfig.tabWidth ); - mWrappedLinesOffset.emplace_back( lb.paddingStart ); + mVisibleLinesOffset.emplace_back( lb.paddingStart ); for ( const auto& col : lb.wraps ) - mWrappedLines.emplace_back( i, col ); + mVisibleLines.emplace_back( i, col ); } std::optional lastWrap; size_t i = 0; - mWrappedLineToIndex.reserve( linesCount ); + mDocLineToVisibleIndex.reserve( linesCount ); - for ( const auto& wl : mWrappedLines ) { + for ( const auto& wl : mVisibleLines ) { if ( !lastWrap || *lastWrap != wl.line() ) { - mWrappedLineToIndex.emplace_back( i ); + mDocLineToVisibleIndex.emplace_back( i ); lastWrap = wl.line(); } i++; @@ -244,15 +240,15 @@ void DocumentView::invalidateCache() { VisibleIndex DocumentView::toVisibleIndex( Int64 docIdx, bool retLast ) const { eeASSERT( isLineVisible( docIdx ) ); - if ( mConfig.mode == LineWrapMode::NoWrap || mWrappedLineToIndex.empty() ) + if ( mConfig.mode == LineWrapMode::NoWrap || mDocLineToVisibleIndex.empty() ) return static_cast( docIdx ); - auto idx = mWrappedLineToIndex[eeclamp( docIdx, 0ll, - static_cast( mWrappedLineToIndex.size() - 1 ) )]; + auto idx = mDocLineToVisibleIndex[eeclamp( + docIdx, 0ll, static_cast( mDocLineToVisibleIndex.size() - 1 ) )]; if ( retLast ) { - Int64 lastOfLine = mWrappedLines[idx].line(); - Int64 wrappedCount = mWrappedLines.size(); - for ( auto i = idx + 1; i < wrappedCount; i++ ) { - if ( mWrappedLines[i].line() == lastOfLine ) + Int64 lastOfLine = mVisibleLines[idx].line(); + Int64 visibleLinesCount = mVisibleLines.size(); + for ( auto i = idx + 1; i < visibleLinesCount; i++ ) { + if ( mVisibleLines[i].line() == lastOfLine ) idx = i; else break; @@ -263,9 +259,9 @@ VisibleIndex DocumentView::toVisibleIndex( Int64 docIdx, bool retLast ) const { bool DocumentView::isWrappedLine( Int64 docIdx ) const { if ( isWrapEnabled() && mConfig.mode != LineWrapMode::NoWrap ) { - Int64 wrappedIndex = static_cast( toVisibleIndex( docIdx ) ); - return wrappedIndex + 1 < static_cast( mWrappedLines.size() ) && - mWrappedLines[wrappedIndex].line() == mWrappedLines[wrappedIndex + 1].line(); + Int64 visibleIndex = static_cast( toVisibleIndex( docIdx ) ); + return visibleIndex + 1 < static_cast( mVisibleLines.size() ) && + mVisibleLines[visibleIndex].line() == mVisibleLines[visibleIndex + 1].line(); } return false; } @@ -282,9 +278,9 @@ DocumentView::VisibleLineInfo DocumentView::getVisibleLineInfo( Int64 docIdx ) c Int64 toIdx = static_cast( toVisibleIndex( docIdx, true ) ); line.visualLines.reserve( toIdx - fromIdx + 1 ); for ( Int64 i = fromIdx; i <= toIdx; i++ ) - line.visualLines.emplace_back( mWrappedLines[i] ); + line.visualLines.emplace_back( mVisibleLines[i] ); line.visibleIndex = static_cast( fromIdx ); - line.paddingStart = mWrappedLinesOffset[docIdx]; + line.paddingStart = mVisibleLinesOffset[docIdx]; return line; } @@ -300,9 +296,9 @@ DocumentView::VisibleLineRange DocumentView::getVisibleLineRange( const TextPosi Int64 toIdx = static_cast( toVisibleIndex( pos.line(), true ) ); DocumentView::VisibleLineRange info; for ( Int64 i = fromIdx; i < toIdx; i++ ) { - Int64 fromCol = mWrappedLines[i].column(); + Int64 fromCol = mVisibleLines[i].column(); Int64 toCol = i + 1 <= toIdx - ? mWrappedLines[i + 1].column() - ( allowVisualLineEnd ? 0 : 1 ) + ? mVisibleLines[i + 1].column() - ( allowVisualLineEnd ? 0 : 1 ) : mDoc->line( pos.line() ).size(); if ( pos.column() >= fromCol && pos.column() <= toCol ) { info.visibleIndex = static_cast( i ); @@ -312,7 +308,7 @@ DocumentView::VisibleLineRange DocumentView::getVisibleLineRange( const TextPosi } eeASSERT( toIdx >= 0 ); info.visibleIndex = static_cast( toIdx ); - info.range = { { pos.line(), mWrappedLines[toIdx].column() }, + info.range = { { pos.line(), mVisibleLines[toIdx].column() }, mDoc->endOfLine( { pos.line(), 0ll } ) }; return info; } @@ -323,9 +319,9 @@ TextRange DocumentView::getVisibleIndexRange( VisibleIndex visibleIndex ) const Int64 idx = static_cast( visibleIndex ); auto start = getVisibleIndexPosition( visibleIndex ); auto end = start; - if ( idx + 1 < static_cast( mWrappedLines.size() ) && - mWrappedLines[idx + 1].line() == start.line() ) { - end.setColumn( mWrappedLines[idx + 1].column() ); + if ( idx + 1 < static_cast( mVisibleLines.size() ) && + mVisibleLines[idx + 1].line() == start.line() ) { + end.setColumn( mVisibleLines[idx + 1].column() ); } else { end.setColumn( mDoc->line( start.line() ).size() ); } @@ -352,9 +348,9 @@ void DocumentView::setPendingReconstruction( bool pendingReconstruction ) { } void DocumentView::clear() { - mWrappedLines.clear(); - mWrappedLineToIndex.clear(); - mWrappedLinesOffset.clear(); + mVisibleLines.clear(); + mDocLineToVisibleIndex.clear(); + mVisibleLinesOffset.clear(); } Float DocumentView::getLineYOffset( VisibleIndex visibleIndex, Float lineHeight ) const { @@ -372,22 +368,22 @@ bool DocumentView::isLineVisible( Int64 ) const { void DocumentView::updateCache( Int64 fromLine, Int64 toLine, Int64 numLines ) { if ( mConfig.mode == LineWrapMode::NoWrap ) return; - // Get affected wrapped range + // Get affected visible range Int64 oldIdxFrom = static_cast( toVisibleIndex( fromLine, false ) ); Int64 oldIdxTo = static_cast( toVisibleIndex( toLine, true ) ); - // Remove old wrapped lines - mWrappedLines.erase( mWrappedLines.begin() + oldIdxFrom, mWrappedLines.begin() + oldIdxTo + 1 ); + // Remove old visible lines + mVisibleLines.erase( mVisibleLines.begin() + oldIdxFrom, mVisibleLines.begin() + oldIdxTo + 1 ); // Remove old offsets - mWrappedLinesOffset.erase( mWrappedLinesOffset.begin() + fromLine, - mWrappedLinesOffset.begin() + toLine + 1 ); + mVisibleLinesOffset.erase( mVisibleLinesOffset.begin() + fromLine, + mVisibleLinesOffset.begin() + toLine + 1 ); // Shift the line numbers if ( numLines != 0 ) { - Int64 wrappedLines = mWrappedLines.size(); - for ( Int64 i = oldIdxFrom; i < wrappedLines; i++ ) - mWrappedLines[i].setLine( mWrappedLines[i].line() + numLines ); + Int64 visibleLinesCount = mVisibleLines.size(); + for ( Int64 i = oldIdxFrom; i < visibleLinesCount; i++ ) + mVisibleLines[i].setLine( mVisibleLines[i].line() + numLines ); } // Recompute line breaks @@ -396,51 +392,40 @@ void DocumentView::updateCache( Int64 fromLine, Int64 toLine, Int64 numLines ) { for ( auto i = fromLine; i <= netLines; i++ ) { auto lb = computeLineBreaks( *mDoc, i, mFontStyle, mMaxWidth, mConfig.mode, mConfig.keepIndentation, mConfig.tabWidth ); - mWrappedLinesOffset.insert( mWrappedLinesOffset.begin() + i, lb.paddingStart ); + mVisibleLinesOffset.insert( mVisibleLinesOffset.begin() + i, lb.paddingStart ); for ( const auto& col : lb.wraps ) { - mWrappedLines.insert( mWrappedLines.begin() + idxOffset, { i, col } ); + mVisibleLines.insert( mVisibleLines.begin() + idxOffset, { i, col } ); idxOffset++; } } - // Recompute wrapped line to index + // Recompute document line to visible index Int64 line = fromLine; - Int64 wrappedLinesCount = mWrappedLines.size(); - mWrappedLineToIndex.resize( mDoc->linesCount() ); - for ( Int64 wrappedIdx = oldIdxFrom; wrappedIdx < wrappedLinesCount; wrappedIdx++ ) { - if ( mWrappedLines[wrappedIdx].column() == 0 ) { - mWrappedLineToIndex[line] = wrappedIdx; + Int64 visibleLinesCount = mVisibleLines.size(); + mDocLineToVisibleIndex.resize( mDoc->linesCount() ); + for ( Int64 visibleIdx = oldIdxFrom; visibleIdx < visibleLinesCount; visibleIdx++ ) { + if ( mVisibleLines[visibleIdx].column() == 0 ) { + mDocLineToVisibleIndex[line] = visibleIdx; line++; } } - mWrappedLineToIndex.resize( mDoc->linesCount() ); + mDocLineToVisibleIndex.resize( mDoc->linesCount() ); #ifdef EE_DEBUG - if ( mConfig.keepIndentation ) { - auto wrappedOffset = mWrappedLinesOffset; - - for ( auto i = fromLine; i <= toLine; i++ ) { - mWrappedLinesOffset[i] = - computeOffsets( mDoc->line( i ).getText(), mFontStyle, mConfig.tabWidth ); - } - - eeASSERT( wrappedOffset == mWrappedLinesOffset ); - } - - auto wrappedLines = mWrappedLines; - auto wrappedLinesToIndex = mWrappedLineToIndex; - auto wrappedOffset = mWrappedLinesOffset; + auto visibleLines = mVisibleLines; + auto docLineToVisibleIndex = mDocLineToVisibleIndex; + auto visibleLinesOffset = mVisibleLinesOffset; invalidateCache(); - eeASSERT( wrappedLines == mWrappedLines ); - eeASSERT( wrappedLinesToIndex == mWrappedLineToIndex ); - eeASSERT( wrappedOffset == mWrappedLinesOffset ); + eeASSERT( visibleLines == mVisibleLines ); + eeASSERT( docLineToVisibleIndex == mDocLineToVisibleIndex ); + eeASSERT( visibleLinesOffset == mVisibleLinesOffset ); #endif } size_t DocumentView::getVisibleLinesCount() const { - return mConfig.mode == LineWrapMode::NoWrap ? mDoc->linesCount() : mWrappedLines.size(); + return mConfig.mode == LineWrapMode::NoWrap ? mDoc->linesCount() : mVisibleLines.size(); } }}} // namespace EE::UI::Doc diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 22bfe92d1..3ecf0c58b 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -1740,7 +1740,7 @@ Float UICodeEditor::getLineWidth( const Int64& docLine ) { } void UICodeEditor::updateScrollBar() { - int notVisibleLineCount = (int)mDoc->linesCount() - (int)getViewPortLineCount().y; + Int64 notVisibleLineCount = (Int64)getTotalVisibleLines() - (Int64)getViewPortLineCount().y; mHScrollBar->setEnabled( false ); mHScrollBar->setVisible( false );