summaryrefslogtreecommitdiff
path: root/doc/src/examples/syntaxhighlighter.qdoc
blob: 76674840b419fc0c3a7de2d31eea31a130ab5cde (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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights.  These rights are described in the Nokia Qt LGPL
** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \example richtext/syntaxhighlighter
    \title Syntax Highlighter Example

    The Syntax Highlighter example shows how to perform simple syntax
    highlighting by subclassing the QSyntaxHighlighter class.

    \image syntaxhighlighter-example.png

    The Syntax Highlighter application displays C++ files with custom
    syntax highlighting.

    The example consists of two classes:

    \list
        \o The \c Highlighter class defines and applies the
           highlighting rules.
        \o The \c MainWindow widget is the application's main window.
    \endlist

    We will first review the \c Highlighter class to see how you can
    customize the QSyntaxHighlighter class to fit your preferences,
    then we will take a look at the relevant parts of the \c
    MainWindow class to see how you can use your custom highlighter
    class in an application.

    \section1 Highlighter Class Definition

    \snippet examples/richtext/syntaxhighlighter/highlighter.h 0

    To provide your own syntax highlighting, you must subclass
    QSyntaxHighlighter, reimplement the \l
    {QSyntaxHighlighter::highlightBlock()}{highlightBlock()} function,
    and define your own highlighting rules.

    We have chosen to store our highlighting rules using a private
    struct: A rule consists of a QRegExp pattern and a QTextCharFormat
    instance. The various rules are then stored using a QVector.

    The QTextCharFormat class provides formatting information for
    characters in a QTextDocument specifying the visual properties of
    the text, as well as information about its role in a hypertext
    document. In this example, we will only define the font weight and
    color using the QTextCharFormat::setFontWeight() and
    QTextCharFormat::setForeground() functions.

    \section1 Highlighter Class Implementation

    When subclassing the QSyntaxHighlighter class you must pass the
    parent parameter to the base class constructor. The parent is the
    text document upon which the syntax highligning will be
    applied. In this example, we have also chosen to define our
    highlighting rules in the constructor:

    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 0
    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 1

    First we define a keyword rule which recognizes the most common
    C++ keywords. We give the \c keywordFormat a bold, dark blue
    font. For each keyword, we assign the keyword and the specified
    format to a HighlightingRule object and append the object to our
    list of rules.

    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 2
    \codeline
    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 4
    \codeline
    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 5

    Then we create a format that we will apply to Qt class names. The
    class names will be rendered with a dark magenta color and a bold
    style. We specify a string pattern that is actually a regular
    expression capturing all Qt class names. Then we assign the
    regular expression and the specified format to a HighlightingRule
    object and append the object to our list of rules.

    We also define highlighting rules for quotations and functions
    using the same approach: The patterns have the form of regular
    expressions and are stored in HighlightingRule objects with the
    associated format.

    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 3
    \codeline
    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 6

    The C++ language has two variations of comments: The single line
    comment (\c //) and the multiline comment (\c{/*...}\starslash). The single
    line comment can easily be defined through a highlighting rule
    similar to the previous ones. But the multiline comment needs
    special care due to the design of the QSyntaxHighlighter class.

    After a QSyntaxHighlighter object is created, its \l
    {QSyntaxHighlighter::highlightBlock()}{highlightBlock()} function
    will be called automatically whenever it is necessary by the rich
    text engine, highlighting the given text block. The problem
    appears when a comment spans several text blocks. We will take a
    closer look at how this problem can be solved when reviewing the
    implementation of the \c Highlighter::highlightBlock()
    function. At this point we only specify the multiline comment's
    color.

    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 7

    The highlightBlock() function is called automatically whenever it
    is necessary by the rich text engine, i.e. when there are text
    blocks that have changed.

    First we apply the syntax highlighting rules that we stored in the
    \c highlightingRules vector. For each rule (i.e. for each
    HighlightingRule object) we search for the pattern in the given
    textblock using the QString::indexOf() function. When the first
    occurrence of the pattern is found, we use the
    QRegExp::matchedLength() function to determine the string that
    will be formatted. QRegExp::matchedLength() returns the length of
    the last matched string, or -1 if there was no match.

    To perform the actual formatting the QSyntaxHighlighter class
    provides the \l {QSyntaxHighlighter::setFormat()}{setFormat()}
    function. This function operates on the text block that is passed
    as argument to the \c highlightBlock() function. The specified
    format is applied to the text from the given start position for
    the given length. The formatting properties set in the given
    format are merged at display time with the formatting information
    stored directly in the document. Note that the document itself
    remains unmodified by the format set through this function.

    This process is repeated until the last occurrence of the pattern
    in the current text block is found.

    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 8

    To deal with constructs that can span several text blocks (like
    the C++ multiline comment), it is necessary to know the end state
    of the previous text block (e.g. "in comment"). Inside your \c
    highlightBlock() implementation you can query the end state of the
    previous text block using the
    QSyntaxHighlighter::previousBlockState() function. After parsing
    the block you can save the last state using
    QSyntaxHighlighter::setCurrentBlockState().

    The \l
    {QSyntaxHighlighter::previousBlockState()}{previousBlockState()}
    function return an int value. If no state is set, the returned
    value is -1. You can designate any other value to identify any
    given state using the \l
    {QSyntaxHighlighter::setCurrentBlockState()}{setCurrentBlockState()}
    function. Once the state is set, the QTextBlock keeps that value
    until it is set again or until the corresponding paragraph of text
    is deleted.

    In this example we have chosen to use 0 to represent the "not in
    comment" state, and 1 for the "in comment" state. When the stored
    syntax highlighting rules are applied we initialize the current
    block state to 0.

    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 9

    If the previous block state was "in comment" (\c
    {previousBlockState() == 1}), we start the search for an end
    expression at the beginning of the text block. If the
    previousBlockState() returns 0, we start the search at the
    location of the first occurrence of a start expression.

    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 10
    \snippet examples/richtext/syntaxhighlighter/highlighter.cpp 11

    When an end expression is found, we calculate the length of the
    comment and apply the multiline comment format. Then we search for
    the next occurrence of the start expression and repeat the
    process.  If no end expression can be found in the current text
    block we set the current block state to 1, i.e. "in comment".

    This completes the \c Highlighter class implementation; it is now
    ready for use.

    \section1 MainWindow Class Definition

    Using a QSyntaxHighlighter subclass is simple; just provide your
    application with an instance of the class and pass it the document
    upon which you want the highlighting to be applied.

    \snippet examples/richtext/syntaxhighlighter/mainwindow.h 0

    In this example we declare a pointer to a \c Highlighter instance
    which we later will initialize in the private \c setupEditor()
    function.

    \section1 MainWindow Class Implementation

    The constructor of the main window is straight forward. We first
    set up the menus, then we initialize the editor and make it the
    central widget of the application. Finally we set the main
    window's title.

    \snippet examples/richtext/syntaxhighlighter/mainwindow.cpp 0

    We initialize and install the \c Highlighter object in the private
    setupEditor() convenience function:

    \snippet examples/richtext/syntaxhighlighter/mainwindow.cpp 1

    First we create the font we want to use in the editor, then we
    create the editor itself which is an instance of the QTextEdit
    class. Before we initialize the editor with the \c MainWindow
    class definition file, we create a \c Highlighter instance passing
    the editor's document as argument. This is the document that the
    highlighting will be applied to. Then we are done.

    A QSyntaxHighlighter object can only be installed on one document
    at the time, but you can easily reinstall the highlighter on
    another document using the QSyntaxHighlighter::setDocument()
    function. The QSyntaxHighlighter class also provides the \l
    {QSyntaxHighlighter::document()}{document()} function which
    returns the currently set document.
*/