#include <QtGui>#include <QtCore>struct HighlightingRule{ QRegExp pattern; QTextCharFormat format;};// добавить границу словаstatic void addWordBoundary(QStringList *list){ list->replaceInStrings(QRegExp("^"), "\\b"); list->replaceInStrings(QRegExp("$"), "\\b");}class USyntaxHighlighter: public QSyntaxHighlighter{ Q_OBJECTpublic: USyntaxHighlighter(QTextDocument *parent = 0); void addRule(HighlightingRule hRule); inline virtual QString language(){ return ""; } inline QStringList keywordList() { return keywordPatterns.replaceInStrings("\\b", ""); }protected: QVector <HighlightingRule> highlightingRules; QRegExp commentStartExpression; QRegExp commentEndExpression; QTextCharFormat keywordFormat; QTextCharFormat classFormat; QTextCharFormat singleLineCommentFormat; QTextCharFormat multiLineCommentFormat; QTextCharFormat quotationFormat; QTextCharFormat functionFormat; QStringList keywordPatterns;protected: void highlightBlock(const QString &text);};
/// PUBLICUSyntaxHighlighter::USyntaxHighlighter(QTextDocument *parent): QSyntaxHighlighter(parent){}void USyntaxHighlighter::addRule(HighlightingRule hRule){ highlightingRules.append(hRule);}/// PROTECTEDvoid USyntaxHighlighter::highlightBlock(const QString &text){ foreach (const HighlightingRule &rule, highlightingRules) { QRegExp expression(rule.pattern); int index = expression.indexIn(text); while (index >= 0) { int length = expression.matchedLength(); setFormat(index, length, rule.format); index = expression.indexIn(text, index + length); } } if(commentStartExpression.isEmpty() || commentEndExpression.isEmpty()) return; setCurrentBlockState(0); int startIndex = 0; if (previousBlockState() != 1) startIndex = commentStartExpression.indexIn(text); while (startIndex >= 0) { int endIndex = commentEndExpression.indexIn(text, startIndex); int commentLength; if (endIndex == -1) { setCurrentBlockState(1); commentLength = text.length() - startIndex; }else commentLength = endIndex - startIndex + commentEndExpression.matchedLength(); setFormat(startIndex, commentLength, multiLineCommentFormat); startIndex = commentStartExpression.indexIn(text, startIndex + commentLength); }}
class USyntaxHighlighter_Python: public USyntaxHighlighter{ Q_OBJECTpublic: inline USyntaxHighlighter_Python(QTextDocument *parent = 0): USyntaxHighlighter(parent) { HighlightingRule rule; keywordFormat.setForeground(Qt::darkCyan); keywordFormat.setFontWeight(QFont::Bold); keywordPatterns << "False" << "class" << "finally" << "is" << "return" << "None" << "continue" << "for" << "lambda" << "try" << "True" << "def" << "from" << "nonlocal" << "while" << "and" << "del" << "global" << "not" << "with" << "as" << "elif" << "if" << "or" << "yield" << "assert" << "else" << "import" << "pass" << "reak" << "except" << "in" << "raise" << "print" << "type"; addWordBoundary(&keywordPatterns); for(int i = 0; i < keywordPatterns.count(); i++) { QString pattern = keywordPatterns.at(i); rule.pattern = QRegExp(pattern); rule.format = keywordFormat; highlightingRules.append(rule); } singleLineCommentFormat.setForeground(Qt::darkGreen); rule.pattern = QRegExp("#[^\n]*"); rule.format = singleLineCommentFormat; highlightingRules.append(rule); multiLineCommentFormat.setForeground(Qt::darkGreen); quotationFormat.setForeground(Qt::darkGray); rule.pattern = QRegExp("\".*\""); rule.format = quotationFormat; highlightingRules.append(rule); rule.pattern = QRegExp("\'.*\'"); rule.format = quotationFormat; highlightingRules.append(rule); commentStartExpression = QRegExp(""); commentEndExpression = QRegExp(""); } inline QString language(){ return "Python"; }};
C++ (Qt)void QSyntaxHighlighter::rehighlightBlock ( const QTextBlock & block ) [slot]void QSyntaxHighlighter::rehighlight () [slot]
UTextEdit::UTextEdit(QWidget *parent): QTextEdit(parent){ connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(matchBrackets()));}
static bool isLeftBrackets(QChar symbol){ return symbol == '(' || symbol == '{' || symbol == '[';}static bool isRightBrackets(QChar symbol){ return symbol == ')' || symbol == '}' || symbol == ']';}struct UBracketInfo{ QChar character; int position;};class UTextBlockData: public QTextBlockUserData{public: QVector <UBracketInfo *> brackets() { return m_brackets; } void insert(UBracketInfo *info) { int i = 0; while(i < m_brackets.size() && info->position > m_brackets.at(i)->position) i++; m_brackets.insert(i, info); } private: QVector <UBracketInfo *> m_brackets;};void UTextEdit::matchBrackets(){ QList <QTextEdit::ExtraSelection> selections; setExtraSelections(selections); QTextBlock textBlock = textCursor().block(); UTextBlockData *data = static_cast <UTextBlockData *> (textBlock.userData()); if(data) { QVector <UBracketInfo *> brackets = data->brackets(); int position = textCursor().block().position(); for(int i = 0; i < brackets.size(); i++) { UBracketInfo *bracket = brackets.at(i); int currentPosition = textCursor().position() - textBlock.position(); // Clicked on a left brackets? if (bracket->position == currentPosition - 1 && isLeftBrackets(bracket->character)) { if (matchLeftBrackets(textBlock, i + 1, 0)) createBracketsSelection(position + bracket->position); } // Clicked on a right brackets? if (bracket->position == currentPosition - 1 && isRightBrackets(bracket->character)) { if (matchRightBrackets(textBlock, i - 1, 0)) createBracketsSelection(position + bracket->position); } } }}/** Test left brackets match **/bool UTextEdit::matchLeftBrackets(QTextBlock currentBlock, int index, int numberLeftBracket){ UTextBlockData *data = static_cast <UTextBlockData *> (currentBlock.userData()); QVector<UBracketInfo *> brackets = data->brackets(); int positionInDocument = currentBlock.position(); // Match in same line? for (; index < brackets.count(); index++) { UBracketInfo *bracket = brackets.at(index); if (isLeftBrackets(bracket->character)) { ++numberLeftBracket; continue; } if (isRightBrackets(bracket->character) && numberLeftBracket == 0) { createBracketsSelection(positionInDocument + bracket->position); return true; }else --numberLeftBracket; } // No match yet? Then try next block currentBlock = currentBlock.next(); if (currentBlock.isValid()) return matchLeftBrackets(currentBlock, 0, numberLeftBracket); // No match at all return false;}/** Test right brackets match **/bool UTextEdit::matchRightBrackets(QTextBlock currentBlock, int index, int numberRightBracket){ UTextBlockData *data = static_cast <UTextBlockData *> (currentBlock.userData()); QVector<UBracketInfo *> brackets = data->brackets(); int positionInDocument = currentBlock.position(); // Match in same line? for (int i = index; i >= 0; i--) { UBracketInfo *bracket = brackets.at(i); if (isRightBrackets(bracket->character)) { ++numberRightBracket; continue; } if (isLeftBrackets(bracket->character) && numberRightBracket == 0) { createBracketsSelection(positionInDocument + bracket->position); return true; } else --numberRightBracket; } // No match yet? Then try previous block currentBlock = currentBlock.previous(); if (currentBlock.isValid()) { // Recalculate correct index first UTextBlockData *data = static_cast <UTextBlockData *> (currentBlock.userData()); QVector <UBracketInfo *> brackets = data->brackets(); return matchRightBrackets(currentBlock, brackets.count() - 1, numberRightBracket); } // No match at all return false;}/** Set brackets highlighter at pos **/void UTextEdit::createBracketsSelection(int position){ QList <QTextEdit::ExtraSelection> listSelections = extraSelections(); QTextEdit::ExtraSelection selection; QTextCharFormat format = selection.format; format.setForeground(Qt::red); selection.format = format; QTextCursor cursor = textCursor(); cursor.setPosition(position); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); selection.cursor = cursor; listSelections.append(selection); setExtraSelections(listSelections);}
class USyntaxHighlighter: public QSyntaxHighlighter{ Q_OBJECTpublic: inline USyntaxHighlighter(QTextDocument *document = 0): QSyntaxHighlighter(document) { } inline void addRule(UHighlightingRule hRule) { highlightingRules.append(hRule); } inline virtual QString language(){ return ""; } inline void setTextEdit(QTextEdit *textEdit) { setDocument(textEdit->document()); } inline QStringList keywordList() { return keywordPatterns.replaceInStrings("\\b", ""); }protected: QVector <UHighlightingRule> highlightingRules; QRegExp commentStartExpression; QRegExp commentEndExpression; QTextCharFormat keywordFormat; QTextCharFormat classFormat; QTextCharFormat singleLineCommentFormat; QTextCharFormat multiLineCommentFormat; QTextCharFormat quotationFormat; QTextCharFormat functionFormat; QStringList keywordPatterns; enum UBrackets { RoundBrackets, CurlyBraces, SquareBrackets };protected: void highlightBlock(const QString &text); void insertBrackets(QChar leftChar, QChar rightChar, UTextBlockData *data, QString text); void insertBrackets(UBrackets brackets, UTextBlockData *data, QString text);};/// PROTECTEDvoid USyntaxHighlighter::highlightBlock(const QString &text){ for(int i = 0; i < highlightingRules.count(); i++) { UHighlightingRule rule = highlightingRules.at(i); QRegExp expression(rule.pattern); int index = expression.indexIn(text); while(index >= 0) { int length = expression.matchedLength(); setFormat(index, length, rule.format); index = expression.indexIn(text, index + length); } } UTextBlockData *data = new UTextBlockData(); /// скобки insertBrackets(RoundBrackets, data, text); insertBrackets(CurlyBraces, data, text); insertBrackets(SquareBrackets, data, text); /// скобки setCurrentBlockUserData(data); if(commentStartExpression.isEmpty() || commentEndExpression.isEmpty()) return; setCurrentBlockState(0); int startIndex = 0; if(previousBlockState() != 1) startIndex = commentStartExpression.indexIn(text); while (startIndex >= 0) { int endIndex = commentEndExpression.indexIn(text, startIndex); int commentLength; if (endIndex == -1) { setCurrentBlockState(1); commentLength = text.length() - startIndex; }else commentLength = endIndex - startIndex + commentEndExpression.matchedLength(); setFormat(startIndex, commentLength, multiLineCommentFormat); startIndex = commentStartExpression.indexIn(text, startIndex + commentLength); }}void USyntaxHighlighter::insertBrackets(QChar leftChar, QChar rightChar, UTextBlockData *data, QString text){ int leftPosition = text.indexOf(leftChar); while(leftPosition != -1) { UBracketInfo *info = new UBracketInfo(); info->character = leftChar; info->position = leftPosition; data->insert(info); leftPosition = text.indexOf(leftChar, leftPosition + 1); } int rightPosition = text.indexOf(rightChar); while(rightPosition != -1) { UBracketInfo *info = new UBracketInfo(); info->character = rightChar; info->position = rightPosition; data->insert(info); rightPosition = text.indexOf(rightChar, rightPosition + 1); }}void USyntaxHighlighter::insertBrackets(UBrackets brackets, UTextBlockData *data, QString text){ QChar leftChar = '0'; QChar rightChar = '0'; switch(brackets) { case RoundBrackets: leftChar = '('; rightChar = ')'; break; case CurlyBraces: leftChar = '{'; rightChar = '}'; break; case SquareBrackets: leftChar = '['; rightChar = ']'; break; } insertBrackets(leftChar, rightChar, data, text);}