Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
text.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "text.h"
5
6#include <QtCore/qregularexpression.h>
7
8#include <cstdio>
9
10QT_BEGIN_NAMESPACE
11
12Text::Text() : m_first(nullptr), m_last(nullptr) { }
13
14Text::Text(const QString &str) : m_first(nullptr), m_last(nullptr)
15{
16 operator<<(str);
17}
18
19Text::Text(const Text &text) : m_first(nullptr), m_last(nullptr)
20{
21 operator=(text);
22}
23
25{
26 clear();
27}
28
29Text &Text::operator=(const Text &text)
30{
31 if (this != &text) {
32 clear();
33 operator<<(text);
34 }
35 return *this;
36}
37
38Text &Text::operator<<(Atom::AtomType atomType)
39{
40 return operator<<(Atom(atomType));
41}
42
43Text &Text::operator<<(const QString &string)
44{
45 return string.isEmpty() ? *this : operator<<(Atom(Atom::String, string));
46}
47
48Text &Text::operator<<(const Atom &atom)
49{
50 Atom *copy = atom.clone();
51
52 if (m_first == nullptr) {
53 m_first = copy;
54 } else {
55 m_last->setNext(copy);
56 }
57
58 m_last = copy;
59 return *this;
60}
61
62Text &Text::operator<<(const Text &text)
63{
64 const Atom *atom = text.firstAtom();
65 while (atom != nullptr) {
66 operator<<(*atom);
67 atom = atom->next();
68 }
69 return *this;
70}
71
73{
74 if (m_first != nullptr) {
75 if (m_first == m_last)
76 m_last = nullptr;
77 Atom *oldFirst = m_first;
78 m_first = m_first->next();
79 delete oldFirst;
80 }
81}
82
84{
85 if (m_last != nullptr) {
86 Atom *oldLast = m_last;
87 if (m_first == m_last) {
88 m_first = nullptr;
89 m_last = nullptr;
90 } else {
91 m_last = m_first;
92 while (m_last->next() != oldLast)
93 m_last = m_last->next();
94 m_last->setNext(nullptr);
95 }
96 delete oldLast;
97 }
98}
99
100/*!
101 This function traverses the atom list of the Text object,
102 extracting all the string parts. It concatenates them to
103 a result string and returns it.
104 */
106{
107 QString str;
108 const Atom *atom = firstAtom();
109 while (atom != nullptr) {
110 if (atom->type() == Atom::String || atom->type() == Atom::AutoLink
111 || atom->type() == Atom::C)
112 str += atom->string();
113 atom = atom->next();
114 }
115 return str;
116}
117
118/*!
119 Returns true if this Text contains the substring \a str.
120 */
121bool Text::contains(const QString &str) const
122{
123 const Atom *atom = firstAtom();
124 while (atom != nullptr) {
125 if (atom->type() == Atom::String || atom->type() == Atom::AutoLink
126 || atom->type() == Atom::C)
127 if (atom->string().contains(str, Qt::CaseInsensitive))
128 return true;
129 atom = atom->next();
130 }
131 return false;
132}
133
134Text Text::subText(Atom::AtomType left, Atom::AtomType right, const Atom *from,
135 bool inclusive) const
136{
137 const Atom *begin = from ? from : firstAtom();
138 const Atom *end;
139
140 while (begin != nullptr && begin->type() != left)
141 begin = begin->next();
142 if (begin != nullptr) {
143 if (!inclusive)
144 begin = begin->next();
145 }
146
147 end = begin;
148 while (end != nullptr && end->type() != right)
149 end = end->next();
150 if (end == nullptr)
151 begin = nullptr;
152 else if (inclusive)
153 end = end->next();
154 return subText(begin, end);
155}
156
157Text Text::sectionHeading(const Atom *sectionLeft)
158{
159 if (sectionLeft != nullptr) {
160 const Atom *begin = sectionLeft;
161 while (begin != nullptr && begin->type() != Atom::SectionHeadingLeft)
162 begin = begin->next();
163 if (begin != nullptr)
164 begin = begin->next();
165
166 const Atom *end = begin;
167 while (end != nullptr && end->type() != Atom::SectionHeadingRight)
168 end = end->next();
169
170 if (end != nullptr)
171 return subText(begin, end);
172 }
173 return Text();
174}
175
176/*!
177 Prints a human-readable version of the contained atoms to stderr.
178
179 The output is formatted as a linear list of atoms, with each atom
180 being on its own line.
181
182 Each atom is represented by its type and its stringified-contents,
183 if any, with a space between the two.
184
185 Indentation is used to emphasize the possible block-level
186 relationship between consecutive atoms, increasing after a
187 "Left" atom and decreasing just before a "Right" atom.
188
189 For example, if this `Text` represented the block-comment
190 containing the text:
191
192 \c {\l {somelink} {This is a link}}
193
194 Then the human-readable output would look like the following:
195
196 \badcode
197 ParaLeft
198 Link "somelink"
199 FormattingLeft "link"
200 String "This is a link"
201 FormattingRight "link"
202 String
203 ParaRight
204 \endcode
205 */
206void Text::dump() const
207{
208 constexpr int minimum_indentation_level { 1 };
209 int indentation_level { minimum_indentation_level };
210 int indentation_width { 4 };
211
212 const Atom *atom = firstAtom();
213 while (atom != nullptr) {
214 QString str = atom->string();
215 str.replace("\\", "\\\\");
216 str.replace("\"", "\\\"");
217 str.replace("\n", "\\n");
218 static const QRegularExpression re(R"([^ -~])");
219 str.replace(re, "?");
220 if (!str.isEmpty())
221 str = " \"" + str + QLatin1Char('"');
222
223 QString atom_type = atom->typeString();
224 if (atom_type.contains("Right"))
225 indentation_level = std::max(minimum_indentation_level, indentation_level - 1);
226
227 fprintf(stderr, "%s%s%s\n",
228 QString(indentation_level * indentation_width, ' ').toLatin1().data(),
229 atom_type.toLatin1().data(), str.toLatin1().data());
230
231 if (atom_type.contains("Left"))
232 indentation_level += 1;
233
234 atom = atom->next();
235 }
236}
237
238Text Text::subText(const Atom *begin, const Atom *end)
239{
240 Text text;
241 if (begin != nullptr) {
242 while (begin != end) {
243 text << *begin;
244 begin = begin->next();
245 }
246 }
247 return text;
248}
249
250void Text::clear()
251{
252 while (m_first)
253 delete std::exchange(m_first, m_first->next());
254 m_last = nullptr;
255}
256
257int Text::compare(const Text &text1, const Text &text2)
258{
259 if (text1.isEmpty())
260 return text2.isEmpty() ? 0 : -1;
261 if (text2.isEmpty())
262 return 1;
263
264 const Atom *atom1 = text1.firstAtom();
265 const Atom *atom2 = text2.firstAtom();
266
267 for (;;) {
268 if (atom1->type() != atom2->type())
269 return (int)atom1->type() - (int)atom2->type();
270 int cmp = QString::compare(atom1->string(), atom2->string());
271 if (cmp != 0)
272 return cmp;
273
274 if (atom1 == text1.lastAtom())
275 return atom2 == text2.lastAtom() ? 0 : -1;
276 if (atom2 == text2.lastAtom())
277 return 1;
278 atom1 = atom1->next();
279 atom2 = atom2->next();
280 }
281}
282
283/*!
284 \internal
285
286 \brief Splits the current Text from \a start to end into a new Text object.
287
288 Returns a new Text from the first Atom in this Text of atom type \a start.
289 */
291 if (m_first == nullptr)
292 return {};
293
294 Atom *previous = nullptr;
295 Atom *current = m_first;
296
297 while (current != nullptr) {
298 if (current->type() == start)
299 break;
300 previous = current;
301 current = current->next();
302 }
303
304 if (!current)
305 return {};
306
307 Text splitText = Text(current, m_last);
308
309 // Reset this Text's first and last atom pointers based on
310 // whether all or part of the content was extracted.
311 m_first = previous ? m_first : nullptr;
312 if (m_last = previous; m_last)
313 m_last->setNext(nullptr);
314
315 return splitText;
316}
317
318QT_END_NAMESPACE
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:19
AtomType type() const
Return the type of this atom.
Definition atom.h:144
void setNext(Atom *newNext)
Definition atom.h:137
AtomType
\value AnnotatedList \value AutoLink \value BaseName \value BriefLeft \value BriefRight \value C \val...
Definition atom.h:21
@ SectionHeadingLeft
Definition atom.h:85
@ String
Definition atom.h:95
@ C
Definition atom.h:28
@ SectionHeadingRight
Definition atom.h:86
@ AutoLink
Definition atom.h:23
Atom * next()
Return the next atom in the atom list.
Definition atom.h:136
virtual Atom * clone() const
Creates and returns a detached copy of this Atom.
Definition atom.cpp:248
const Atom * next() const
Return the next atom in the atom list.
Definition atom.h:141
Definition text.h:12
bool contains(const QString &str) const
Returns true if this Text contains the substring str.
Definition text.cpp:121
static Text subText(const Atom *begin, const Atom *end=nullptr)
Definition text.cpp:238
static Text sectionHeading(const Atom *sectionBegin)
Definition text.cpp:157
void dump() const
Prints a human-readable version of the contained atoms to stderr.
Definition text.cpp:206
~Text()
Definition text.cpp:24
const Atom * firstAtom() const
Definition text.h:33
Text splitAtFirst(Atom::AtomType start)
Splits the current Text from start to end into a new Text object.
Definition text.cpp:290
bool isEmpty() const
Definition text.h:30
Text subText(Atom::AtomType left, Atom::AtomType right, const Atom *from=nullptr, bool inclusive=false) const
Definition text.cpp:134
void stripFirstAtom()
Definition text.cpp:72
Text(const Text &text)
Definition text.cpp:19
void clear()
Definition text.cpp:250
Text & operator=(const Text &text)
Definition text.cpp:29
Text()
Definition text.cpp:12
const Atom * lastAtom() const
Definition text.h:34
QString toString() const
This function traverses the atom list of the Text object, extracting all the string parts.
Definition text.cpp:105
Text(const QString &str)
Definition text.cpp:14
void stripLastAtom()
Definition text.cpp:83
static int compare(const Text &text1, const Text &text2)
Definition text.cpp:257