KSyntaxHighlighting

syntaxhighlighter.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: MIT
5 */
6 
7 #include "syntaxhighlighter.h"
8 #include "abstracthighlighter_p.h"
9 #include "definition.h"
10 #include "foldingregion.h"
11 #include "format.h"
12 #include "state.h"
13 #include "theme.h"
14 
15 Q_DECLARE_METATYPE(QTextBlock)
16 
17 using namespace KSyntaxHighlighting;
18 
19 namespace KSyntaxHighlighting
20 {
21 class TextBlockUserData : public QTextBlockUserData
22 {
23 public:
24  State state;
25  QVector<FoldingRegion> foldingRegions;
26 };
27 
28 class SyntaxHighlighterPrivate : public AbstractHighlighterPrivate
29 {
30 public:
31  static FoldingRegion foldingRegion(const QTextBlock &startBlock);
32  QVector<FoldingRegion> foldingRegions;
33 };
34 
35 }
36 
37 FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock &startBlock)
38 {
39  const auto data = dynamic_cast<TextBlockUserData *>(startBlock.userData());
40  if (!data) {
41  return FoldingRegion();
42  }
43  for (int i = data->foldingRegions.size() - 1; i >= 0; --i) {
44  if (data->foldingRegions.at(i).type() == FoldingRegion::Begin) {
45  return data->foldingRegions.at(i);
46  }
47  }
48  return FoldingRegion();
49 }
50 
51 SyntaxHighlighter::SyntaxHighlighter(QObject *parent)
52  : QSyntaxHighlighter(parent)
53  , AbstractHighlighter(new SyntaxHighlighterPrivate)
54 {
55  qRegisterMetaType<QTextBlock>();
56 }
57 
58 SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document)
59  : QSyntaxHighlighter(document)
60  , AbstractHighlighter(new SyntaxHighlighterPrivate)
61 {
62  qRegisterMetaType<QTextBlock>();
63 }
64 
65 SyntaxHighlighter::~SyntaxHighlighter()
66 {
67 }
68 
70 {
71  const auto needsRehighlight = definition() != def;
73  if (needsRehighlight) {
74  rehighlight();
75  }
76 }
77 
79 {
80  return SyntaxHighlighterPrivate::foldingRegion(startBlock).type() == FoldingRegion::Begin;
81 }
82 
84 {
85  const auto region = SyntaxHighlighterPrivate::foldingRegion(startBlock);
86 
87  auto block = startBlock;
88  int depth = 1;
89  while (block.isValid()) {
90  block = block.next();
91  const auto data = dynamic_cast<TextBlockUserData *>(block.userData());
92  if (!data) {
93  continue;
94  }
95  for (auto it = data->foldingRegions.constBegin(); it != data->foldingRegions.constEnd(); ++it) {
96  if ((*it).id() != region.id()) {
97  continue;
98  }
99  if ((*it).type() == FoldingRegion::End) {
100  --depth;
101  } else if ((*it).type() == FoldingRegion::Begin) {
102  ++depth;
103  }
104  if (depth == 0) {
105  return block;
106  }
107  }
108  }
109 
110  return QTextBlock();
111 }
112 
113 void SyntaxHighlighter::highlightBlock(const QString &text)
114 {
116 
117  State state;
118  if (currentBlock().position() > 0) {
119  const auto prevBlock = currentBlock().previous();
120  const auto prevData = dynamic_cast<TextBlockUserData *>(prevBlock.userData());
121  if (prevData) {
122  state = prevData->state;
123  }
124  }
125  d->foldingRegions.clear();
126  state = highlightLine(text, state);
127 
128  auto data = dynamic_cast<TextBlockUserData *>(currentBlockUserData());
129  if (!data) { // first time we highlight this
130  data = new TextBlockUserData;
131  data->state = state;
132  data->foldingRegions = d->foldingRegions;
134  return;
135  }
136 
137  if (data->state == state && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here
138  return;
139  }
140  data->state = state;
141  data->foldingRegions = d->foldingRegions;
142 
143  const auto nextBlock = currentBlock().next();
144  if (nextBlock.isValid()) {
145  QMetaObject::invokeMethod(this, "rehighlightBlock", Qt::QueuedConnection, Q_ARG(QTextBlock, nextBlock));
146  }
147 }
148 
149 void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)
150 {
151  if (length == 0) {
152  return;
153  }
154 
155  QTextCharFormat tf;
156  // always set the foreground color to avoid palette issues
157  tf.setForeground(format.textColor(theme()));
158 
159  if (format.hasBackgroundColor(theme())) {
160  tf.setBackground(format.backgroundColor(theme()));
161  }
162  if (format.isBold(theme())) {
164  }
165  if (format.isItalic(theme())) {
166  tf.setFontItalic(true);
167  }
168  if (format.isUnderline(theme())) {
169  tf.setFontUnderline(true);
170  }
171  if (format.isStrikeThrough(theme())) {
172  tf.setFontStrikeOut(true);
173  }
174 
175  QSyntaxHighlighter::setFormat(offset, length, tf);
176 }
177 
178 void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion region)
179 {
180  Q_UNUSED(offset);
181  Q_UNUSED(length);
183 
184  if (region.type() == FoldingRegion::Begin) {
185  d->foldingRegions.push_back(region);
186  }
187 
188  if (region.type() == FoldingRegion::End) {
189  for (int i = d->foldingRegions.size() - 1; i >= 0; --i) {
190  if (d->foldingRegions.at(i).id() != region.id() || d->foldingRegions.at(i).type() != FoldingRegion::Begin) {
191  continue;
192  }
193  d->foldingRegions.remove(i);
194  return;
195  }
196  d->foldingRegions.push_back(region);
197  }
198 }
void setCurrentBlockUserData(QTextBlockUserData *data)
void applyFolding(int offset, int length, FoldingRegion region) override
Reimplement this to apply folding to your output.
Opaque handle to the state of the highlighting engine.
Definition: state.h:25
Represents a begin or end of a folding region.
Definition: foldingregion.h:18
void setFormat(int start, int count, const QTextCharFormat &format)
void setFontWeight(int weight)
QTextBlock findFoldingRegionEnd(const QTextBlock &startBlock) const
Finds the end of the folding region starting at startBlock.
Describes the format to be used for a specific text fragment.
Definition: format.h:33
Abstract base class for highlighters.
QTextBlock currentBlock() const const
QTextBlock next() const const
void setFontStrikeOut(bool strikeOut)
void setBackground(const QBrush &brush)
void setFontItalic(bool italic)
@ End
Indicates the end of a FoldingRegion.
Definition: foldingregion.h:30
void applyFormat(int offset, int length, const Format &format) override
Reimplement this to apply formats to your output.
void setForeground(const QBrush &brush)
QTextBlockUserData * currentBlockUserData() const const
QTextBlock previous() const const
QueuedConnection
QTextBlockUserData * userData() const const
void setDefinition(const Definition &def) override
Sets the syntax definition used for highlighting.
QTextCharFormat format(int position) const const
bool startsFoldingRegion(const QTextBlock &startBlock) const
Returns whether there is a folding region beginning at startBlock.
State highlightLine(QStringView text, const State &state)
Highlight the given line.
Type type() const
Returns whether this is the begin or end of a region.
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
virtual void setDefinition(const Definition &def)
Sets the syntax definition used for highlighting.
A QSyntaxHighlighter implementation for use with QTextDocument.
Definition definition() const
Returns the syntax definition used for highlighting.
void setFontUnderline(bool underline)
Theme theme() const
Returns the currently selected theme for highlighting.
quint16 id() const
Returns a unique identifier for this folding region.
@ Begin
Indicates the start of a FoldingRegion.
Definition: foldingregion.h:28
Represents a syntax definition.
Definition: definition.h:86
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Mar 26 2023 04:09:17 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.