Введение / установка
Я работаю над проектом текстового редактора, и в настоящее время у меня настроена рабочая подсветка синтаксиса. Но я чувствую, что мой подход к проектированию не очень хорошо подходит для поддерживаемого кода.
Вот объявление класса подсветки синтаксиса (не беспокойтесь о языковых типах, которым предшествует «Q»; они просто определены каркасом Qt для C ++):
class Highlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
Highlighter(QTextDocument *parent = nullptr) : QSyntaxHighlighter (parent) {}
virtual void addKeywords(QStringList keywords);
virtual void setKeywordFormat();
virtual void setClassPattern(QRegularExpression classPattern);
virtual void setClassFormat();
virtual void setFunctionPattern(QRegularExpression functionPattern);
virtual void setFunctionFormat();
virtual void setQuotePattern(QRegularExpression quotePattern);
virtual void setQuoteFormat();
virtual void setInlineCommentPattern(QRegularExpression inlineCommentPattern);
virtual void setInlineCommentFormat();
virtual void setBlockCommentStartPattern(QRegularExpression blockCommentStart);
virtual void setBlockCommentEndPattern(QRegularExpression blockCommentEnd);
virtual void setBlockCommentFormat();
virtual void addRule(QRegularExpression pattern, QTextCharFormat format);
protected:
virtual void highlightBlock(const QString &text) override;
virtual void highlightMultilineComments(const QString &text);
private:
struct HighlightingRule
{
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> rules;
QRegularExpression blockCommentStart;
QRegularExpression blockCommentEnd;
QTextCharFormat keywordFormat;
QTextCharFormat classFormat;
QTextCharFormat inlineCommentFormat;
QTextCharFormat blockCommentFormat;
QTextCharFormat quoteFormat;
QTextCharFormat functionFormat;
};
Я объявил многие функции виртуальными с учетом наследования. Однако вопрос о том, стоит ли мне использовать наследование, действительно лежит в основе этой проблемы (подробнее об этом чуть ниже).
Кроме того, заголовок включает следующие функции, не являющиеся частью класса:
Highlighter *cHighlighter(QTextDocument *doc);
Highlighter *cppHighlighter(QTextDocument *doc);
Highlighter *javaHighlighter(QTextDocument *doc);
Highlighter *pythonHighlighter(QTextDocument *doc);
Каждая из этих функций собирает соответствующий тип маркера. Ниже приведены определения функций:
/* Returns a Highlighter object specific to the C language and its grammar and syntax.
*/
Highlighter *cHighlighter(QTextDocument *doc)
{
QStringList keywords;
keywords << "\\bauto\\b" << "\\bbreak\\b" << "\\bcase\\b" << "\\bchar\\b" << "\\bconst\\b"
<< "\\bcontinue\\b" << "\\bdefault\\b" << "\\bdo\\b" << "\\bdouble\\b" << "\\belse\\b"
<< "\\benum\\b" << "\\bextern\\b" << "\\bfloat\\b" << "\\bfor\\b" << "\\bgoto\\b"
<< "\\bif\\b" << "\\bint\\b" << "\\blong\\b" << "\\bregister\\b" << "\\breturn\\b"
<< "\\bshort\\b" << "\\bsigned\\b" << "\\bsizeof\\b" << "\\bstatic\\b" << "\\bstruct\\b"
<< "\\bswitch\\b" << "\\btypedef\\b" << "\\bunion\\b" << "\\bunsigned\\b" << "\\bvoid\\b"
<< "\\bvolatile\\b" << "\\bwhile\\b";
QRegularExpression classPattern("\\b[A-Z_][a-zA-Z0-9_]*\\b");
QRegularExpression quotePattern("(\".*\")|('\\\\.')|('.{0,1}')");
QRegularExpression functionPattern("\\b[A-Za-z_][A-Za-z0-9_]*(?=\\()");
QRegularExpression inlineCommentPattern("//.*");
QRegularExpression blockCommentStart("/\\*");
QRegularExpression blockCommentEnd("\\*/");
Highlighter *highlighter = new Highlighter(doc);
highlighter->addKeywords(keywords);
highlighter->setClassPattern(classPattern);
highlighter->setQuotePattern(quotePattern);
highlighter->setFunctionPattern(functionPattern);
highlighter->setInlineCommentPattern(inlineCommentPattern);
highlighter->setBlockCommentStartPattern(blockCommentStart);
highlighter->setBlockCommentEndPattern(blockCommentEnd);
return highlighter;
}
/* Returns a Highlighter object specific to the C++ language and its grammar and syntax.
*/
Highlighter *cppHighlighter(QTextDocument *doc)
{
Highlighter *cLanguage = cHighlighter(doc);
QStringList cppOnlyKeywords;
cppOnlyKeywords << "\\basm\\b" << "\\bbool\\b" << "\\bcatch\\b" <<
"\\bclass\\b" << "\\bconst_cast\\b" << "\\bdelete\\b" <<
"\\bdynamic_cast\\b" << "\\bexplicit\\b" << "\\bfalse\\b" <<
"\\bfriend\\b" << "\\binline\\b" << "\\bmutable\\b" <<
"\\bnamespace\\b" << "\\bnew\\b" << "\\boperator\\b" <<
"\\bprivate\\b" << "\\bprotected\\b" << "\\bpublic\\b" <<
"\\breinterpret_cast\\b" << "\\bstatic_cast\\b" <<
"\\btemplate\\b" << "\\bthis\\b" << "\\bthrow\\b" <<
"\\btrue\\b" << "\\btry\\b" << "\\btypeid\\b" << "\\btypename\\b" <<
"\\bvirtual\\b" << "\\busing\\b" << "\\bwchar_t\\b";
cLanguage->addKeywords(cppOnlyKeywords);
return cLanguage;
}
/* Returns a Highlighter object specific to the Java language and its grammar and syntax.
*/
Highlighter *javaHighlighter(QTextDocument *doc)
{
QStringList keywords;
keywords << "\\babstract\\b" << "\\bassert\\b" << "\\bboolean\\b" << "\\bbreak\\b" << "\\bbyte\\b"
<< "\\bcase\\b" << "\\bcatch\\b" << "\\bchar\\b" << "\\bclass\\b" << "\\bconst\\b" << "\\bcontinue\\b"
<< "\\bdefault\\b" << "\\bdo\\b" << "\\bdouble\\b" << "\\belse\\b" << "\\benum\\b" << "\\bextends\\b"
<< "\\bfinal\\b" << "\\bfinally\\b" << "\\bfloat\\b" << "\\bfor\\b" << "\\bgoto\\b" << "\\bif\\b"
<< "\\bimplements\\b" << "\\bimport\\b" << "\\binstanceof\\b" << "\\bint\\b" << "\\binterface\\b"
<< "\\blong\\b" << "\\bnative\\b" << "\\bnew\\b" << "\\bpackage\\b" << "\\bprivate\\b" << "\\bprotected\\b"
<< "\\bpublic\\b" << "\\breturn\\b" << "\\bshort\\b" << "\\bstatic\\b" << "\\bstrictfp\\b" << "\\bsuper\\b"
<< "\\bswitch\\b" << "\\bsynchronized\\b" << "\\bthis\\b" << "\\bthrow\\b" << "\\bthrows\\b" << "\\btransient\\b"
<< "\\btry\\b" << "\\bvoid\\b" << "\\bvolatile\\b" << "\\bwhile\\b" << "\\btrue\\b" << "\\bfalse\\b" << "\\bnull\\b";
QRegularExpression classPattern("\\b[A-Z_][a-zA-Z0-9_]*\\b");
QRegularExpression quotePattern("(\".*\")|('\\\\.')|('.{0,1}')");
QRegularExpression functionPattern("\\b[A-Za-z_][A-Za-z0-9_]*(?=\\()");
QRegularExpression inlineCommentPattern("//.*");
QRegularExpression blockCommentStart("/\\*");
QRegularExpression blockCommentEnd("\\*/");
Highlighter *highlighter = new Highlighter(doc);
highlighter->addKeywords(keywords);
highlighter->setClassPattern(classPattern);
highlighter->setQuotePattern(quotePattern);
highlighter->setFunctionPattern(functionPattern);
highlighter->setInlineCommentPattern(inlineCommentPattern);
highlighter->setBlockCommentStartPattern(blockCommentStart);
highlighter->setBlockCommentEndPattern(blockCommentEnd);
return highlighter;
}
/* Returns a Highlighter object specific to the Python language and its grammar and syntax.
*/
Highlighter *pythonHighlighter(QTextDocument *doc)
{
QStringList keywords;
keywords << "\\band\\b" << "\\bas\\b" << "\\bassert\\b" << "\\bbreak\\b" << "\\bclass\\b" << "\\bcontinue\\b"
<< "\\bdef\\b" << "\\bdel\\b" << "\\belif\\b" << "\\belse\\b" << "\\bexcept\\b" << "\\bFalse\\b"
<< "\\bfinally\\b" << "\\bfor\\b" << "\\bfrom\\b" << "\\bglobal\\b" << "\\bif\\b" << "\\bimport\\b"
<< "\\bin\\b" << "\\bis\\b" << "\\blambda\\b" << "\\bNone\\b" << "\\bnonlocal\\b" << "\\bnot\\b"
<< "\\bor\\b" << "\\bpass\\b" << "\\braise\\b" << "\\breturn\\b" << "\\bTrue\\b" << "\\btry\\b"
<< "\\bwhile\\b" << "\\bwith\\b" << "\\byield\\b";
QRegularExpression classPattern("\\b[A-Z_][a-zA-Z0-9_]*\\b");
QRegularExpression quotePattern("(\".*\")|('.*')");
QRegularExpression functionPattern("\\b[A-Za-z_][A-Za-z0-9_]*(?=\\()");
QRegularExpression inlineCommentPattern("#.*");
QRegularExpression blockCommentStart("'''");
QRegularExpression blockCommentEnd("'''");
Highlighter *highlighter = new Highlighter(doc);
highlighter->addKeywords(keywords);
highlighter->setClassPattern(classPattern);
highlighter->setQuotePattern(quotePattern);
highlighter->setFunctionPattern(functionPattern);
highlighter->setInlineCommentPattern(inlineCommentPattern);
highlighter->setBlockCommentStartPattern(blockCommentStart);
highlighter->setBlockCommentEndPattern(blockCommentEnd);
return highlighter;
}
Проблема
Обратите внимание на защищенный метод с именем highlightMultilineComments
. По умолчанию из-за того, как в Qt выполняется подсветка синтаксиса, этот метод предполагает, что регулярные выражения Highlighter blockCommentStart
и blockCommentEnd
не идентичны. В случае таких языков, как Python, это явно не так, поскольку начальный и конечный разделители комментариев одинаковы (тройные одинарные или двойные кавычки). И в этом случае функция не работает должным образом. Это все, что вам нужно знать.
Проблемы с наследованием
Я сделал метод highlightMultilineComments
виртуальным с намерением создать подкласс, скажем PythonHighlighter
, который переопределяет только эту специальную функцию для определения пользовательской логики. Теоретически, другие языки могут переопределять все и настраивать то, как они хотят настроить подсветку (если я перейду с наследованием).
Но если бы я создал подкласс для Python, это означало бы, что я должен был бы создать его для C, C ++, Java и любого другого языка, который я хотел бы добавить в будущем (для согласованности). Очевидно, что это сложнее в управлении, чем мой нынешний подход, где у меня есть функции, которые просто собирают маркеры. Если я добавлю класс для каждого языка, количество исходных файлов значительно возрастет.
Проблемы с функциями компоновщика
Таким образом, использование функций компоновщика имеет свои преимущества. Но такой подход не позволяет мне переопределить метод highlightMultilineComments
. Так что это явно не идеально в этом отношении.
Вопрос
Как я могу использовать преимущества наследования - возможность переопределять методы, подобные highlightMultilineComments
, в зависимости от языка - без ущерба для относительной управляемости "функций построителя"?
Дополнительные вещи, которые я рассмотрел
Я также рассмотрел возможность добавления функции, подобной highlightSymmetricMultilineComments
. Затем highlightMultilineComments
может проверить, имеют ли blockCommentStart
и blockCommentEnd
одинаковый шаблон регулярных выражений. Если они имеют одинаковый шаблон, функция просто вызовет свой симметричный вариант.
Это представляет очевидную проблему - не имеет смысла, чтобы это было в Highlighter, учитывая, что не все языки имеют симметричные многострочные комментарии (Python - единственный, который в настоящее время поддерживается текстовым редактором, который поддерживает).