2018-11-08 11:39:48 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2019 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
|
**
|
|
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "highlighter.h"
|
|
|
|
|
|
|
|
|
|
#include "highlightersettings.h"
|
2019-05-03 08:48:25 +02:00
|
|
|
#include "tabsettings.h"
|
2021-06-21 08:46:58 +02:00
|
|
|
#include "textdocumentlayout.h"
|
2019-11-04 10:03:27 +01:00
|
|
|
#include "texteditor.h"
|
2021-06-21 08:46:58 +02:00
|
|
|
#include "texteditorsettings.h"
|
2018-11-08 11:39:48 +01:00
|
|
|
|
2019-11-04 10:03:27 +01:00
|
|
|
#include <coreplugin/editormanager/documentmodel.h>
|
2018-11-08 11:39:48 +01:00
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/messagemanager.h>
|
2019-02-06 10:43:34 +01:00
|
|
|
#include <utils/mimetypes/mimedatabase.h>
|
2019-06-21 14:16:54 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2021-06-21 08:46:58 +02:00
|
|
|
#include <utils/stylehelper.h>
|
2018-11-08 11:39:48 +01:00
|
|
|
|
2019-03-04 09:12:20 +01:00
|
|
|
#include <DefinitionDownloader>
|
2019-05-03 08:48:25 +02:00
|
|
|
#include <FoldingRegion>
|
2021-06-21 08:46:58 +02:00
|
|
|
#include <Format>
|
2018-11-08 11:39:48 +01:00
|
|
|
#include <Repository>
|
|
|
|
|
#include <SyntaxHighlighter>
|
|
|
|
|
|
|
|
|
|
#include <QDir>
|
2021-06-21 08:46:58 +02:00
|
|
|
#include <QLoggingCategory>
|
2018-11-08 11:39:48 +01:00
|
|
|
#include <QMetaEnum>
|
|
|
|
|
|
|
|
|
|
using namespace TextEditor;
|
|
|
|
|
|
2021-06-21 08:46:58 +02:00
|
|
|
static Q_LOGGING_CATEGORY(highlighterLog, "qtc.editor.highlighter", QtWarningMsg)
|
|
|
|
|
|
2019-02-07 13:40:39 +01:00
|
|
|
static const char kDefinitionForMimeType[] = "definitionForMimeType";
|
|
|
|
|
static const char kDefinitionForExtension[] = "definitionForExtension";
|
|
|
|
|
static const char kDefinitionForFilePath[] = "definitionForFilePath";
|
|
|
|
|
|
2018-11-08 11:39:48 +01:00
|
|
|
KSyntaxHighlighting::Repository *highlightRepository()
|
|
|
|
|
{
|
|
|
|
|
static KSyntaxHighlighting::Repository *repository = nullptr;
|
|
|
|
|
if (!repository) {
|
|
|
|
|
repository = new KSyntaxHighlighting::Repository();
|
|
|
|
|
repository->addCustomSearchPath(TextEditorSettings::highlighterSettings().definitionFilesPath());
|
2021-06-29 17:57:49 +02:00
|
|
|
const Utils::FilePath dir = Core::ICore::resourcePath("generic-highlighter/syntax");
|
|
|
|
|
if (dir.exists())
|
|
|
|
|
repository->addCustomSearchPath(dir.parentDir().path());
|
2018-11-08 11:39:48 +01:00
|
|
|
}
|
|
|
|
|
return repository;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TextStyle categoryForTextStyle(int style)
|
|
|
|
|
{
|
|
|
|
|
switch (style) {
|
|
|
|
|
case KSyntaxHighlighting::Theme::Normal: return C_TEXT;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Keyword: return C_KEYWORD;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Function: return C_FUNCTION;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Variable: return C_LOCAL;
|
|
|
|
|
case KSyntaxHighlighting::Theme::ControlFlow: return C_KEYWORD;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Operator: return C_OPERATOR;
|
|
|
|
|
case KSyntaxHighlighting::Theme::BuiltIn: return C_PRIMITIVE_TYPE;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Extension: return C_GLOBAL;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Preprocessor: return C_PREPROCESSOR;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Attribute: return C_LOCAL;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Char: return C_STRING;
|
|
|
|
|
case KSyntaxHighlighting::Theme::SpecialChar: return C_STRING;
|
|
|
|
|
case KSyntaxHighlighting::Theme::String: return C_STRING;
|
|
|
|
|
case KSyntaxHighlighting::Theme::VerbatimString: return C_STRING;
|
|
|
|
|
case KSyntaxHighlighting::Theme::SpecialString: return C_STRING;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Import: return C_PREPROCESSOR;
|
|
|
|
|
case KSyntaxHighlighting::Theme::DataType: return C_TYPE;
|
|
|
|
|
case KSyntaxHighlighting::Theme::DecVal: return C_NUMBER;
|
|
|
|
|
case KSyntaxHighlighting::Theme::BaseN: return C_NUMBER;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Float: return C_NUMBER;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Constant: return C_KEYWORD;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Comment: return C_COMMENT;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Documentation: return C_DOXYGEN_COMMENT;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Annotation: return C_DOXYGEN_TAG;
|
|
|
|
|
case KSyntaxHighlighting::Theme::CommentVar: return C_DOXYGEN_TAG;
|
|
|
|
|
case KSyntaxHighlighting::Theme::RegionMarker: return C_PREPROCESSOR;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Information: return C_WARNING;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Warning: return C_WARNING;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Alert: return C_ERROR;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Error: return C_ERROR;
|
|
|
|
|
case KSyntaxHighlighting::Theme::Others: return C_TEXT;
|
|
|
|
|
}
|
|
|
|
|
return C_TEXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Highlighter::Highlighter()
|
|
|
|
|
{
|
|
|
|
|
setTextFormatCategories(QMetaEnum::fromType<KSyntaxHighlighting::Theme::TextStyle>().keyCount(),
|
|
|
|
|
&categoryForTextStyle);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 08:50:16 +01:00
|
|
|
Highlighter::Definition Highlighter::definitionForName(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
return highlightRepository()->definitionForName(name);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 10:52:32 +01:00
|
|
|
Highlighter::Definitions Highlighter::definitionsForDocument(const TextDocument *document)
|
|
|
|
|
{
|
2019-06-21 14:16:54 +02:00
|
|
|
QTC_ASSERT(document, return {});
|
2020-03-24 09:17:57 +01:00
|
|
|
// First try to find definitions for the file path, only afterwards try the MIME type.
|
|
|
|
|
// An example where that is important is if there was a definition for "*.rb.xml", which
|
|
|
|
|
// cannot be referred to with a MIME type (since there is none), but there is the definition
|
|
|
|
|
// for XML files, which specifies a MIME type in addition to a glob pattern.
|
|
|
|
|
// If we check the MIME type first and then skip the pattern, the definition for "*.rb.xml" is
|
|
|
|
|
// never considered.
|
|
|
|
|
// The KSyntaxHighlighting CLI also completely ignores MIME types.
|
2020-09-25 08:08:19 +02:00
|
|
|
const Utils::FilePath &filePath = document->filePath();
|
|
|
|
|
Definitions definitions = definitionsForFileName(filePath);
|
|
|
|
|
if (definitions.isEmpty()) {
|
|
|
|
|
// check for *.in filename since those are usually used for
|
|
|
|
|
// cmake configure_file input filenames without the .in extension
|
|
|
|
|
if (filePath.endsWith(".in")) {
|
|
|
|
|
definitions = definitionsForFileName(
|
2021-06-04 07:59:00 +02:00
|
|
|
Utils::FilePath::fromString(filePath.completeBaseName()));
|
2020-09-25 08:08:19 +02:00
|
|
|
}
|
2021-06-21 09:28:06 +02:00
|
|
|
if (filePath.fileName() == "qtquickcontrols2.conf")
|
|
|
|
|
definitions = definitionsForFileName(filePath.stringAppended(".ini"));
|
2020-09-25 08:08:19 +02:00
|
|
|
}
|
|
|
|
|
if (definitions.isEmpty()) {
|
|
|
|
|
const Utils::MimeType &mimeType = Utils::mimeTypeForName(document->mimeType());
|
|
|
|
|
if (mimeType.isValid())
|
|
|
|
|
definitions = definitionsForMimeType(mimeType.name());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return definitions;
|
2019-02-06 10:52:32 +01:00
|
|
|
}
|
|
|
|
|
|
2019-02-07 13:40:39 +01:00
|
|
|
static Highlighter::Definition definitionForSetting(const QString &settingsKey,
|
|
|
|
|
const QString &mapKey)
|
|
|
|
|
{
|
|
|
|
|
QSettings *settings = Core::ICore::settings();
|
|
|
|
|
settings->beginGroup(Constants::HIGHLIGHTER_SETTINGS_CATEGORY);
|
|
|
|
|
const QString &definitionName = settings->value(settingsKey).toMap().value(mapKey).toString();
|
|
|
|
|
settings->endGroup();
|
|
|
|
|
return Highlighter::definitionForName(definitionName);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 10:52:32 +01:00
|
|
|
Highlighter::Definitions Highlighter::definitionsForMimeType(const QString &mimeType)
|
|
|
|
|
{
|
2019-02-07 13:40:39 +01:00
|
|
|
Definitions definitions = highlightRepository()->definitionsForMimeType(mimeType).toList();
|
|
|
|
|
if (definitions.size() > 1) {
|
|
|
|
|
const Definition &rememberedDefinition = definitionForSetting(kDefinitionForMimeType,
|
|
|
|
|
mimeType);
|
|
|
|
|
if (rememberedDefinition.isValid() && definitions.contains(rememberedDefinition))
|
|
|
|
|
definitions = {rememberedDefinition};
|
|
|
|
|
}
|
|
|
|
|
return definitions;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
Highlighter::Definitions Highlighter::definitionsForFileName(const Utils::FilePath &fileName)
|
2019-02-07 13:40:39 +01:00
|
|
|
{
|
|
|
|
|
Definitions definitions
|
|
|
|
|
= highlightRepository()->definitionsForFileName(fileName.fileName()).toList();
|
|
|
|
|
|
|
|
|
|
if (definitions.size() > 1) {
|
2021-06-04 09:13:49 +02:00
|
|
|
const QString &fileExtension = fileName.completeSuffix();
|
2019-02-07 13:40:39 +01:00
|
|
|
const Definition &rememberedDefinition
|
|
|
|
|
= fileExtension.isEmpty()
|
|
|
|
|
? definitionForSetting(kDefinitionForFilePath,
|
2021-06-09 08:35:53 +02:00
|
|
|
fileName.absoluteFilePath().toString())
|
2019-02-07 13:40:39 +01:00
|
|
|
: definitionForSetting(kDefinitionForExtension, fileExtension);
|
|
|
|
|
if (rememberedDefinition.isValid() && definitions.contains(rememberedDefinition))
|
|
|
|
|
definitions = {rememberedDefinition};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return definitions;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 08:08:44 +01:00
|
|
|
void Highlighter::rememberDefinitionForDocument(const Highlighter::Definition &definition,
|
|
|
|
|
const TextDocument *document)
|
2019-02-07 13:40:39 +01:00
|
|
|
{
|
2019-06-21 14:16:54 +02:00
|
|
|
QTC_ASSERT(document, return );
|
2019-02-07 13:40:39 +01:00
|
|
|
if (!definition.isValid())
|
|
|
|
|
return;
|
|
|
|
|
const QString &mimeType = document->mimeType();
|
2021-06-09 08:35:53 +02:00
|
|
|
const Utils::FilePath &path = document->filePath();
|
|
|
|
|
const QString &fileExtension = path.completeSuffix();
|
2019-02-07 13:40:39 +01:00
|
|
|
QSettings *settings = Core::ICore::settings();
|
|
|
|
|
settings->beginGroup(Constants::HIGHLIGHTER_SETTINGS_CATEGORY);
|
2021-06-09 08:35:53 +02:00
|
|
|
const Definitions &fileNameDefinitions = definitionsForFileName(path);
|
2020-08-19 06:52:24 +02:00
|
|
|
if (fileNameDefinitions.contains(definition)) {
|
|
|
|
|
if (!fileExtension.isEmpty()) {
|
|
|
|
|
const QString id(kDefinitionForExtension);
|
|
|
|
|
QMap<QString, QVariant> map = settings->value(id).toMap();
|
|
|
|
|
map.insert(fileExtension, definition.name());
|
|
|
|
|
settings->setValue(id, map);
|
|
|
|
|
} else if (!path.isEmpty()) {
|
|
|
|
|
const QString id(kDefinitionForFilePath);
|
|
|
|
|
QMap<QString, QVariant> map = settings->value(id).toMap();
|
2021-06-09 08:35:53 +02:00
|
|
|
map.insert(path.absoluteFilePath().toString(), definition.name());
|
2020-08-19 06:52:24 +02:00
|
|
|
settings->setValue(id, map);
|
|
|
|
|
}
|
|
|
|
|
} else if (!mimeType.isEmpty()) {
|
2019-02-07 13:40:39 +01:00
|
|
|
const QString id(kDefinitionForMimeType);
|
|
|
|
|
QMap<QString, QVariant> map = settings->value(id).toMap();
|
|
|
|
|
map.insert(mimeType, definition.name());
|
|
|
|
|
settings->setValue(id, map);
|
|
|
|
|
}
|
|
|
|
|
settings->endGroup();
|
2019-02-06 10:52:32 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-24 08:08:44 +01:00
|
|
|
void Highlighter::clearDefinitionForDocumentCache()
|
2019-02-06 10:52:32 +01:00
|
|
|
{
|
2019-02-07 13:40:39 +01:00
|
|
|
QSettings *settings = Core::ICore::settings();
|
|
|
|
|
settings->beginGroup(Constants::HIGHLIGHTER_SETTINGS_CATEGORY);
|
|
|
|
|
settings->remove(kDefinitionForMimeType);
|
|
|
|
|
settings->remove(kDefinitionForExtension);
|
|
|
|
|
settings->remove(kDefinitionForFilePath);
|
|
|
|
|
settings->endGroup();
|
2019-02-06 10:52:32 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
void Highlighter::addCustomHighlighterPath(const Utils::FilePath &path)
|
2018-11-08 11:39:48 +01:00
|
|
|
{
|
|
|
|
|
highlightRepository()->addCustomSearchPath(path.toString());
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-04 10:03:27 +01:00
|
|
|
void Highlighter::downloadDefinitions(std::function<void()> callback) {
|
2018-11-08 11:39:48 +01:00
|
|
|
auto downloader =
|
|
|
|
|
new KSyntaxHighlighting::DefinitionDownloader(highlightRepository());
|
2020-12-17 09:21:55 +01:00
|
|
|
connect(downloader, &KSyntaxHighlighting::DefinitionDownloader::done, [downloader, callback]() {
|
|
|
|
|
Core::MessageManager::writeFlashing(tr("Highlighter updates: done"));
|
|
|
|
|
downloader->deleteLater();
|
|
|
|
|
reload();
|
|
|
|
|
if (callback)
|
|
|
|
|
callback();
|
|
|
|
|
});
|
2018-11-08 11:39:48 +01:00
|
|
|
connect(downloader,
|
|
|
|
|
&KSyntaxHighlighting::DefinitionDownloader::informationMessage,
|
|
|
|
|
[](const QString &message) {
|
2020-12-17 09:21:55 +01:00
|
|
|
Core::MessageManager::writeSilently(tr("Highlighter updates:") + ' ' + message);
|
2018-11-08 11:39:48 +01:00
|
|
|
});
|
2020-12-17 09:21:55 +01:00
|
|
|
Core::MessageManager::writeDisrupting(tr("Highlighter updates: starting"));
|
2018-11-08 11:39:48 +01:00
|
|
|
downloader->start();
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-04 10:03:27 +01:00
|
|
|
void Highlighter::reload()
|
|
|
|
|
{
|
|
|
|
|
highlightRepository()->reload();
|
|
|
|
|
for (auto editor : Core::DocumentModel::editorsForOpenedDocuments()) {
|
|
|
|
|
if (auto textEditor = qobject_cast<BaseTextEditor *>(editor)) {
|
|
|
|
|
if (qobject_cast<Highlighter *>(textEditor->textDocument()->syntaxHighlighter()))
|
|
|
|
|
textEditor->editorWidget()->configureGenericHighlighter();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-08 11:39:48 +01:00
|
|
|
void Highlighter::handleShutdown()
|
|
|
|
|
{
|
|
|
|
|
delete highlightRepository();
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 10:03:09 +01:00
|
|
|
static bool isOpeningParenthesis(QChar c)
|
|
|
|
|
{
|
|
|
|
|
return c == QLatin1Char('{') || c == QLatin1Char('[') || c == QLatin1Char('(');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isClosingParenthesis(QChar c)
|
|
|
|
|
{
|
|
|
|
|
return c == QLatin1Char('}') || c == QLatin1Char(']') || c == QLatin1Char(')');
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-08 11:39:48 +01:00
|
|
|
void Highlighter::highlightBlock(const QString &text)
|
|
|
|
|
{
|
2020-01-07 12:05:16 +01:00
|
|
|
if (!definition().isValid()) {
|
|
|
|
|
formatSpaces(text);
|
2018-11-08 11:39:48 +01:00
|
|
|
return;
|
2020-01-07 12:05:16 +01:00
|
|
|
}
|
2019-06-05 09:26:12 +02:00
|
|
|
QTextBlock block = currentBlock();
|
2019-05-03 08:48:25 +02:00
|
|
|
KSyntaxHighlighting::State state;
|
2019-06-05 09:26:12 +02:00
|
|
|
TextDocumentLayout::setBraceDepth(block, TextDocumentLayout::braceDepth(block.previous()));
|
2019-12-04 08:19:53 +01:00
|
|
|
if (TextBlockUserData *data = TextDocumentLayout::textUserData(block)) {
|
2019-05-03 08:48:25 +02:00
|
|
|
state = data->syntaxState();
|
|
|
|
|
data->setFoldingStartIncluded(false);
|
|
|
|
|
data->setFoldingEndIncluded(false);
|
|
|
|
|
}
|
2018-11-08 11:39:48 +01:00
|
|
|
state = highlightLine(text, state);
|
2019-05-03 08:48:25 +02:00
|
|
|
const QTextBlock nextBlock = block.next();
|
2019-03-07 10:03:09 +01:00
|
|
|
|
|
|
|
|
Parentheses parentheses;
|
|
|
|
|
int pos = 0;
|
|
|
|
|
for (const QChar &c : text) {
|
|
|
|
|
if (isOpeningParenthesis(c))
|
|
|
|
|
parentheses.push_back(Parenthesis(Parenthesis::Opened, c, pos));
|
|
|
|
|
else if (isClosingParenthesis(c))
|
|
|
|
|
parentheses.push_back(Parenthesis(Parenthesis::Closed, c, pos));
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
TextDocumentLayout::setParentheses(currentBlock(), parentheses);
|
|
|
|
|
|
2019-05-03 08:48:25 +02:00
|
|
|
if (nextBlock.isValid()) {
|
|
|
|
|
TextBlockUserData *data = TextDocumentLayout::userData(nextBlock);
|
2019-06-05 09:26:12 +02:00
|
|
|
if (data->syntaxState() != state) {
|
|
|
|
|
data->setSyntaxState(state);
|
|
|
|
|
setCurrentBlockState(currentBlockState() ^ 1); // force rehighlight of next block
|
|
|
|
|
}
|
|
|
|
|
data->setFoldingIndent(TextDocumentLayout::braceDepth(block));
|
2019-05-03 08:48:25 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-14 10:04:33 +01:00
|
|
|
formatSpaces(text);
|
2018-11-08 11:39:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Highlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)
|
|
|
|
|
{
|
2019-07-02 13:04:46 +02:00
|
|
|
const KSyntaxHighlighting::Theme defaultTheme;
|
|
|
|
|
QTextCharFormat qformat = formatForCategory(format.textStyle());
|
|
|
|
|
|
|
|
|
|
if (format.hasTextColor(defaultTheme)) {
|
|
|
|
|
const QColor textColor = format.textColor(defaultTheme);
|
|
|
|
|
if (format.hasBackgroundColor(defaultTheme)) {
|
|
|
|
|
const QColor backgroundColor = format.hasBackgroundColor(defaultTheme);
|
2019-11-14 14:12:59 +01:00
|
|
|
if (Utils::StyleHelper::isReadableOn(backgroundColor, textColor)) {
|
2019-07-02 13:04:46 +02:00
|
|
|
qformat.setForeground(textColor);
|
|
|
|
|
qformat.setBackground(backgroundColor);
|
2019-11-14 14:12:59 +01:00
|
|
|
} else if (Utils::StyleHelper::isReadableOn(qformat.background().color(), textColor)) {
|
2019-07-02 13:04:46 +02:00
|
|
|
qformat.setForeground(textColor);
|
|
|
|
|
}
|
2019-11-14 14:12:59 +01:00
|
|
|
} else if (Utils::StyleHelper::isReadableOn(qformat.background().color(), textColor)) {
|
2019-07-02 13:04:46 +02:00
|
|
|
qformat.setForeground(textColor);
|
|
|
|
|
}
|
|
|
|
|
} else if (format.hasBackgroundColor(defaultTheme)) {
|
|
|
|
|
const QColor backgroundColor = format.hasBackgroundColor(defaultTheme);
|
2019-11-14 14:12:59 +01:00
|
|
|
if (Utils::StyleHelper::isReadableOn(backgroundColor, qformat.foreground().color()))
|
2019-07-02 13:04:46 +02:00
|
|
|
qformat.setBackground(backgroundColor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (format.isBold(defaultTheme))
|
|
|
|
|
qformat.setFontWeight(QFont::Bold);
|
|
|
|
|
|
|
|
|
|
if (format.isItalic(defaultTheme))
|
|
|
|
|
qformat.setFontItalic(true);
|
|
|
|
|
|
|
|
|
|
if (format.isUnderline(defaultTheme))
|
|
|
|
|
qformat.setFontUnderline(true);
|
|
|
|
|
|
|
|
|
|
if (format.isStrikeThrough(defaultTheme))
|
|
|
|
|
qformat.setFontStrikeOut(true);
|
|
|
|
|
setFormat(offset, length, qformat);
|
2018-11-08 11:39:48 +01:00
|
|
|
}
|
2019-05-03 08:48:25 +02:00
|
|
|
|
|
|
|
|
void Highlighter::applyFolding(int offset,
|
|
|
|
|
int length,
|
|
|
|
|
KSyntaxHighlighting::FoldingRegion region)
|
|
|
|
|
{
|
|
|
|
|
if (!region.isValid())
|
|
|
|
|
return;
|
2019-06-05 09:26:12 +02:00
|
|
|
QTextBlock block = currentBlock();
|
2019-05-03 08:48:25 +02:00
|
|
|
const QString &text = block.text();
|
|
|
|
|
TextBlockUserData *data = TextDocumentLayout::userData(currentBlock());
|
|
|
|
|
const bool fromStart = TabSettings::firstNonSpace(text) == offset;
|
|
|
|
|
const bool toEnd = (offset + length) == (text.length() - TabSettings::trailingWhitespaces(text));
|
|
|
|
|
if (region.type() == KSyntaxHighlighting::FoldingRegion::Begin) {
|
2021-06-21 08:46:58 +02:00
|
|
|
const int newBraceDepth = TextDocumentLayout::braceDepth(block) + 1;
|
|
|
|
|
TextDocumentLayout::setBraceDepth(block, newBraceDepth);
|
|
|
|
|
qCDebug(highlighterLog) << "Found folding start from '" << offset << "' to '" << length
|
|
|
|
|
<< "' resulting in the bracedepth '" << newBraceDepth << "' in :";
|
|
|
|
|
qCDebug(highlighterLog) << text;
|
|
|
|
|
// if there is only a folding begin marker in the line move the current block into the fold
|
|
|
|
|
if (fromStart && toEnd && length <= 1) {
|
2019-06-05 09:26:12 +02:00
|
|
|
data->setFoldingIndent(TextDocumentLayout::braceDepth(block));
|
2019-05-03 08:48:25 +02:00
|
|
|
data->setFoldingStartIncluded(true);
|
|
|
|
|
}
|
|
|
|
|
} else if (region.type() == KSyntaxHighlighting::FoldingRegion::End) {
|
2021-06-21 08:46:58 +02:00
|
|
|
const int newBraceDepth = qMax(0, TextDocumentLayout::braceDepth(block) - 1);
|
|
|
|
|
qCDebug(highlighterLog) << "Found folding end from '" << offset << "' to '" << length
|
|
|
|
|
<< "' resulting in the bracedepth '" << newBraceDepth << "' in :";
|
|
|
|
|
qCDebug(highlighterLog) << text;
|
|
|
|
|
TextDocumentLayout::setBraceDepth(block, newBraceDepth);
|
2019-05-03 08:48:25 +02:00
|
|
|
// if the folding end is at the end of the line move the current block into the fold
|
|
|
|
|
if (toEnd)
|
|
|
|
|
data->setFoldingEndIncluded(true);
|
|
|
|
|
else
|
2019-06-05 09:26:12 +02:00
|
|
|
data->setFoldingIndent(TextDocumentLayout::braceDepth(block));
|
2019-05-03 08:48:25 +02:00
|
|
|
}
|
|
|
|
|
}
|