1// Copyright (C) 2021 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
4#ifndef QQMLDOMLINEWRITER_P
5#define QQMLDOMLINEWRITER_P
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qqmldom_global.h"
19#include "qqmldomstringdumper_p.h"
20
21#include <QtQml/private/qqmljssourcelocation_p.h>
22#include <QtCore/QObject>
23#include <QtCore/QAtomicInt>
24#include <QtCore/QMap>
25#include <functional>
26
27QT_BEGIN_NAMESPACE
28namespace QQmlJS {
29namespace Dom {
30
31class IndentInfo
32{
33public:
34 QStringView string;
35 QStringView trailingString;
36 int nNewlines = 0;
37 int column = 0;
38
39 IndentInfo(QStringView line, int tabSize, int initialColumn = 0)
40 {
41 string = line;
42 int fixup = 0;
43 if (initialColumn < 0) // we do not want % of negative numbers
44 fixup = (-initialColumn + tabSize - 1) / tabSize * tabSize;
45 column = initialColumn + fixup;
46 const QChar tab = QLatin1Char('\t');
47 int iStart = 0;
48 int len = line.size();
49 for (int i = 0; i < len; i++) {
50 if (line[i] == tab)
51 column = ((column / tabSize) + 1) * tabSize;
52 else if (line[i] == QLatin1Char('\n')
53 || (line[i] == QLatin1Char('\r')
54 && (i + 1 == len || line[i + 1] != QLatin1Char('\n')))) {
55 iStart = i + 1;
56 ++nNewlines;
57 column = 0;
58 } else if (!line[i].isLowSurrogate())
59 column++;
60 }
61 column -= fixup;
62 trailingString = line.mid(pos: iStart);
63 }
64};
65
66class QMLDOM_EXPORT FormatOptions
67{
68public:
69 int tabSize = 4;
70 int indentSize = 4;
71 bool useTabs = false;
72};
73
74class QMLDOM_EXPORT LineWriterOptions
75{
76 Q_GADGET
77public:
78 enum class LineEndings { Unix, Windows, OldMacOs };
79 Q_ENUM(LineEndings)
80 enum class TrailingSpace { Preserve, Remove };
81 Q_ENUM(TrailingSpace)
82 enum class Update { None = 0, Expressions = 0x1, Locations = 0x2, All = 0x3, Default = All };
83 Q_ENUM(Update)
84 Q_DECLARE_FLAGS(Updates, Update)
85 enum class AttributesSequence { Normalize, Preserve };
86 Q_ENUM(AttributesSequence)
87
88 int maxLineLength = -1;
89 int strongMaxLineExtra = 20;
90 int minContentLength = 10;
91#if defined (Q_OS_WIN)
92 LineEndings lineEndings = LineEndings::Windows;
93#else
94 LineEndings lineEndings = LineEndings::Unix;
95#endif
96 TrailingSpace codeTrailingSpace = TrailingSpace::Remove;
97 TrailingSpace commentTrailingSpace = TrailingSpace::Remove;
98 TrailingSpace stringTrailingSpace = TrailingSpace::Preserve;
99 FormatOptions formatOptions;
100 Updates updateOptions = Update::Default;
101 AttributesSequence attributesSequence = AttributesSequence::Normalize;
102 bool objectsSpacing = false;
103 bool functionsSpacing = false;
104};
105Q_DECLARE_OPERATORS_FOR_FLAGS(LineWriterOptions::Updates)
106
107using PendingSourceLocationId = int;
108using PendingSourceLocationIdAtomic = QAtomicInt;
109class LineWriter;
110
111class QMLDOM_EXPORT PendingSourceLocation
112{
113 Q_GADGET
114public:
115 quint32 utf16Start() const;
116 quint32 utf16End() const;
117 void changeAtOffset(quint32 offset, qint32 change, qint32 colChange, qint32 lineChange);
118 void commit();
119 PendingSourceLocationId id;
120 SourceLocation value;
121 SourceLocation *toUpdate = nullptr;
122 std::function<void(SourceLocation)> updater = nullptr;
123 bool open = true;
124};
125
126class QMLDOM_EXPORT LineWriter
127{
128 Q_GADGET
129public:
130 enum class TextAddType {
131 Normal,
132 Extra,
133 Newline,
134 NewlineSplit,
135 NewlineExtra,
136 PartialCommit,
137 Eof
138 };
139
140 LineWriter(const SinkF &innerSink, const QString &fileName,
141 const LineWriterOptions &options = LineWriterOptions(), int lineNr = 0,
142 int columnNr = 0, int utf16Offset = 0, const QString &currentLine = QString());
143 std::function<void(QStringView)> sink()
144 {
145 return [this](QStringView s) { this->write(v: s); };
146 }
147
148 virtual ~LineWriter() { }
149
150 QList<SinkF> innerSinks() { return m_innerSinks; }
151 void addInnerSink(const SinkF &s) { m_innerSinks.append(t: s); }
152 LineWriter &ensureNewline(int nNewlines = 1, TextAddType t = TextAddType::Extra);
153 LineWriter &ensureSpace(TextAddType t = TextAddType::Extra);
154 LineWriter &ensureSpace(QStringView space, TextAddType t = TextAddType::Extra);
155
156 LineWriter &newline()
157 {
158 write(v: u"\n");
159 return *this;
160 }
161 LineWriter &space()
162 {
163 write(v: u" ");
164 return *this;
165 }
166 LineWriter &write(QStringView v, TextAddType tType = TextAddType::Normal);
167 LineWriter &write(QStringView v, SourceLocation *toUpdate)
168 {
169 auto pLoc = startSourceLocation(toUpdate);
170 write(v);
171 endSourceLocation(pLoc);
172 return *this;
173 }
174 void commitLine(const QString &eol, TextAddType t = TextAddType::Normal, int untilChar = -1);
175 void flush();
176 void eof(bool ensureNewline = true);
177 SourceLocation committedLocation() const;
178 PendingSourceLocationId startSourceLocation(SourceLocation *);
179 PendingSourceLocationId startSourceLocation(std::function<void(SourceLocation)>);
180 void endSourceLocation(PendingSourceLocationId);
181 quint32 counter() const { return m_counter; }
182 int addTextAddCallback(std::function<bool(LineWriter &, TextAddType)> callback);
183 bool removeTextAddCallback(int i) { return m_textAddCallbacks.remove(key: i); }
184 int addNewlinesAutospacerCallback(int nLines);
185 void handleTrailingSpace(LineWriterOptions::TrailingSpace s);
186 void setLineIndent(int indentAmount);
187 QString fileName() const { return m_fileName; }
188 const QString &currentLine() const { return m_currentLine; }
189 const LineWriterOptions &options() const { return m_options; }
190 virtual void lineChanged() { }
191 virtual void reindentAndSplit(const QString &eol, bool eof = false);
192 virtual void willCommit() { }
193
194private:
195 Q_DISABLE_COPY_MOVE(LineWriter)
196protected:
197 void changeAtOffset(quint32 offset, qint32 change, qint32 colChange, qint32 lineChange);
198 QString eolToWrite() const;
199 SourceLocation currentSourceLocation() const;
200 int column(int localIndex);
201 void textAddCallback(TextAddType t);
202
203 QList<SinkF> m_innerSinks;
204 QString m_fileName;
205 int m_lineNr = 0;
206 int m_columnNr = 0; // columnNr (starts at 0) of committed data
207 int m_lineUtf16Offset = 0; // utf16 offset since last newline (what is typically stores as
208 // SourceLocation::startColumn
209 int m_currentColumnNr = 0; // current columnNr (starts at 0)
210 int m_utf16Offset = 0; // utf16 offset since start for committed data
211 QString m_currentLine;
212 LineWriterOptions m_options;
213 PendingSourceLocationIdAtomic m_lastSourceLocationId;
214 QMap<PendingSourceLocationId, PendingSourceLocation> m_pendingSourceLocations;
215 QAtomicInt m_lastCallbackId;
216 QMap<int, std::function<bool(LineWriter &, TextAddType)>> m_textAddCallbacks;
217 quint32 m_counter = 0;
218 quint32 m_committedEmptyLines = 0x7FFFFFFF;
219 bool m_reindent = true;
220};
221
222} // namespace Dom
223} // namespace QQmlJS
224QT_END_NAMESPACE
225#endif
226

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/qmldom/qqmldomlinewriter_p.h