6#include <QtCore/qdebug.h>
7#include <QtCore/qfileinfo.h>
8#include <QtCore/qregularexpression.h>
12QHash<QString, QString> Quoter::s_commentHash;
16 const qsizetype n = s.size();
17 bool slurping =
false;
19 const QChar newLine = QLatin1Char(
'\n');
21 for (
int i = 0; i != n; ++i) {
23 bool hit = (c == newLine);
33QStringList
Quoter::splitLines(
const QString &line)
36 qsizetype i = line.size();
39 while (j >= 0 && line.at(j) == QLatin1Char(
'\n'))
41 while (j >= 0 && line.at(j) != QLatin1Char(
'\n'))
43 result.prepend(line.mid(j + 1, i - j - 1));
52
53
54
57 enum { Normal, MetAlnum, MetSpace } state = Normal;
58 const qsizetype n = str.size();
61 QChar *d = str.data();
62 for (
int i = 0; i != n; ++i) {
64 if (c.isLetterOrNumber()) {
65 if (state == Normal) {
68 if (state == MetSpace)
73 }
else if (c.isSpace()) {
74 if (state == MetAlnum)
87
88
89
90
91
92
93
94 if (s_commentHash.empty()) {
95 s_commentHash[
"pro"] =
"#!";
96 s_commentHash[
"py"] =
"#!";
97 s_commentHash[
"cmake"] =
"#!";
98 s_commentHash[
"html"] =
"<!--";
99 s_commentHash[
"qrc"] =
"<!--";
100 s_commentHash[
"ui"] =
"<!--";
101 s_commentHash[
"xml"] =
"<!--";
102 s_commentHash[
"xq"] =
"<!--";
109 m_plainLines.clear();
110 m_markedLines.clear();
111 m_codeLocation = Location();
115 const QString &markedCode)
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 m_codeLocation = Location(userFriendlyFilePath);
142 m_plainLines = splitLines(plainCode);
143 m_markedLines = splitLines(markedCode);
144 if (m_markedLines.size() != m_plainLines.size()) {
145 m_codeLocation.warning(
146 QStringLiteral(
"Something is wrong with qdoc's handling of marked code"));
147 m_markedLines = m_plainLines;
151
152
153 for (
auto &line : m_markedLines)
154 replaceMultipleNewlines(line);
155 m_codeLocation.start();
159 const QString &pattern)
161 if (m_plainLines.isEmpty()) {
162 failedAtEnd(docLocation, command);
166 if (pattern.isEmpty()) {
167 docLocation.warning(QStringLiteral(
"Missing pattern after '\\%1'").arg(command));
171 if (match(docLocation, pattern, m_plainLines.first()))
175 docLocation.warning(QStringLiteral(
"Command '\\%1' failed").arg(command));
176 m_codeLocation.warning(QStringLiteral(
"Pattern '%1' didn't match here").arg(pattern));
184 QString comment = commentForCode();
185 QString delimiter = comment + QString(
" [%1]").arg(identifier);
189 while (!m_plainLines.isEmpty()) {
190 if (match(docLocation, delimiter, m_plainLines.first())) {
191 QString startLine = getLine();
192 while (indent < startLine.size() && startLine[indent] == QLatin1Char(
' '))
198 while (!m_plainLines.isEmpty()) {
199 QString line = m_plainLines.first();
200 if (match(docLocation, delimiter, line)) {
201 QString lastLine = getLine(indent);
202 qsizetype dIndex = lastLine.indexOf(delimiter);
206 QString leading = lastLine.left(dIndex);
207 dIndex = leading.indexOf(comment);
209 leading = leading.left(dIndex);
210 if (leading.endsWith(QLatin1String(
"<@comment>")))
212 if (!leading.trimmed().isEmpty())
218 t += removeSpecialLines(line, comment, indent);
220 failedAtEnd(docLocation, QString(
"snippet (%1)").arg(delimiter));
227 QString comment = commentForCode();
229 if (pattern.isEmpty()) {
230 while (!m_plainLines.isEmpty()) {
231 QString line = m_plainLines.first();
232 t += removeSpecialLines(line, comment);
235 while (!m_plainLines.isEmpty()) {
236 if (match(docLocation, pattern, m_plainLines.first())) {
241 failedAtEnd(docLocation, command);
247 const QString &pattern)
249 QString t = quoteTo(docLocation, command, pattern);
254QString
Quoter::getLine(
int unindent)
256 if (m_plainLines.isEmpty())
259 m_plainLines.removeFirst();
261 QString t = m_markedLines.takeFirst();
263 while (i < unindent && i < t.size() && t[i] == QLatin1Char(
' '))
267 t += QLatin1Char(
'\n');
268 m_codeLocation.advanceLines(t.count(QLatin1Char(
'\n')));
272bool Quoter::match(
const Location &docLocation,
const QString &pattern0,
const QString &line)
275 while (str.endsWith(QLatin1Char(
'\n')))
276 str.truncate(str.size() - 1);
278 QString pattern = pattern0;
279 if (pattern.startsWith(QLatin1Char(
'/')) && pattern.endsWith(QLatin1Char(
'/'))
280 && pattern.size() > 2) {
281 QRegularExpression rx(pattern.mid(1, pattern.size() - 2));
282 if (!m_silent && !rx.isValid()) {
284 QStringLiteral(
"Invalid regular expression '%1'").arg(rx.pattern()));
287 return str.indexOf(rx) != -1;
290 trimWhiteSpace(pattern);
291 return str.indexOf(pattern) != -1;
294void Quoter::failedAtEnd(
const Location &docLocation,
const QString &command)
296 if (!m_silent && !command.isEmpty()) {
297 if (m_codeLocation.filePath().isEmpty()) {
298 docLocation.warning(QStringLiteral(
"Unexpected '\\%1'").arg(command));
300 docLocation.warning(QStringLiteral(
"Command '\\%1' failed at end of file '%2'")
301 .arg(command, m_codeLocation.filePath()));
307QString
Quoter::commentForCode()
const
309 QFileInfo fi = QFileInfo(m_codeLocation.fileName());
310 if (fi.fileName() ==
"CMakeLists.txt")
312 return s_commentHash.value(fi.suffix(),
"//!");
315QString
Quoter::removeSpecialLines(
const QString &line,
const QString &comment,
int unindent)
320 QString trimmed = line.trimmed();
321 if (trimmed.startsWith(
"QT_BEGIN_NAMESPACE")) {
323 }
else if (trimmed.startsWith(
"QT_END_NAMESPACE")) {
325 t += QLatin1Char(
'\n');
326 }
else if (!trimmed.startsWith(comment)) {
328 t += getLine(unindent);
331 if (line.contains(QLatin1Char(
'\n')))
332 t += QLatin1Char(
'\n');
The Location class provides a way to mark a location in a file.
QString quoteTo(const Location &docLocation, const QString &command, const QString &pattern)
QString quoteSnippet(const Location &docLocation, const QString &identifier)
QString quoteUntil(const Location &docLocation, const QString &command, const QString &pattern)
void quoteFromFile(const QString &userFriendlyFileName, const QString &plainCode, const QString &markedCode)
QString quoteLine(const Location &docLocation, const QString &command, const QString &pattern)
Combined button and popup list for selecting options.
static void replaceMultipleNewlines(QString &s)
static void trimWhiteSpace(QString &str)