diff options
Diffstat (limited to 'src/qmldom/qqmldomlinewriter_p.h')
-rw-r--r-- | src/qmldom/qqmldomlinewriter_p.h | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/qmldom/qqmldomlinewriter_p.h b/src/qmldom/qqmldomlinewriter_p.h new file mode 100644 index 0000000000..86da8d6f54 --- /dev/null +++ b/src/qmldom/qqmldomlinewriter_p.h @@ -0,0 +1,225 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QQMLDOMLINEWRITER_P +#define QQMLDOMLINEWRITER_P + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qqmldom_global.h" +#include "qqmldomstringdumper_p.h" + +#include <QtQml/private/qqmljssourcelocation_p.h> +#include <QtCore/QObject> +#include <QtCore/QAtomicInt> +#include <QtCore/QMap> +#include <functional> + +QT_BEGIN_NAMESPACE +namespace QQmlJS { +namespace Dom { + +class IndentInfo +{ +public: + QStringView string; + QStringView trailingString; + int nNewlines = 0; + int column = 0; + + IndentInfo(QStringView line, int tabSize, int initialColumn = 0) + { + string = line; + int fixup = 0; + if (initialColumn < 0) // we do not want % of negative numbers + fixup = (-initialColumn + tabSize - 1) / tabSize * tabSize; + column = initialColumn + fixup; + const QChar tab = QLatin1Char('\t'); + int iStart = 0; + int len = line.size(); + for (int i = 0; i < len; i++) { + if (line[i] == tab) + column = ((column / tabSize) + 1) * tabSize; + else if (line[i] == QLatin1Char('\n') + || (line[i] == QLatin1Char('\r') + && (i + 1 == len || line[i + 1] != QLatin1Char('\n')))) { + iStart = i + 1; + ++nNewlines; + column = 0; + } else if (!line[i].isLowSurrogate()) + column++; + } + column -= fixup; + trailingString = line.mid(iStart); + } +}; + +class QMLDOM_EXPORT FormatOptions +{ +public: + int tabSize = 4; + int indentSize = 4; + bool useTabs = false; +}; + +class QMLDOM_EXPORT LineWriterOptions +{ + Q_GADGET +public: + enum class LineEndings { Unix, Windows, OldMacOs }; + Q_ENUM(LineEndings) + enum class TrailingSpace { Preserve, Remove }; + Q_ENUM(TrailingSpace) + enum class Update { None = 0, Expressions = 0x1, Locations = 0x2, All = 0x3, Default = All }; + Q_ENUM(Update) + Q_DECLARE_FLAGS(Updates, Update) + enum class AttributesSequence { Normalize, Preserve }; + Q_ENUM(AttributesSequence) + + int maxLineLength = -1; + int strongMaxLineExtra = 20; + int minContentLength = 10; +#if defined (Q_OS_WIN) + LineEndings lineEndings = LineEndings::Windows; +#else + LineEndings lineEndings = LineEndings::Unix; +#endif + TrailingSpace codeTrailingSpace = TrailingSpace::Remove; + TrailingSpace commentTrailingSpace = TrailingSpace::Remove; + TrailingSpace stringTrailingSpace = TrailingSpace::Preserve; + FormatOptions formatOptions; + Updates updateOptions = Update::Default; + AttributesSequence attributesSequence = AttributesSequence::Normalize; + bool objectsSpacing = false; + bool functionsSpacing = false; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(LineWriterOptions::Updates) + +using PendingSourceLocationId = int; +using PendingSourceLocationIdAtomic = QAtomicInt; +class LineWriter; + +class QMLDOM_EXPORT PendingSourceLocation +{ + Q_GADGET +public: + quint32 utf16Start() const; + quint32 utf16End() const; + void changeAtOffset(quint32 offset, qint32 change, qint32 colChange, qint32 lineChange); + void commit(); + PendingSourceLocationId id; + SourceLocation value; + SourceLocation *toUpdate = nullptr; + std::function<void(SourceLocation)> updater = nullptr; + bool open = true; +}; + +class QMLDOM_EXPORT LineWriter +{ + Q_GADGET +public: + enum class TextAddType { + Normal, + Extra, + Newline, + NewlineSplit, + NewlineExtra, + PartialCommit, + Eof + }; + + LineWriter(const SinkF &innerSink, const QString &fileName, + const LineWriterOptions &options = LineWriterOptions(), int lineNr = 0, + int columnNr = 0, int utf16Offset = 0, const QString ¤tLine = QString()); + std::function<void(QStringView)> sink() + { + return [this](QStringView s) { this->write(s); }; + } + + virtual ~LineWriter() { } + + QList<SinkF> innerSinks() { return m_innerSinks; } + void addInnerSink(const SinkF &s) { m_innerSinks.append(s); } + LineWriter &ensureNewline(int nNewlines = 1, TextAddType t = TextAddType::Extra); + LineWriter &ensureSpace(TextAddType t = TextAddType::Extra); + LineWriter &ensureSpace(QStringView space, TextAddType t = TextAddType::Extra); + + LineWriter &newline() + { + write(u"\n"); + return *this; + } + LineWriter &space() + { + write(u" "); + return *this; + } + LineWriter &write(QStringView v, TextAddType tType = TextAddType::Normal); + LineWriter &write(QStringView v, SourceLocation *toUpdate) + { + auto pLoc = startSourceLocation(toUpdate); + write(v); + endSourceLocation(pLoc); + return *this; + } + void commitLine(const QString &eol, TextAddType t = TextAddType::Normal, int untilChar = -1); + void flush(); + void eof(bool ensureNewline = true); + SourceLocation committedLocation() const; + PendingSourceLocationId startSourceLocation(SourceLocation *); + PendingSourceLocationId startSourceLocation(std::function<void(SourceLocation)>); + void endSourceLocation(PendingSourceLocationId); + quint32 counter() const { return m_counter; } + int addTextAddCallback(std::function<bool(LineWriter &, TextAddType)> callback); + bool removeTextAddCallback(int i) { return m_textAddCallbacks.remove(i); } + int addNewlinesAutospacerCallback(int nLines); + void handleTrailingSpace(LineWriterOptions::TrailingSpace s); + void setLineIndent(int indentAmount); + QString fileName() const { return m_fileName; } + const QString ¤tLine() const { return m_currentLine; } + const LineWriterOptions &options() const { return m_options; } + virtual void lineChanged() { } + virtual void reindentAndSplit(const QString &eol, bool eof = false); + virtual void willCommit() { } + +private: + Q_DISABLE_COPY_MOVE(LineWriter) +protected: + void changeAtOffset(quint32 offset, qint32 change, qint32 colChange, qint32 lineChange); + QString eolToWrite() const; + SourceLocation currentSourceLocation() const; + int column(int localIndex); + void textAddCallback(TextAddType t); + + QList<SinkF> m_innerSinks; + QString m_fileName; + int m_lineNr = 0; + int m_columnNr = 0; // columnNr (starts at 0) of committed data + int m_lineUtf16Offset = 0; // utf16 offset since last newline (what is typically stores as + // SourceLocation::startColumn + int m_currentColumnNr = 0; // current columnNr (starts at 0) + int m_utf16Offset = 0; // utf16 offset since start for committed data + QString m_currentLine; + LineWriterOptions m_options; + PendingSourceLocationIdAtomic m_lastSourceLocationId; + QMap<PendingSourceLocationId, PendingSourceLocation> m_pendingSourceLocations; + QAtomicInt m_lastCallbackId; + QMap<int, std::function<bool(LineWriter &, TextAddType)>> m_textAddCallbacks; + quint32 m_counter = 0; + quint32 m_committedEmptyLines = 0x7FFFFFFF; + bool m_reindent = true; +}; + +} // namespace Dom +} // namespace QQmlJS +QT_END_NAMESPACE +#endif |