ff4ff35918
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
198 lines
6.0 KiB
C++
198 lines
6.0 KiB
C++
// Copyright (C) 2021 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#include "syntaxhighlighter.h"
|
|
|
|
#include <QtCore/qregularexpression.h>
|
|
|
|
#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
|
|
#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterialshadergenerator_p.h>
|
|
|
|
#include <QtQuick3DGlslParser/private/glsllexer_p.h>
|
|
#include <QtQuick3DGlslParser/private/glslparser_p.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
// Text color and style categories
|
|
enum TextStyle : quint8 {
|
|
C_VISUAL_WHITESPACE,
|
|
C_PREPROCESSOR,
|
|
C_NUMBER,
|
|
C_COMMENT,
|
|
C_KEYWORD,
|
|
C_PARAMETER,
|
|
C_REMOVED_LINE
|
|
};
|
|
|
|
static constexpr TextStyle GLSLReservedKeyword = C_REMOVED_LINE;
|
|
|
|
static QTextCharFormat formatForCategory(TextStyle category)
|
|
{
|
|
switch (category) {
|
|
case C_PARAMETER:
|
|
{
|
|
QTextCharFormat fmt;
|
|
fmt.setForeground(QColor::fromRgb(0xaa, 0xaa, 0xff));
|
|
return fmt;
|
|
}
|
|
case C_PREPROCESSOR:
|
|
{
|
|
QTextCharFormat fmt;
|
|
fmt.setForeground(QColor::fromRgb(0x55, 0x55, 0xff));
|
|
return fmt;
|
|
}
|
|
case C_NUMBER:
|
|
{
|
|
QTextCharFormat fmt;
|
|
fmt.setForeground(QColor::fromRgb(0xff, 0x55, 0xff));
|
|
return fmt;
|
|
}
|
|
case C_COMMENT:
|
|
{
|
|
QTextCharFormat fmt;
|
|
fmt.setForeground(QColor::fromRgb(0x55, 0xff, 0xff));
|
|
return fmt;
|
|
}
|
|
case C_KEYWORD:
|
|
{
|
|
QTextCharFormat fmt;
|
|
fmt.setForeground(QColor::fromRgb(0xff, 0xff, 0x55));
|
|
return fmt;
|
|
}
|
|
case C_REMOVED_LINE:
|
|
Q_FALLTHROUGH();
|
|
case C_VISUAL_WHITESPACE:
|
|
break;
|
|
}
|
|
|
|
return QTextCharFormat();
|
|
}
|
|
|
|
SyntaxHighlighter::SyntaxHighlighter(QObject *p)
|
|
: QSyntaxHighlighter(p)
|
|
{
|
|
|
|
}
|
|
|
|
void SyntaxHighlighter::highlightBlock(const QString &text)
|
|
{
|
|
if (m_keywords.isEmpty()) {
|
|
const auto keywords = QtQuick3DEditorHelpers::CustomMaterial::preprocessorVars();
|
|
for (const auto &kw : keywords)
|
|
m_keywords.insert(kw);
|
|
}
|
|
if (m_argumentKeywords.isEmpty()) {
|
|
const auto args = QtQuick3DEditorHelpers::CustomMaterial::reservedArgumentNames();
|
|
for (const auto &arg : args)
|
|
m_argumentKeywords.insert(arg);
|
|
}
|
|
const int previousState = previousBlockState();
|
|
int state = 0;
|
|
if (previousState != -1)
|
|
state = previousState & 0xff;
|
|
|
|
const QByteArray data = text.toLatin1();
|
|
GLSL::Lexer lex(/*engine=*/ nullptr, data.constData(), data.size());
|
|
lex.setState(state);
|
|
lex.setScanKeywords(false);
|
|
lex.setScanComments(true);
|
|
|
|
lex.setVariant(GLSL::Lexer::Variant_GLSL_400);
|
|
|
|
QList<GLSL::Token> tokens;
|
|
GLSL::Token tk;
|
|
do {
|
|
lex.yylex(&tk);
|
|
tokens.append(tk);
|
|
} while (tk.isNot(GLSL::Parser::EOF_SYMBOL));
|
|
|
|
state = lex.state(); // refresh the state
|
|
|
|
if (tokens.isEmpty()) {
|
|
setCurrentBlockState(previousState);
|
|
if (!text.isEmpty()) // the empty line can still contain whitespace
|
|
setFormat(0, text.size(), formatForCategory(C_VISUAL_WHITESPACE));
|
|
return;
|
|
}
|
|
|
|
for (int i = 0, end = tokens.size(); i != end; ++i) {
|
|
const GLSL::Token &tk = tokens.at(i);
|
|
|
|
int previousTokenEnd = 0;
|
|
if (i != 0) {
|
|
// mark the whitespaces
|
|
previousTokenEnd = tokens.at(i - 1).begin() + tokens.at(i - 1).length;
|
|
}
|
|
|
|
if (previousTokenEnd != tk.begin())
|
|
setFormat(previousTokenEnd, tk.begin() - previousTokenEnd, formatForCategory(C_VISUAL_WHITESPACE));
|
|
|
|
if (tk.is(GLSL::Parser::T_NUMBER)) {
|
|
setFormat(tk.begin(), tk.length, formatForCategory(C_NUMBER));
|
|
} else if (tk.is(GLSL::Parser::T_COMMENT)) {
|
|
highlightLine(text, tk.begin(), tk.length, formatForCategory(C_COMMENT));
|
|
} else if (tk.is(GLSL::Parser::T_IDENTIFIER)) {
|
|
int kind = lex.findKeyword(data.constData() + tk.position, tk.length);
|
|
if (kind == GLSL::Parser::T_IDENTIFIER) {
|
|
if (m_keywords.contains(QByteArrayView(data.constData() + tk.position, tk.length)))
|
|
setFormat(tk.position, tk.length, formatForCategory(C_PREPROCESSOR));
|
|
if (m_argumentKeywords.contains(QByteArrayView(data.constData() + tk.position, tk.length)))
|
|
setFormat(tk.position, tk.length, formatForCategory(C_PARAMETER));
|
|
}
|
|
if (kind == GLSL::Parser::T_RESERVED)
|
|
setFormat(tk.position, tk.length, formatForCategory(GLSLReservedKeyword));
|
|
else if (kind != GLSL::Parser::T_IDENTIFIER)
|
|
setFormat(tk.position, tk.length, formatForCategory(C_KEYWORD));
|
|
}
|
|
}
|
|
|
|
// mark the trailing white spaces
|
|
{
|
|
const GLSL::Token tk = tokens.last();
|
|
const int lastTokenEnd = tk.begin() + tk.length;
|
|
if (text.size() > lastTokenEnd)
|
|
highlightLine(text, lastTokenEnd, text.size() - lastTokenEnd, QTextCharFormat());
|
|
}
|
|
}
|
|
|
|
void SyntaxHighlighter::highlightLine(const QString &text, int position, int length,
|
|
const QTextCharFormat &format)
|
|
{
|
|
const QTextCharFormat visualSpaceFormat = formatForCategory(C_VISUAL_WHITESPACE);
|
|
|
|
const int end = position + length;
|
|
int index = position;
|
|
|
|
while (index != end) {
|
|
const bool isSpace = text.at(index).isSpace();
|
|
const int start = index;
|
|
|
|
do { ++index; }
|
|
while (index != end && text.at(index).isSpace() == isSpace);
|
|
|
|
const int tokenLength = index - start;
|
|
if (isSpace)
|
|
setFormat(start, tokenLength, visualSpaceFormat);
|
|
else if (format.isValid())
|
|
setFormat(start, tokenLength, format);
|
|
}
|
|
}
|
|
|
|
QQuickTextDocument *SyntaxHighlighter::document() const
|
|
{
|
|
return m_quickTextDocument;
|
|
}
|
|
|
|
void SyntaxHighlighter::setDocument(QQuickTextDocument *newDocument)
|
|
{
|
|
if (m_quickTextDocument == newDocument)
|
|
return;
|
|
|
|
m_quickTextDocument = newDocument;
|
|
QSyntaxHighlighter::setDocument(m_quickTextDocument != nullptr ? m_quickTextDocument->textDocument() : nullptr);
|
|
|
|
emit documentChanged();
|
|
}
|
|
|
|
QT_END_NAMESPACE
|