void Editor::autoComplete( const QString& item ) { if( !d->autoCompleteEnabled || item.isEmpty() ) return; int para = 0, curPos = 0; getCursorPosition( ¶, &curPos ); QString subtext = text().left( curPos ); Tokens tokens = Evaluator::scan( subtext ); if( !tokens.valid() || tokens.count() < 1 ) return; Token lastToken = tokens[ tokens.count()-1 ]; if( !lastToken.isIdentifier() ) return; QStringList str = QStringList::split( ':', item ); blockSignals( true ); setSelection( 0, lastToken.pos(), 0, lastToken.pos()+lastToken.text().length() ); insert( str[0] ); blockSignals( false ); }
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::doMatchingRight() { if( !d->syntaxHighlightEnabled ) return; // tokenize the expression int para = 0, curPos = 0; getCursorPosition( ¶, &curPos ); // check for left par QString subtext = text().right( text().length() - curPos ); Tokens tokens = Evaluator::scan( subtext ); if( !tokens.valid() ) return; if( tokens.count()<1 ) return; Token firstToken = tokens[ 0 ]; // left par ? if( firstToken.isOperator() ) if( firstToken.asOperator() == Token::LeftPar ) if( firstToken.pos() == 0 ) { // find the matching right par unsigned par = 1; unsigned int k = 0; Token matchToken; int matchPos = -1; for( k = 1; k < tokens.count(); k++ ) { if( par < 1 ) break; Token matchToken = tokens[k]; if( matchToken.isOperator() ) { if( matchToken.asOperator() == Token::LeftPar ) par++; if( matchToken.asOperator() == Token::RightPar ) par--; if( par == 0 ) matchPos = matchToken.pos(); } } if( matchPos >= 0 ) { setSelection( 0, curPos+matchPos, 0, curPos+matchPos+1, 2 ); setSelection( 0, curPos+firstToken.pos(), 0, curPos+firstToken.pos()+1, 1 ); setCursorPosition( para, curPos ); } } }
static QString tokenizeFormula(const QString& formula) { Formula f; QString expr = formula; expr.prepend( '=' ); f.setExpression( expr ); Tokens tokens = f.tokens(); QString resultCodes; if( tokens.valid() ) for( int i = 0; i < tokens.count(); i++ ) resultCodes.append( encodeTokenType( tokens[i] ) ); return resultCodes; }
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 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); } }
QString Calligra::Sheets::Odf::encodeFormula(const QString& expr, const KLocale* locale) { // use locale settings const QString decimal = locale ? locale->decimalSymbol() : "."; QString result('='); Formula formula; Tokens tokens = formula.scan(expr, locale); if (!tokens.valid() || tokens.count() == 0) return expr; // no altering on error for (int i = 0; i < tokens.count(); ++i) { const QString tokenText = tokens[i].text(); const Token::Type type = tokens[i].type(); switch (type) { case Token::Cell: case Token::Range: { result.append('['); // FIXME Stefan: Hack to get the apostrophes right. Fix and remove! const int pos = tokenText.lastIndexOf('!'); if (pos != -1 && tokenText.left(pos).contains(' ')) result.append(Region::saveOdf('\'' + tokenText.left(pos) + '\'' + tokenText.mid(pos))); else result.append(Region::saveOdf(tokenText)); result.append(']'); break; } case Token::Float: { QString tmp(tokenText); result.append(tmp.replace(decimal, ".")); break; } case Token::Operator: { if (tokens[i].asOperator() == Token::Equal) result.append('='); else result.append(tokenText); break; } case Token::Identifier: { if (tokenText == "ERRORTYPE") { // need to replace this result.append("ERROR.TYPE"); } else if (tokenText == "LEGACYNORMSDIST") { result.append("LEGACY.NORMSDIST"); } else if (tokenText == "LEGACYNORMSINV") { result.append("LEGACY.NORMSINV"); } else { // dump it out unchanged result.append(tokenText); } break; } case Token::Boolean: case Token::Integer: case Token::String: default: result.append(tokenText); break; } } return result; }
void Editor::triggerAutoComplete() { if( !d->autoCompleteEnabled ) return; // tokenize the expression (don't worry, this is very fast) // faster now that it uses flex. ;) int para = 0, curPos = 0; getCursorPosition( ¶, &curPos ); QString subtext = text().left( curPos ); Tokens tokens = Evaluator::scan( subtext ); if(!tokens.valid()) { kdWarning() << "invalid tokens.\n"; return; } if(tokens.isEmpty() || subtext.endsWith(" ")) return; Token lastToken = tokens[ tokens.count()-1 ]; // last token must be an identifier if( !lastToken.isIdentifier() ) return; QString id = lastToken.text(); if( id.isEmpty() ) return; // find matches in function names QStringList fnames = FunctionManager::instance()->functionList(FunctionManager::All); QStringList choices; for( unsigned i=0; i<fnames.count(); i++ ) if( fnames[i].startsWith( id, false ) ) { QString str = fnames[i]; ::Function* f = FunctionManager::instance()->function( str ); if( f && !f->description.isEmpty() ) str.append( ':' ).append( f->description ); choices.append( str ); } choices.sort(); // find matches in variables names QStringList vchoices; QStringList values = NumeralModel::instance()->valueNames(); for(QStringList::ConstIterator it = values.begin(); it != values.end(); ++it) if( (*it).startsWith( id, false ) ) { QString choice = NumeralModel::description(*it); if(choice.isEmpty()) choice = NumeralModel::instance()->value(*it).toString(); vchoices.append( QString("%1:%2").arg( *it, choice ) ); } vchoices.sort(); choices += vchoices; // no match, don't bother with completion if( !choices.count() ) return; // one match, complete it for the user if( choices.count()==1 ) { QString str = QStringList::split( ':', choices[0] )[0]; // single perfect match, no need to give choices. if(str == id.lower()) return; str = str.remove( 0, id.length() ); int para = 0, curPos = 0; getCursorPosition( ¶, &curPos ); blockSignals( true ); insert( str ); setSelection( 0, curPos, 0, curPos+str.length() ); blockSignals( false ); return; } // present the user with completion choices d->completion->showCompletion( choices ); }
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); }