Название: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: gil9red от Апрель 02, 2013, 15:31
Здравствуйте! Делаю многоязыковую подсветку синтаксиса, в качестве основы взял qt-шный пример Можно ли в наследнике QSyntaxHighlighter написать код подсветки пар скобок: (), {}, [], <>? Если можно то как и где :)
Спасибо :)
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: _OLEGator_ от Апрель 02, 2013, 16:03
А в чем собственно проблема, разве в примерах этого нет?
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: gil9red от Апрель 02, 2013, 16:32
да можно это сделать, вот только нужно делать подсветку, когда текстовый курсор будет рядом с скобкой :)
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: gil9red от Апрель 03, 2013, 17:02
Что никто не знает? :) Такая подсветка пар скобок есть например в Qt Creator'е, NotePad++ :) Хотелось бы определять подсветку пар скобок именно в классах подсветки синтаксиса - для гибкость подсветки) Приведу тогда код, может станет яснее) Есть класс USyntaxHighlighter, наследуемый от QSyntaxHighlighter. Класс USyntaxHighlighter содержит только алгоритмы подсветки и все: h. #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_OBJECT
public: 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); };
.срр /// PUBLIC USyntaxHighlighter::USyntaxHighlighter(QTextDocument *parent): QSyntaxHighlighter(parent) {
}
void USyntaxHighlighter::addRule(HighlightingRule hRule) { highlightingRules.append(hRule); }
/// PROTECTED void 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); } }
А тут пример класса, наследуемого от USyntaxHighlighter и определяемого синтаксис: class USyntaxHighlighter_Python: public USyntaxHighlighter { Q_OBJECT
public: 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"; } };
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: gil9red от Апрель 03, 2013, 23:34
Похоже я тут сам с собой общаюсь... Нашел решение, осталось малость - сделать его :D скину решение, когда готово будет :)
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: _OLEGator_ от Апрель 04, 2013, 09:12
Как в Creator'e реализовано смотрел?
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: gil9red от Апрель 04, 2013, 11:21
Да, сначало искал в гите креаторе, но надоело искать :) и нашел исходники какого то редактора кода написанного на qt, но его подсветка не полностью соответствовала тому что мне нужно было, поэтому буду переделывать :)
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: _OLEGator_ от Апрель 04, 2013, 11:29
Можно повеситься на сигнал QTextEdit::cursorPositionChanged(), запоминать позицию и при необходимости обновлять подсветку. C++ (Qt) void QSyntaxHighlighter::rehighlightBlock ( const QTextBlock & block ) [slot] void QSyntaxHighlighter::rehighlight () [slot]
Конечно я бы все-таки глянул, как реализовано в Creator'e.
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: kai666_73 от Апрель 04, 2013, 17:23
И все-таки в креаторе это сделано смачно ) Могу, так-сказать, задать направление basetexteditor.cpp -> BaseTextEditorWidget::slotCursorPositionChanged() -> BaseTextEditorWidget::updateHighlights() -> ...
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: gil9red от Апрель 04, 2013, 21:58
Раз обещал скинуть, слово нужно выполнять :) Нам нужно будет сделать наследника QTextEdit и в него добавить слоты matchBrackets, matchLeftBrackets, matchRightBrackets , createBracketsSelection. Слот matchBrackets подключаем к сигналу cursorPositionChanged: 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); }
А также создадим наследника QSyntaxHighlighter: class USyntaxHighlighter: public QSyntaxHighlighter { Q_OBJECT
public: 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); };
/// PROTECTED void 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); }
Код еще не закончен, но рабочий :) Во вложении код UTextEdit, USyntaxHighlighter и его наследника с поддержкой подсветки синтаксиса с++ USyntaxHighlighter_Сpp :)
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: krish от Август 09, 2013, 12:49
А можно весь проект Qt ? а то интересно посмотреть как это выглядит в деле. Я пытался по исходникам оживить код, но кроме синтаксиса ничего не выделяет. Ни скобки, ничего другого.
Название: Re: QSyntaxHighlighter. Подсветка пар скобок
Отправлено: gil9red от Август 09, 2013, 13:57
Можно :D Вот только не для всех языков мне хватило энтузиазма и терпения закончить настройку файлов правил (rules) :)
|