Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsyntaxhighlighter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#ifndef QT_NO_SYNTAXHIGHLIGHTER
7#include <private/qobject_p.h>
8#include <qtextdocument.h>
9#include <private/qtextdocument_p.h>
10#include <qtextlayout.h>
11#include <qpointer.h>
13#include <qtextobject.h>
14#include <qtextcursor.h>
15#include <qdebug.h>
16#include <qtimer.h>
17
18#include <algorithm>
19
21
23{
24 Q_DECLARE_PUBLIC(QSyntaxHighlighter)
25public:
29
30 QPointer<QTextDocument> doc;
31
32 void _q_reformatBlocks(int from, int charsRemoved, int charsAdded);
33 void reformatBlocks(int from, int charsRemoved, int charsAdded);
34 void reformatBlock(const QTextBlock &block);
35
37 {
38 QScopedValueRollback<bool> bg(inReformatBlocks, true);
39 cursor.beginEditBlock();
40 int from = cursor.position();
41 cursor.movePosition(operation);
42 reformatBlocks(from, 0, cursor.position() - from);
43 cursor.endEditBlock();
44 }
45
46 inline void _q_delayedRehighlight() {
48 return;
49 rehighlightPending = false;
50 q_func()->rehighlight();
51 }
52
53 void applyFormatChanges();
54 QList<QTextCharFormat> formatChanges;
58};
59
61{
62 bool formatsChanged = false;
63
65
66 QList<QTextLayout::FormatRange> ranges = layout->formats();
67
68 const int preeditAreaStart = layout->preeditAreaPosition();
69 const int preeditAreaLength = layout->preeditAreaText().size();
70
71 if (preeditAreaLength != 0) {
72 auto isOutsidePreeditArea = [=](const QTextLayout::FormatRange &range) {
73 return range.start < preeditAreaStart
74 || range.start + range.length > preeditAreaStart + preeditAreaLength;
75 };
76 if (ranges.removeIf(isOutsidePreeditArea) > 0)
77 formatsChanged = true;
78 } else if (!ranges.isEmpty()) {
79 ranges.clear();
80 formatsChanged = true;
81 }
82
83 int i = 0;
84 while (i < formatChanges.size()) {
86
87 while (i < formatChanges.size() && formatChanges.at(i) == r.format)
88 ++i;
89
90 if (i == formatChanges.size())
91 break;
92
93 r.start = i;
94 r.format = formatChanges.at(i);
95
96 while (i < formatChanges.size() && formatChanges.at(i) == r.format)
97 ++i;
98
100 r.length = i - r.start;
101
102 if (preeditAreaLength != 0) {
103 if (r.start >= preeditAreaStart)
104 r.start += preeditAreaLength;
105 else if (r.start + r.length >= preeditAreaStart)
106 r.length += preeditAreaLength;
107 }
108
109 ranges << r;
110 formatsChanged = true;
111 }
112
113 if (formatsChanged) {
114 layout->setFormats(ranges);
116 }
117}
118
119void QSyntaxHighlighterPrivate::_q_reformatBlocks(int from, int charsRemoved, int charsAdded)
120{
122 reformatBlocks(from, charsRemoved, charsAdded);
123}
124
125void QSyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int charsAdded)
126{
127 QTextBlock block = doc->findBlock(from);
128 if (!block.isValid())
129 return;
130
131 int endPosition;
132 QTextBlock lastBlock = doc->findBlock(from + charsAdded + (charsRemoved > 0 ? 1 : 0));
133 if (lastBlock.isValid())
134 endPosition = lastBlock.position() + lastBlock.length();
135 else
136 endPosition = QTextDocumentPrivate::get(doc)->length();
137
138 bool forceHighlightOfNextBlock = false;
139
140 while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
141 const int stateBeforeHighlight = block.userState();
142
143 reformatBlock(block);
144
145 forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);
146
147 block = block.next();
148 }
149
151}
152
154{
156
157 Q_ASSERT_X(!currentBlock.isValid(), "QSyntaxHighlighter::reformatBlock()", "reFormatBlock() called recursively");
158
159 currentBlock = block;
160
162 q->highlightBlock(block.text());
164
166}
167
259 : QObject(*new QSyntaxHighlighterPrivate, parent)
260{
261 if (parent && parent->inherits("QTextEdit")) {
262 QTextDocument *doc = qvariant_cast<QTextDocument *>(parent->property("document"));
263 if (doc)
264 setDocument(doc);
265 }
266}
267
278
286
292{
294 if (d->doc) {
295 disconnect(d->doc, SIGNAL(contentsChange(int,int,int)),
296 this, SLOT(_q_reformatBlocks(int,int,int)));
297
298 QTextCursor cursor(d->doc);
299 cursor.beginEditBlock();
300 for (QTextBlock blk = d->doc->begin(); blk.isValid(); blk = blk.next())
301 blk.layout()->clearFormats();
302 cursor.endEditBlock();
303 }
304 d->doc = doc;
305 if (d->doc) {
306 connect(d->doc, SIGNAL(contentsChange(int,int,int)),
307 this, SLOT(_q_reformatBlocks(int,int,int)));
308 if (!d->doc->isEmpty()) {
309 d->rehighlightPending = true;
310 QTimer::singleShot(0, this, SLOT(_q_delayedRehighlight()));
311 }
312 }
313}
314
320{
321 Q_D(const QSyntaxHighlighter);
322 return d->doc;
323}
324
333{
335 if (!d->doc)
336 return;
337
338 QTextCursor cursor(d->doc);
339 d->rehighlight(cursor, QTextCursor::End);
340 d->rehighlightPending = false; // user manually did a full rehighlight
341}
342
351{
353 if (!d->doc || !block.isValid() || block.document() != d->doc)
354 return;
355
356 const bool rehighlightPending = d->rehighlightPending;
357
358 QTextCursor cursor(block);
359 d->rehighlight(cursor, QTextCursor::EndOfBlock);
360
361 if (rehighlightPending)
362 d->rehighlightPending = rehighlightPending;
363}
364
404{
406 if (start < 0 || start >= d->formatChanges.size())
407 return;
408
409 const int end = qMin(start + count, d->formatChanges.size());
410 for (int i = start; i < end; ++i)
411 d->formatChanges[i] = format;
412}
413
431
449
457{
458 Q_D(const QSyntaxHighlighter);
459 if (pos < 0 || pos >= d->formatChanges.size())
460 return QTextCharFormat();
461 return d->formatChanges.at(pos);
462}
463
472{
473 Q_D(const QSyntaxHighlighter);
474 if (!d->currentBlock.isValid())
475 return -1;
476
477 const QTextBlock previous = d->currentBlock.previous();
478 if (!previous.isValid())
479 return -1;
480
481 return previous.userState();
482}
483
489{
490 Q_D(const QSyntaxHighlighter);
491 if (!d->currentBlock.isValid())
492 return -1;
493
494 return d->currentBlock.userState();
495}
496
503{
505 if (!d->currentBlock.isValid())
506 return;
507
508 d->currentBlock.setUserState(newState);
509}
510
546{
548 if (!d->currentBlock.isValid())
549 return;
550
551 d->currentBlock.setUserData(data);
552}
553
561{
562 Q_D(const QSyntaxHighlighter);
563 if (!d->currentBlock.isValid())
564 return nullptr;
565
566 return d->currentBlock.userData();
567}
568
575{
576 Q_D(const QSyntaxHighlighter);
577 return d->currentBlock;
578}
579
581
582#include "moc_qsyntaxhighlighter.cpp"
583
584#endif // QT_NO_SYNTAXHIGHLIGHTER
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
\reentrant
Definition qfont.h:22
qsizetype size() const noexcept
Definition qlist.h:397
QList< T > & fill(parameter_type t, qsizetype size=-1)
Definition qlist.h:903
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void clear()
Definition qlist.h:434
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
bool inherits(const char *classname) const
Returns true if this object is an instance of a class that inherits className or a QObject subclass t...
Definition qobject.h:348
void reformatBlock(const QTextBlock &block)
void _q_reformatBlocks(int from, int charsRemoved, int charsAdded)
void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation)
void reformatBlocks(int from, int charsRemoved, int charsAdded)
QPointer< QTextDocument > doc
QList< QTextCharFormat > formatChanges
\reentrant \inmodule QtGui
QTextBlock currentBlock() const
void setCurrentBlockState(int newState)
Sets the state of the current text block to newState.
QTextCharFormat format(int pos) const
Returns the format at position inside the syntax highlighter's current text block.
void setCurrentBlockUserData(QTextBlockUserData *data)
Attaches the given data to the current text block.
int previousBlockState() const
Returns the end state of the text block previous to the syntax highlighter's current block.
QTextBlockUserData * currentBlockUserData() const
Returns the QTextBlockUserData object previously attached to the current text block.
QSyntaxHighlighter(QObject *parent)
Constructs a QSyntaxHighlighter with the given parent.
QTextDocument * document() const
Returns the QTextDocument on which this syntax highlighter is installed.
void rehighlightBlock(const QTextBlock &block)
void setDocument(QTextDocument *doc)
Installs the syntax highlighter on the given QTextDocument doc.
void setFormat(int start, int count, const QTextCharFormat &format)
This function is applied to the syntax highlighter's current text block (i.e.
int currentBlockState() const
Returns the state of the current text block.
\reentrant
iterator begin() const
Returns a text block iterator pointing to the beginning of the text block.
int length() const
Returns the length of the block in characters.
const QTextDocument * document() const
Returns the text document this text block belongs to, or \nullptr if the text block does not belong t...
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
int userState() const
QTextLayout * layout() const
Returns the QTextLayout that is used to lay out and display the block's contents.
int position() const
Returns the index of the block's first character within the document.
QString text() const
Returns the block's contents as plain text.
QTextBlock previous() const
Returns the text block in the document before this block, or an empty text block if this is the first...
void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior=FontPropertiesAll)
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
MoveOperation
\value NoMove Keep the cursor where it is
Definition qtextcursor.h:61
static const QTextDocumentPrivate * get(const QTextDocument *document)
\reentrant \inmodule QtGui
QTextBlock findBlock(int pos) const
Returns the text block that contains the {pos}-th character.
void markContentsDirty(int from, int length)
Marks the contents specified by the given position and length as "dirty", informing the document that...
void setForeground(const QBrush &brush)
Sets the foreground brush to the specified brush.
\reentrant
Definition qtextlayout.h:70
bool singleShot
whether the timer is a single-shot timer
Definition qtimer.h:22
QCursor cursor
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
Combined button and popup list for selecting options.
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLboolean r
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei range
GLuint color
[2]
GLuint start
GLint GLsizei GLsizei GLenum format
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QVBoxLayout * layout
myObject disconnect()
[26]