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;
}
示例#3
0
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);
        }
    }
}
示例#4
0
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);
        }
    }
}
示例#5
0
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());
        }
    }
}
示例#6
0
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();
}
示例#7
0
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;
}
示例#9
0
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);
}