int FormulaEditorHighlighter::findMatchingBrace(int pos) { int depth = 0; int step = 0; Tokens tokens = d->tokens; //If this is a left brace we need to step forwards through the text to find the matching right brace, //otherwise, it is a right brace so we need to step backwards through the text to find the matching left //brace. if (tokens.at(pos).asOperator() == Token::LeftPar) step = 1; else step = -1; for (int index = pos ; (index >= 0) && (index < (int) tokens.count()) ; index += step) { if (tokens.at(index).asOperator() == Token::LeftPar) depth++; if (tokens.at(index).asOperator() == Token::RightPar) depth--; if (depth == 0) { return index; } } return -1; }
Token *TokenManager::getTokenByBase(Token *base, int offset) { Tokens *tks = this->tokens; size_t size = tks->size(); int wanted_idx = -1; for (size_t i = 0; i < size; i++) { if (tks->at(i) == base) { wanted_idx = i + offset; } } return (0 <= wanted_idx && (size_t)wanted_idx < size) ? tks->at(wanted_idx) : NULL; }
void Editor::doMatchingRight() { // Tokenize the expression. const int currentPosition = textCursor().position(); // Check for left par. QString subtext = text().right(text().length() - currentPosition); Tokens tokens = m_evaluator->scan(subtext); if (!tokens.valid() || tokens.count() < 1) return; Token firstToken = tokens.at(0); // Left par? if (firstToken.type() == Token::stxOpenPar && firstToken.pos() == 0) { // Find the matching right par. unsigned par = 1; int k = 0; Token matchToken; int matchPosition = -1; for (k = 1; k < tokens.count() && par > 0; ++k) { const Token matchToken = tokens.at(k); switch (matchToken.type()) { case Token::stxOpenPar : ++par; break; case Token::stxClosePar: --par; break; default:; } matchPosition = matchToken.pos(); } if (par == 0) { QTextEdit::ExtraSelection hilite1; hilite1.cursor = textCursor(); hilite1.cursor.setPosition(currentPosition+matchPosition); hilite1.cursor.setPosition(currentPosition+matchPosition + 1, QTextCursor::KeepAnchor); hilite1.format.setBackground(m_highlighter->colorForRole(SyntaxHighlighter::Matched)); QTextEdit::ExtraSelection hilite2; hilite2.cursor = textCursor(); hilite2.cursor.setPosition(currentPosition+firstToken.pos()); hilite2.cursor.setPosition(currentPosition+firstToken.pos() + 1, QTextCursor::KeepAnchor); hilite2.format.setBackground(m_highlighter->colorForRole(SyntaxHighlighter::Matched)); QList<QTextEdit::ExtraSelection> extras; extras << hilite1; extras << hilite2; setExtraSelections(extras); } } }
void Editor::doMatchingLeft() { // Tokenize the expression. const int currentPosition = textCursor().position(); // Check for right par. QString subtext = text().left(currentPosition); Tokens tokens = m_evaluator->scan(subtext, Evaluator::NoAutoFix); if (!tokens.valid() || tokens.count() < 1) return; Token lastToken = tokens.at(tokens.count() - 1); // Right par? if (lastToken.type() == Token::stxClosePar && lastToken.pos() == currentPosition - 1) { // Find the matching left par. unsigned par = 1; int matchPosition = -1; for (int i = tokens.count() - 2; i >= 0 && par > 0; --i) { Token matchToken = tokens.at(i); switch (matchToken.type()) { case Token::stxOpenPar : --par; break; case Token::stxClosePar: ++par; break; default:; } matchPosition = matchToken.pos(); } if (par == 0) { QTextEdit::ExtraSelection hilite1; hilite1.cursor = textCursor(); hilite1.cursor.setPosition(matchPosition); hilite1.cursor.setPosition(matchPosition + 1, QTextCursor::KeepAnchor); hilite1.format.setBackground(m_highlighter->colorForRole(SyntaxHighlighter::Matched)); QTextEdit::ExtraSelection hilite2; hilite2.cursor = textCursor(); hilite2.cursor.setPosition(lastToken.pos()); hilite2.cursor.setPosition(lastToken.pos() + 1, QTextCursor::KeepAnchor); hilite2.format.setBackground(m_highlighter->colorForRole(SyntaxHighlighter::Matched)); QList<QTextEdit::ExtraSelection> extras; extras << hilite1; extras << hilite2; setExtraSelections(extras); } } }
void SyntaxHighlighter::highlightBlock(const QString& text) { if (!Settings::instance()->syntaxHighlighting) { setFormat(0, text.length(), colorForRole(Number)); return; } if (text.startsWith(QLatin1String("="))) { setFormat(0, 1, colorForRole(Operator)); setFormat(1, text.length(), colorForRole(Result)); groupDigits(text, 1, text.length() - 1); return; } Tokens tokens = Evaluator::instance()->scan(text); for (int i = 0; i < tokens.count(); ++i) { const Token& token = tokens.at(i); const QString tokenText = token.text().toLower(); QStringList functionNames = FunctionRepo::instance()->getIdentifiers(); QColor color; switch (token.type()) { case Token::stxNumber: case Token::stxUnknown: color = colorForRole(Number); break; case Token::stxOperator: color = colorForRole(Operator); break; case Token::stxSep: color = colorForRole(Separator); break; case Token::stxOpenPar: case Token::stxClosePar: color = colorForRole(Parens); break; case Token::stxIdentifier: color = colorForRole(Variable); for (int i = 0; i < functionNames.count(); ++i) if (functionNames.at(i).toLower() == tokenText) color = colorForRole(Function); break; default: break; }; if (token.pos() >= 0) { setFormat(token.pos(), token.text().length(), color); if (token.type() == Token::stxNumber) groupDigits(text, token.pos(), token.text().length()); } } }
static const Token tokenAtPosition(const Tokens &tokens, const unsigned pos) { for (int i = tokens.size() - 1; i >= 0; --i) { const Token tk = tokens.at(i); if (pos >= tk.utf16charsBegin() && pos < tk.utf16charsEnd()) return tk; } return Token(); }
void Editor::autoComplete(const QString& item) { if (!m_isAutoCompletionEnabled || item.isEmpty()) return; const int currentPosition = textCursor().position(); const QString subtext = text().left(currentPosition); const Tokens tokens = m_evaluator->scan(subtext); if (!tokens.valid() || tokens.count() < 1) return; const Token lastToken = tokens.at(tokens.count() - 1); if (!lastToken.isIdentifier()) return; const QStringList str = item.split(':'); blockSignals(true); QTextCursor cursor = textCursor(); cursor.setPosition(lastToken.pos()); cursor.setPosition(lastToken.pos() + lastToken.text().length(), QTextCursor::KeepAnchor); setTextCursor(cursor); insert(str.at(0)); blockSignals(false); cursor = textCursor(); bool hasParensAlready; if ((hasParensAlready = cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor))) { QString nextChar = cursor.selectedText(); hasParensAlready = (nextChar == "("); } bool shouldAutoInsertParens = (FunctionRepo::instance()->find(str.at(0)) || m_evaluator->hasUserFunction(str.at(0))) && !hasParensAlready; if (shouldAutoInsertParens) { insert(QString::fromLatin1("()")); cursor = textCursor(); cursor.movePosition(QTextCursor::PreviousCharacter); setTextCursor(cursor); } }
int ClangFunctionHintModel::activeArgument(const QString &prefix) const { int argnr = 0; int parcount = 0; SimpleLexer tokenize; Tokens tokens = tokenize(prefix); for (int i = 0; i < tokens.count(); ++i) { const CPlusPlus::Token &tk = tokens.at(i); if (tk.is(T_LPAREN)) ++parcount; else if (tk.is(T_RPAREN)) --parcount; else if (! parcount && tk.is(T_COMMA)) ++argnr; } if (parcount < 0) return -1; if (argnr != m_currentArg) m_currentArg = argnr; return argnr; }
void Editor::triggerAutoComplete() { if (!m_isAutoCompletionEnabled) return; // Tokenize the expression (this is very fast). const int currentPosition = textCursor().position(); QString subtext = text().left(currentPosition); const Tokens tokens = m_evaluator->scan(subtext, Evaluator::NoAutoFix); if (!tokens.valid() || tokens.count() < 1) return; Token lastToken = tokens.at(tokens.count()-1); // Last token must be an identifier. if (!lastToken.isIdentifier()) return; const QString id = lastToken.text(); if (id.length() < 1) return; // No space after identifier. if (lastToken.pos() + id.length() < subtext.length()) return; // Find matches in function names. const QStringList fnames = FunctionRepo::instance()->getIdentifiers(); QStringList choices; for (int i = 0; i < fnames.count(); ++i) { if (fnames.at(i).startsWith(id, Qt::CaseInsensitive)) { QString str = fnames.at(i); Function* f = FunctionRepo::instance()->find(str); if (f) str.append(':').append(f->name()); choices.append(str); } } choices.sort(); // Find matches in variables names. QStringList vchoices; QList<Evaluator::Variable> variables = m_evaluator->getVariables(); for (int i = 0; i < variables.count(); ++i) if (variables.at(i).name.startsWith(id, Qt::CaseInsensitive)) vchoices.append(QString("%1:%2").arg(variables.at(i).name) .arg(NumberFormatter::format(variables.at(i).value))); vchoices.sort(); choices += vchoices; // Find matches in user functions. QStringList ufchoices; QList<Evaluator::UserFunctionDescr> userFunctions = m_evaluator->getUserFunctions(); for (int i = 0; i < userFunctions.count(); ++i) if (userFunctions.at(i).name.startsWith(id, Qt::CaseInsensitive)) ufchoices.append(QString("%1:User function").arg(userFunctions.at(i).name)); ufchoices.sort(); choices += ufchoices; // TODO: if we are assigning a user function, find matches in its arguments names and // replace variables names that collide. But we cannot know if we are assigning // a user function without evaluating the expression (a token scan will not be enough). // No match, don't bother with completion. if (!choices.count()) return; // Single perfect match, no need to give choices. if (choices.count() == 1) if (choices.at(0).toLower() == id.toLower()) return; // Present the user with completion choices. m_completion->showCompletion(choices); }