QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) { enum { MAX_BLOCK_COUNT = 5 }; QTextBlock block = cursor.block(); QTextBlock initialBlock = block; for (int i = 0; i < MAX_BLOCK_COUNT; ++i) { if (! initialBlock.previous().isValid()) break; initialBlock = initialBlock.previous(); } QString text; QTextBlock it = initialBlock; for (; it.isValid(); it = it.next()) { QString textBlock = it.text(); if (it == block) textBlock = textBlock.left(cursor.position() - cursor.block().position()); text += textBlock; if (it == block) break; text += QLatin1Char('\n'); } SimpleLexer tokenize; tokenize.setSkipComments(true); QList<SimpleToken> tokens = tokenize(text, previousBlockState(initialBlock)); tokens.prepend(SimpleToken()); // sentinel _jumpedComma = false; const int i = startOfExpression(tokens, tokens.size()); if (i == tokens.size()) return QString(); return text.mid(tokens.at(i).position(), tokens.last().position() + tokens.last().length() - tokens.at(i).position()); }
SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor, QTextBlock *b) { SimpleLexer tokenize; tokenize.setObjCEnabled(true); tokenize.setSkipComments(false); QTextBlock block = cursor.block(); int column = cursor.position() - cursor.block().position(); _text = block.text(); _tokens = tokenize(_text, BackwardsScanner::previousBlockState(block)); for (int index = _tokens.size() - 1; index != -1; --index) { const SimpleToken &tk = _tokens.at(index); if (tk.position() < column) { if (b) *b = block; return tk; } } return SimpleToken(); }
void CppCompletionAssistProcessor::startOfOperator(QTextDocument *textDocument, int positionInDocument, unsigned *kind, int &start, const CPlusPlus::LanguageFeatures &languageFeatures, bool adjustForQt5SignalSlotCompletion, DotAtIncludeCompletionHandler dotAtIncludeCompletionHandler) { if (start != positionInDocument) { QTextCursor tc(textDocument); tc.setPosition(positionInDocument); // Include completion: make sure the quote character is the first one on the line if (*kind == T_STRING_LITERAL) { QTextCursor s = tc; s.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); QString sel = s.selectedText(); if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) { *kind = T_EOF_SYMBOL; start = positionInDocument; } } if (*kind == T_COMMA) { ExpressionUnderCursor expressionUnderCursor(languageFeatures); if (expressionUnderCursor.startOfFunctionCall(tc) == -1) { *kind = T_EOF_SYMBOL; start = positionInDocument; } } SimpleLexer tokenize; tokenize.setLanguageFeatures(languageFeatures); tokenize.setSkipComments(false); const Tokens &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block())); const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); // get the token at the left of the cursor const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); const QChar characterBeforePositionInDocument = textDocument->characterAt(positionInDocument - 1); if (adjustForQt5SignalSlotCompletion && *kind == T_AMPER && tokenIdx > 0) { const Token &previousToken = tokens.at(tokenIdx - 1); if (previousToken.kind() == T_COMMA) start = positionInDocument - (tk.utf16charOffset - previousToken.utf16charOffset) - 1; } else if (*kind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) { *kind = T_EOF_SYMBOL; start = positionInDocument; // Do not complete in comments, except in doxygen comments for doxygen commands. // Do not complete in strings, except it is for include completion. } else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) || ((tk.is(T_CPP_DOXY_COMMENT) || tk.is(T_DOXY_COMMENT)) && !isDoxygenTagCompletionCharacter(characterBeforePositionInDocument)) || (tk.isLiteral() && (*kind != T_STRING_LITERAL && *kind != T_ANGLE_STRING_LITERAL && *kind != T_SLASH && *kind != T_DOT))) { *kind = T_EOF_SYMBOL; start = positionInDocument; // Include completion: can be triggered by slash, but only in a string } else if (*kind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) { *kind = T_EOF_SYMBOL; start = positionInDocument; } else if (*kind == T_LPAREN) { if (tokenIdx > 0) { const Token &previousToken = tokens.at(tokenIdx - 1); // look at the token at the left of T_LPAREN switch (previousToken.kind()) { case T_IDENTIFIER: case T_GREATER: case T_SIGNAL: case T_SLOT: break; // good default: // that's a bad token :) *kind = T_EOF_SYMBOL; start = positionInDocument; } } } // Check for include preprocessor directive else if (*kind == T_STRING_LITERAL || *kind == T_ANGLE_STRING_LITERAL || *kind == T_SLASH || (*kind == T_DOT && (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL)))) { bool include = false; if (tokens.size() >= 3) { if (tokens.at(0).is(T_POUND) && tokens.at(1).is(T_IDENTIFIER) && (tokens.at(2).is(T_STRING_LITERAL) || tokens.at(2).is(T_ANGLE_STRING_LITERAL))) { const Token &directiveToken = tokens.at(1); QString directive = tc.block().text().mid(directiveToken.utf16charsBegin(), directiveToken.utf16chars()); if (directive == QLatin1String("include") || directive == QLatin1String("include_next") || directive == QLatin1String("import")) { include = true; } } } if (!include) { *kind = T_EOF_SYMBOL; start = positionInDocument; } else if (*kind == T_DOT && dotAtIncludeCompletionHandler){ dotAtIncludeCompletionHandler(start, kind); } } } }