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 AttributesSequence { Normalize, Preserve };
83 Q_ENUM(AttributesSequence)
84 // Always: always add a semicolon at the end of statement
85 // Essential: adds semicolon only when ASI would not insert for us
86 enum class SemicolonRule { Always, Essential };
87 Q_ENUM(SemicolonRule)
88
89 int maxLineLength = -1; // -1 means no limit
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 AttributesSequence attributesSequence = AttributesSequence::Normalize;
101 bool objectsSpacing = false;
102 bool functionsSpacing = false;
103 bool sortImports = false;
104 SemicolonRule semicolonRule = SemicolonRule::Always;
105};
106
107class LineWriter;
108
109class QMLDOM_EXPORT LineWriter
110{
111 Q_GADGET
112public:
113 enum class TextAddType {
114 Normal,
115 Extra,
116 Newline,
117 NewlineSplit,
118 NewlineExtra,
119 PartialCommit,
120 Eof
121 };
122
123 LineWriter(const SinkF &innerSink, const QString &fileName,
124 const LineWriterOptions &options = LineWriterOptions(), int lineNr = 0,
125 int columnNr = 0, int utf16Offset = 0, const QString &currentLine = QString());
126 std::function<void(QStringView)> sink()
127 {
128 return [this](QStringView s) { this->write(v: s); };
129 }
130
131 virtual ~LineWriter() { }
132
133 QList<SinkF> innerSinks() { return m_innerSinks; }
134 void addInnerSink(const SinkF &s) { m_innerSinks.append(t: s); }
135 LineWriter &ensureNewline(int nNewlines = 1, TextAddType t = TextAddType::Extra);
136 LineWriter &ensureSpace(TextAddType t = TextAddType::Extra);
137 LineWriter &ensureSpace(QStringView space, TextAddType t = TextAddType::Extra);
138 LineWriter &ensureSemicolon(TextAddType t = TextAddType::Extra);
139
140 LineWriter &newline()
141 {
142 write(v: u"\n");
143 return *this;
144 }
145 LineWriter &space()
146 {
147 write(v: u" ");
148 return *this;
149 }
150 LineWriter &write(QStringView v, TextAddType tType = TextAddType::Normal);
151 void commitLine(const QString &eol, TextAddType t = TextAddType::Normal, int untilChar = -1);
152 void flush();
153 void eof(bool ensureNewline = true);
154 SourceLocation committedLocation() const;
155 quint32 counter() const { return m_counter; }
156 int addTextAddCallback(std::function<bool(LineWriter &, TextAddType)> callback);
157 bool removeTextAddCallback(int i) { return m_textAddCallbacks.remove(key: i); }
158 int addNewlinesAutospacerCallback(int nLines);
159 void handleTrailingSpace(LineWriterOptions::TrailingSpace s);
160 void setLineIndent(int indentAmount);
161 QString fileName() const { return m_fileName; }
162 const QString &currentLine() const { return m_currentLine; }
163 const LineWriterOptions &options() const { return m_options; }
164 virtual void lineChanged() { }
165 virtual void reindentAndSplit(const QString &eol, bool eof = false);
166 virtual void willCommit() { }
167
168private:
169 Q_DISABLE_COPY_MOVE(LineWriter)
170protected:
171 QString eolToWrite() const;
172 SourceLocation currentSourceLocation() const;
173 int column(int localIndex);
174 void textAddCallback(TextAddType t);
175
176 QList<SinkF> m_innerSinks;
177 QString m_fileName;
178 int m_lineNr = 0;
179 int m_columnNr = 0; // columnNr (starts at 0) of committed data
180 int m_lineUtf16Offset = 0; // utf16 offset since last newline (what is typically stores as
181 // SourceLocation::startColumn
182 int m_currentColumnNr = 0; // current columnNr (starts at 0)
183 int m_utf16Offset = 0; // utf16 offset since start for committed data
184 QString m_currentLine;
185 LineWriterOptions m_options;
186 QAtomicInt m_lastCallbackId;
187 QMap<int, std::function<bool(LineWriter &, TextAddType)>> m_textAddCallbacks;
188 quint32 m_counter = 0;
189 quint32 m_committedEmptyLines = 0x7FFFFFFF;
190 bool m_reindent = true;
191};
192
193} // namespace Dom
194} // namespace QQmlJS
195QT_END_NAMESPACE
196#endif
197

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