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; }
bool PreProcessor::elif_directive() { assert(tokenit.is(_PP_ELIF)); tokenit.next(); if (ifBlockEnables.empty()) { ERROR("'if' directive is not found"); return false; } bool if_is_enable = ifBlockEnables.back(); if (if_is_enable) { TokenIterator tag = tokenit; skipUntilElseOrEnd(); tag.erase(tokenit-tag); } else { AST *ast = expression(); if (!ast) { return false; } if (eval(ast)) { ifBlockEnables.pop_back(); ifBlockEnables.push_back(true); } else { TokenIterator tag = tokenit; skipUntilElseOrEnd(); tag.erase(tokenit-tag); } } return true; }
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); }
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; }
void PreProcessor::applyMacro(const String &ident, const ref<MacroDef> ¯o) { assert(tokenit.is(_IDENT)); DBG("apply macro: %s", ident.c_str()); if (macro->params.empty()) { tokenit.erase(1);//erase identifier tokenit.insert(macro->tokens); } else { TokenIterator tag = tokenit; tokenit.next(); //get caller params if (tokenit.is(_LPAREN)) { tokenit.next(); List<List<Token> > caller_params; if (!parseFunctionParams(caller_params)) { ERROR("failed to parse function macro"); return; } if (macro->params.size() != caller_params.size()) { ERROR("macro %s requres %d parameters", ident.c_str(), macro->params.size()); return; } tag.erase(tokenit-tag);//erase function call tokens //replace macro params List<Token> replace_tokens = replaceMacroParams(macro->tokens, caller_params); tokenit.insert(replace_tokens); //tokenit.next(); } } }
bool PreProcessor::else_directive() { assert(tokenit.is(_PP_ELSE)); tokenit.next(); if (!tokenit.is(_PP_END)) { //TODO: warning } tokenit.skipUntil({_PP_END}, true); tokenit.next(); if (ifBlockEnables.empty()) { ERROR("'if' directive is not found (before 'else')"); return false; } bool if_is_enable = ifBlockEnables.back(); if (if_is_enable) { TokenIterator tag = tokenit; skipUntilElseOrEnd(); tag.erase(tokenit-tag); } else { ifBlockEnables.pop_back(); ifBlockEnables.push_back(true); } return true; }
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 == ';'); }
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 ); } }
bool PreProcessor::if_directive() { assert(tokenit.is(_PP_IF)); tokenit.next(); AST *ast = expression(); if (!ast) { return false; } if (eval(ast)) { ifBlockEnables.push_back(true); } else { ifBlockEnables.push_back(false); TokenIterator tag = tokenit; skipUntilElseOrEnd(); tag.erase(tokenit-tag); } return true; }
/******************************************************************* * Function Name: readToken * Description: tokenize words ********************************************************************/ Ini::Token Ini::readToken( TokenIterator &cursor, string &word ) { if( (*cursor)[0] == '[' ) { word = lowerCase( cursor->substr(1, cursor->size() - 2) ); cursor++ ; return group_TK ; } word = lowerCase( *cursor ); cursor ++ ; if( *cursor == ":" ) { // hh:mm:ss:mmm is a special case if ( isNumber( word ) ) { bool leave = false; while ( !leave ) { if ( *cursor == ":" ) { word += *cursor ; cursor++ ; } else { leave = true; } if ( isNumber( *cursor ) ) { word += *cursor ; cursor++ ; } else { leave = true; } } return id_TK ; } else { cursor ++ ; return def_TK ; } } else return id_TK ; }
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::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); }
ParsingResult parseToken(Token token, TokenIterator& begin, TokenIterator& end, const TokenAction& action = TokenAction()) { if (begin >= end) { return make_pair(false, SemanticAction()); } if (begin->name() != token.name()) { return make_pair(false, SemanticAction()); } const Token& theToken = *begin; ++begin; if (action) { return make_pair(true, bind(action, theToken)); } return make_pair(true, SemanticAction()); }
List<Token> PreProcessor::replaceMacroParams(const List<Token> &mtokens, const List<List<Token>> &caller_params) { //FIXME: nested macro //i.e. FUNC(x, FUNC(x,y)) List<Token> replace = mtokens; TokenIterator it; it.setTokens(&replace); while (!it.eof()) { if (it.is(_PP_MACRO_PARAM)) { int index = it.val()->toInt(); const List<Token> ¶m = caller_params.at(index); it.erase(1); it.insert(param); } it.next(); } return replace; }
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(); }
// 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::keyPressEvent( QKeyEvent *e ) { hideMouseCursor(e); QTextCursor cursor( textCursor() ); bool cursorMoved = true; if (e == QKeySequence::MoveToNextWord) moveToNextToken( cursor, QTextCursor::MoveAnchor ); else if (e == QKeySequence::MoveToPreviousWord) moveToPreviousToken( cursor, QTextCursor::MoveAnchor ); else if (e == QKeySequence::SelectNextWord) moveToNextToken( cursor, QTextCursor::KeepAnchor ); else if (e == QKeySequence::SelectPreviousWord) moveToPreviousToken( cursor, QTextCursor::KeepAnchor ); else cursorMoved = false; if (cursorMoved) { setTextCursor( cursor ); return; } switch (e->key()) { case Qt::Key_Home: { Qt::KeyboardModifiers mods(e->modifiers()); if (mods && mods != Qt::ShiftModifier) { GenericCodeEditor::keyPressEvent(e); return; } QTextCursor::MoveMode mode = mods & Qt::ShiftModifier ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor; QTextCursor c(textCursor()); QTextBlock b(c.block()); int pos = indentedStartOfLine(b); pos += b.position(); if (c.position() == pos) c.movePosition(QTextCursor::StartOfLine, mode); else c.setPosition(pos, mode); setTextCursor(c); return; } case Qt::Key_Backtab: { QTextCursor cursor = textCursor(); insertSpaceToNextTabStop( cursor ); ensureCursorVisible(); return; } case Qt::Key_Backspace: if (mInsertMatchingTokens && !overwriteMode() && e->modifiers() == 0) if (removeMatchingTokens()) break; GenericCodeEditor::keyPressEvent(e); break; case Qt::Key_Enter: case Qt::Key_Return: { QTextBlock cursorBlock = cursor.block(); int cursorPosInBlock = cursor.position() - cursorBlock.position(); TokenIterator nextToken = TokenIterator::rightOf(cursorBlock, cursorPosInBlock); if ( nextToken.block() == cursorBlock && nextToken.type() == Token::ClosingBracket ) { cursor.beginEditBlock(); cursor.insertBlock(); cursor.insertBlock(); cursor.endEditBlock(); cursor.movePosition( QTextCursor::PreviousBlock, QTextCursor::KeepAnchor ); indent(cursor, JoinEditBlock); cursor.movePosition( QTextCursor::EndOfBlock ); } else { cursor.beginEditBlock(); cursor.insertBlock(); cursor.endEditBlock(); indent(cursor, JoinEditBlock); } cursor.setVerticalMovementX(-1); setTextCursor(cursor); break; } default: if (!overwriteMode() && insertMatchingTokens(e->text())) break; GenericCodeEditor::keyPressEvent(e); } mAutoCompleter->keyPress(e); }
inline static bool tokenMaybeRegionStart( const TokenIterator & it ) { Q_ASSERT(it.isValid()); return ( it->character == '(' && it->positionInBlock == 0 ); }