static bool bracketPairDefinesRegion( const BracketPair & bracketPair ) { Q_ASSERT(bracketPair.first.isValid()); Q_ASSERT(bracketPair.second.isValid()); if ( bracketPair.first->character != '(' || bracketPair.second->character != ')' ) return false; if (!tokenIsFirstAndOnlyInBlock(bracketPair.second) || !tokenIsFirstAndOnlyInBlock(bracketPair.second)) return false; // check whether this is an Event TokenIterator it = bracketPair.first.next(); if (it.isValid()) { if (it->type == Token::SymbolArg) return false; else { ++it; if (it.isValid() && it->character == ':') return false; } } return true; }
QTextCursor ScCodeEditor::selectionForPosition( int position ) { QTextBlock block( textDocument()->findBlock(position) ); if (!block.isValid()) return QTextCursor(); int positionInBlock = position - block.position(); TokenIterator it = TokenIterator( block, positionInBlock ); if (it.type() == Token::Unknown) { // Token is invalid, or Token::Unknown (i.e. punctuations). // Prefer token at previous position. TokenIterator alternativeIt = TokenIterator( block, positionInBlock - 1 ); if (alternativeIt.isValid()) it = alternativeIt; } if (it.isValid()) { switch (it->type) { case Token::OpeningBracket: case Token::ClosingBracket: { BracketPair match; matchBracket(it, match); if (match.first.isValid() && match.second.isValid()) { int start = match.first.position(); int end = match.second.position() + 1; QTextCursor selection(textDocument()); if (it == match.second) { selection.setPosition(start); selection.setPosition(end, QTextCursor::KeepAnchor); } else { selection.setPosition(end); selection.setPosition(start, QTextCursor::KeepAnchor); } return selection; } break; } default: QTextCursor selection( textDocument() ); selection.setPosition( it.position() ); selection.setPosition( selection.position() + it->length, QTextCursor::KeepAnchor ); return selection; } } return QTextCursor(); }
void ScCodeEditor::gotoPreviousRegion() { QTextCursor cursor = textCursor(); int cursorPosition = cursor.position(); BracketPair prevBracketPair; BracketPair bracketPair; TokenIterator it = TokenIterator::rightOf( textDocument()->begin(), 0 ); while(it.isValid()) { nextBracketPair(it, bracketPair); if ( !bracketPair.second.isValid() || bracketPair.second.position() >= cursorPosition - 1 ) { break; } if (bracketPairDefinesRegion(bracketPair)) { prevBracketPair = bracketPair; } it = bracketPair.second; } if ( prevBracketPair.first.isValid() && prevBracketPair.second.isValid() ) { setTextCursor( cursorAt(prevBracketPair.second, 1) ); return; } cursor.movePosition(QTextCursor::Start); setTextCursor(cursor); }
QTextCursor ScCodeEditor::regionAroundCursor(const QTextCursor & cursor) { int cursorPosition = cursor.position(); BracketPair bracketPair; TokenIterator it = TokenIterator::rightOf( textDocument()->begin(), 0 ); while (it.isValid()) { nextBracketPair(it, bracketPair); if (bracketPair.first.isValid() && bracketPair.first.position() < cursorPosition) { if ( bracketPair.second.isValid() && bracketPair.second.position() >= cursorPosition && bracketPairDefinesRegion(bracketPair) ) { QTextCursor regionCursor(QPlainTextEdit::document()); regionCursor.setPosition(bracketPair.first.position() + 1); regionCursor.setPosition(bracketPair.second.position(), QTextCursor::KeepAnchor); return regionCursor; } } else { break; } it = bracketPair.second; } return QTextCursor(); }
inline static bool tokenIsFirstAndOnlyInBlock( const TokenIterator & it ) { Q_ASSERT(it.isValid()); bool result = it->positionInBlock == 0; result = result && static_cast<TextBlockData*>(it.block().userData())->tokens.size() == 1; return result; }
QTextCursor ScCodeEditor::cursorAt(const TokenIterator it, int offset) { Q_ASSERT(it.isValid()); QTextCursor textCursor(textDocument()); textCursor.setPosition(it.position() + offset); return textCursor; }
inline static bool tokenMaybeRegionEnd( const TokenIterator & it ) { Q_ASSERT(it.isValid()); if (it->character != ')') return false; TokenIterator next_it = it.next(); return (!next_it.isValid() || next_it.block() != it.block() || next_it->character == ';'); }
static bool bracketPairDefinesRegion( const BracketPair & bracketPair ) { Q_ASSERT(bracketPair.first.isValid()); Q_ASSERT(bracketPair.second.isValid()); if (!tokenMaybeRegionStart(bracketPair.first) || !tokenMaybeRegionEnd(bracketPair.second)) return false; // check whether this is an Event TokenIterator it = bracketPair.first.next(); if (it.isValid()) { if (it->type == Token::SymbolArg) return false; else { ++it; if (it.isValid() && it->character == ':') return false; } } return true; }
void ScCodeEditor::matchBracket( const TokenIterator & bracket, BracketPair & match ) { Q_ASSERT(bracket.isValid()); switch(bracket->type) { case Token::OpeningBracket: match.first = bracket; match.second = nextClosingBracket(bracket.next()); break; case Token::ClosingBracket: match.second = bracket; match.first = previousOpeningBracket(bracket.previous()); break; default: match.first = TokenIterator(); match.second = TokenIterator(); } }
void ScCodeEditor::gotoNextBlock() { QTextCursor cursor = textCursor(); TokenIterator tokenIt = TokenIterator::rightOf( cursor.block(), cursor.positionInBlock() ); if (tokenIt.type() == Token::OpeningBracket && tokenIt.block() == cursor.block() && tokenIt->positionInBlock == cursor.positionInBlock()) ++tokenIt; tokenIt = nextClosingBracket( tokenIt ); if (tokenIt.isValid()) setTextCursor( cursorAt(tokenIt, 1) ); else { cursor.movePosition( QTextCursor::End ); setTextCursor( cursor ); } }
void ScCodeEditor::gotoPreviousBlock() { QTextCursor cursor = textCursor(); TokenIterator tokenIt = TokenIterator::leftOf(cursor.block(), cursor.positionInBlock()); if (tokenIt.type() == Token::ClosingBracket && tokenIt.block() == cursor.block() && tokenIt->positionInBlock == cursor.positionInBlock() - 1) --tokenIt; tokenIt = previousOpeningBracket( tokenIt ); if (tokenIt.isValid()) setTextCursor( cursorAt(tokenIt) ); else { cursor.movePosition( QTextCursor::Start ); setTextCursor( cursor ); } }
// taking nested brackets into account TokenIterator ScCodeEditor::previousOpeningBracket(TokenIterator it) { int level = 0; while (it.isValid()) { switch (it->type) { case Token::OpeningBracket: if (level == 0) return it; --level; break; case Token::ClosingBracket: ++level; default: break; } --it; } return it; }
void ScCodeEditor::gotoNextRegion() { QTextCursor cursor = textCursor(); int cursorPosition = cursor.position(); BracketPair bracketPair; TokenIterator it = TokenIterator::rightOf( textDocument()->begin(), 0 ); while (it.isValid()) { nextBracketPair(it, bracketPair); if ( bracketPair.first.isValid() && bracketPair.second.isValid() && bracketPair.first.position() > cursorPosition && bracketPairDefinesRegion(bracketPair)) { setTextCursor( cursorAt(bracketPair.first) ); return; } it = bracketPair.second; } cursor.movePosition(QTextCursor::End); setTextCursor(cursor); }
inline static bool tokenMaybeRegionStart( const TokenIterator & it ) { Q_ASSERT(it.isValid()); return ( it->character == '(' && it->positionInBlock == 0 ); }