122 lines
3.6 KiB
C++
122 lines
3.6 KiB
C++
// QCodeEditor
|
|
#include "QPythonHighlighter.hpp"
|
|
#include "QLanguage.hpp"
|
|
#include "QSyntaxStyle.hpp"
|
|
|
|
// Qt
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
|
|
QPythonHighlighter::QPythonHighlighter(QTextDocument *document)
|
|
: QStyleSyntaxHighlighter(document), m_highlightRules(),
|
|
m_highlightBlockRules(),
|
|
m_includePattern(QRegularExpression(R"(import \w+)")),
|
|
m_functionPattern(QRegularExpression(
|
|
R"(\b([A-Za-z0-9_]+(?:\.))*([A-Za-z0-9_]+)(?=\())")),
|
|
m_defTypePattern(QRegularExpression(
|
|
R"(\b([A-Za-z0-9_]+)\s+[A-Za-z]{1}[A-Za-z0-9_]+\s*[;=])")) {
|
|
QFile fl(":/WingToolPy/python.xml");
|
|
|
|
if (!fl.open(QIODevice::ReadOnly)) {
|
|
return;
|
|
}
|
|
|
|
QLanguage language(&fl);
|
|
|
|
if (!language.isLoaded()) {
|
|
return;
|
|
}
|
|
|
|
auto keys = language.keys();
|
|
for (auto &&key : keys) {
|
|
auto names = language.names(key);
|
|
for (auto &&name : names) {
|
|
m_highlightRules.append(
|
|
{QRegularExpression(QString(R"(\b%1\b)").arg(name)), key});
|
|
}
|
|
}
|
|
|
|
// Following rules has higher priority to display
|
|
// than language specific keys
|
|
// So they must be applied at last.
|
|
// Numbers
|
|
m_highlightRules.append(
|
|
{QRegularExpression(R"(\b(0b|0x){0,1}[\d.']+\b)"), "Number"});
|
|
|
|
// Strings
|
|
m_highlightRules.append({QRegularExpression(R"("[^\n"]*")"), "String"});
|
|
m_highlightRules.append({QRegularExpression(R"('[^\n"]*')"), "String"});
|
|
|
|
// Single line comment
|
|
m_highlightRules.append({QRegularExpression("#[^\n]*"), "Comment"});
|
|
|
|
// Multiline string
|
|
m_highlightBlockRules.append(
|
|
{QRegularExpression("(''')"), QRegularExpression("(''')"), "String"});
|
|
m_highlightBlockRules.append({QRegularExpression("(\"\"\")"),
|
|
QRegularExpression("(\"\"\")"), "String"});
|
|
}
|
|
|
|
void QPythonHighlighter::highlightBlock(const QString &text) {
|
|
// Checking for function
|
|
{
|
|
auto matchIterator = m_functionPattern.globalMatch(text);
|
|
|
|
while (matchIterator.hasNext()) {
|
|
auto match = matchIterator.next();
|
|
|
|
setFormat(match.capturedStart(), match.capturedLength(),
|
|
syntaxStyle()->getFormat("Type"));
|
|
|
|
setFormat(match.capturedStart(2), match.capturedLength(2),
|
|
syntaxStyle()->getFormat("Function"));
|
|
}
|
|
}
|
|
|
|
for (auto &rule : m_highlightRules) {
|
|
auto matchIterator = rule.pattern.globalMatch(text);
|
|
|
|
while (matchIterator.hasNext()) {
|
|
auto match = matchIterator.next();
|
|
|
|
setFormat(match.capturedStart(), match.capturedLength(),
|
|
syntaxStyle()->getFormat(rule.formatName));
|
|
}
|
|
}
|
|
|
|
setCurrentBlockState(0);
|
|
int startIndex = 0;
|
|
int highlightRuleId = previousBlockState();
|
|
if (highlightRuleId < 1 || highlightRuleId > m_highlightBlockRules.size()) {
|
|
for (int i = 0; i < m_highlightBlockRules.size(); ++i) {
|
|
startIndex = text.indexOf(m_highlightBlockRules.at(i).startPattern);
|
|
|
|
if (startIndex >= 0) {
|
|
highlightRuleId = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (startIndex >= 0) {
|
|
const auto &blockRules = m_highlightBlockRules.at(highlightRuleId - 1);
|
|
auto match = blockRules.endPattern.match(
|
|
text, startIndex + 1); // Should be + length of start pattern
|
|
|
|
int endIndex = match.capturedStart();
|
|
int matchLength = 0;
|
|
|
|
if (endIndex == -1) {
|
|
setCurrentBlockState(highlightRuleId);
|
|
matchLength = text.length() - startIndex;
|
|
} else {
|
|
matchLength = endIndex - startIndex + match.capturedLength();
|
|
}
|
|
|
|
setFormat(startIndex, matchLength,
|
|
syntaxStyle()->getFormat(blockRules.formatName));
|
|
startIndex =
|
|
text.indexOf(blockRules.startPattern, startIndex + matchLength);
|
|
}
|
|
}
|