aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/texteditor/syntaxhighlighter.h
blob: 94cee8a65eff35d875a21df6db9449dcfb05e81d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#pragma once

#include "texteditor_global.h"

#include <texteditor/texteditorconstants.h>
#include <texteditor/textdocumentlayout.h>

#include <KSyntaxHighlighting/Definition>

#include <QObject>
#include <QTextLayout>

#include <functional>
#include <climits>

QT_BEGIN_NAMESPACE
class QTextDocument;
class QSyntaxHighlighterPrivate;
class QTextCharFormat;
class QFont;
class QColor;
class QTextBlockUserData;
class QTextEdit;
QT_END_NAMESPACE

namespace TextEditor {

class FontSettings;
class SyntaxHighlighterPrivate;

class TEXTEDITOR_EXPORT SyntaxHighlighter : public QObject
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(SyntaxHighlighter)
public:
    SyntaxHighlighter(QObject *parent = nullptr);
    SyntaxHighlighter(QTextDocument *parent);
    SyntaxHighlighter(QTextEdit *parent);
    ~SyntaxHighlighter() override;

    void setDocument(QTextDocument *doc);
    QTextDocument *document() const;

    void setMimeType(const QString &mimeType);
    QString mimeType() const;

    static QList<QColor> generateColors(int n, const QColor &background);

    // Don't call in constructors of derived classes
    virtual void setFontSettings(const TextEditor::FontSettings &fontSettings);
    TextEditor::FontSettings fontSettings() const;

    enum State  {
        InProgress,
        Done
    };

    struct Result
    {
        void fillByBlock(const QTextBlock &block)
        {
            m_blockNumber = block.position();
            m_userState = block.userState();

            TextBlockUserData *userDate = TextDocumentLayout::textUserData(block);
            if (!userDate)
                return;

            m_hasBlockUserData = true;
            m_foldingIndent = userDate->foldingIndent();
            m_folded = userDate->folded();
            m_ifdefedOut = userDate->ifdefedOut();
            m_foldingStartIncluded = userDate->foldingStartIncluded();
            m_foldingEndIncluded = userDate->foldingEndIncluded();
            m_parentheses = userDate->parentheses();
            m_expectedRawStringSuffix = userDate->expectedRawStringSuffix();
        }

        void copyToBlock(QTextBlock &block) const
        {
            block.setUserState(m_userState);

            if (m_hasBlockUserData) {
                TextBlockUserData *data = TextDocumentLayout::userData(block);
                data->setExpectedRawStringSuffix(m_expectedRawStringSuffix);
                data->setFolded(m_folded);
                data->setFoldingIndent(m_foldingIndent);
                data->setFoldingStartIncluded(m_foldingStartIncluded);
                data->setFoldingEndIncluded(m_foldingEndIncluded);

                if (m_ifdefedOut)
                    data->setIfdefedOut();
                else
                    data->clearIfdefedOut();

                data->setParentheses(m_parentheses);
            }
        }

        int m_blockNumber;
        bool m_hasBlockUserData = false;

        int m_foldingIndent : 16;
        uint m_folded : 1;
        uint m_ifdefedOut : 1;
        uint m_foldingStartIncluded : 1;
        uint m_foldingEndIncluded : 1;

        Parentheses m_parentheses;
        QByteArray m_expectedRawStringSuffix;
        int m_userState = -1;
        QList<QTextLayout::FormatRange> m_formatRanges;

        State m_state = InProgress;
    };

    void setExtraFormats(const QTextBlock &block, const QList<QTextLayout::FormatRange> &formats);
    virtual void setLanguageFeaturesFlags(unsigned int /*flags*/) {}; // needed for CppHighlighting
    virtual void setEnabled(bool /*enabled*/) {}; // needed for DiffAndLogHighlighter
    virtual void setDefinitionName(const QString & /*definitionName*/) {} // needed for Highlighter

public slots:
    virtual void rehighlight();
    void rehighlightBlock(const QTextBlock &block);
    void clearExtraFormats(const QTextBlock &block);
    void clearAllExtraFormats();

protected:
    void setDefaultTextFormatCategories();
    void setTextFormatCategories(int count, std::function<TextStyle(int)> formatMapping);
    QTextCharFormat formatForCategory(int categoryIndex) const;
    QTextCharFormat whitespacified(const QTextCharFormat &fmt);
    QTextCharFormat asSyntaxHighlight(const QTextCharFormat &fmt);

    // implement in subclasses
    // default implementation highlights whitespace
    virtual void highlightBlock(const QString &text);

    void setFormat(int start, int count, const QTextCharFormat &format);
    void setFormat(int start, int count, const QColor &color);
    void setFormat(int start, int count, const QFont &font);
    QTextCharFormat format(int pos) const;

    void formatSpaces(const QString &text, int start = 0, int count = INT_MAX);
    void setFormatWithSpaces(const QString &text, int start, int count,
                             const QTextCharFormat &format);

    int previousBlockState() const;
    int currentBlockState() const;
    void setCurrentBlockState(int newState);

    void setCurrentBlockUserData(QTextBlockUserData *data);
    QTextBlockUserData *currentBlockUserData() const;

    QTextBlock currentBlock() const;

protected:
    virtual void documentChanged(QTextDocument * /*oldDoc*/, QTextDocument * /*newDoc*/) {};

signals:
    void resultsReady(const QList<Result> &result);

private:
    void setTextFormatCategories(const QList<std::pair<int, TextStyle>> &categories);
    void reformatBlocks(int from, int charsRemoved, int charsAdded);
    void delayedRehighlight();

    QScopedPointer<SyntaxHighlighterPrivate> d_ptr;

#ifdef WITH_TESTS
    friend class tst_highlighter;
    SyntaxHighlighter(QTextDocument *parent, const FontSettings &fontsettings);
#endif
};

} // namespace TextEditor