From 39921ce7bd7ebecaefceaf00428c90c25d69f603 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 6 May 2021 12:21:08 +0200 Subject: [PATCH] Designer: take tab settings into account when generating qml code Task-number: QTCREATORBUG-24523 Change-Id: I1e02c781fbbde8114dd4570460756ce796275379 Reviewed-by: Thomas Hartmann --- .../designercore/filemanager/qmlrewriter.cpp | 75 ++++--------------- .../designercore/filemanager/qmlrewriter.h | 7 +- .../include/basetexteditmodifier.h | 2 +- .../include/componenttextmodifier.h | 2 +- .../include/plaintexteditmodifier.h | 19 +++-- .../designercore/include/textmodifier.h | 6 +- .../model/basetexteditmodifier.cpp | 9 ++- .../model/componenttextmodifier.cpp | 4 +- .../designercore/model/modeltotextmerger.cpp | 15 ++-- .../designercore/model/qmltextgenerator.cpp | 24 +++--- .../designercore/model/qmltextgenerator.h | 13 +++- .../model/rewriteactioncompressor.cpp | 10 ++- .../model/rewriteactioncompressor.h | 4 +- 13 files changed, 86 insertions(+), 104 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp index 25a72134b2a..1173b87b41f 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp @@ -33,7 +33,6 @@ #include - static Q_LOGGING_CATEGORY(qmlRewriter, "qtc.rewriter.qmlrewriter", QtWarningMsg) using namespace QmlDesigner::Internal; @@ -73,24 +72,18 @@ QString QMLRewriter::textAt(const QmlJS::SourceLocation &location) const return m_textModifier->text().mid(location.offset, location.length); } +int QMLRewriter::indentDepth() const +{ + return textModifier()->tabSettings().m_indentSize; +} + unsigned QMLRewriter::calculateIndentDepth(const QmlJS::SourceLocation &position) const { QTextDocument *doc = m_textModifier->textDocument(); QTextCursor tc(doc); tc.setPosition(position.offset); - const int lineOffset = tc.block().position(); - unsigned indentDepth = 0; - forever { - const QChar ch = doc->characterAt(lineOffset + indentDepth); - - if (ch.isNull() || !ch.isSpace()) - break; - else - ++indentDepth; - } - - return indentDepth; + return textModifier()->tabSettings().indentationColumn(tc.block().text()); } QString QMLRewriter::addIndentation(const QString &text, unsigned depth) @@ -98,56 +91,20 @@ QString QMLRewriter::addIndentation(const QString &text, unsigned depth) if (depth == 0) return text; - const QString indentation(depth, QLatin1Char(' ')); - - if (text.isEmpty()) - return indentation; - - const QLatin1Char lineSep('\n'); - const QStringList lines = text.split(lineSep); + TextEditor::TabSettings tabSettings = textModifier()->tabSettings(); QString result; - - for (int i = 0; i < lines.size(); ++i) { - if (i > 0) - result += lineSep; - const QString &line = lines.at(i); - if (!line.isEmpty()) { - result += indentation; - result += line; - } - } - - return result; -} - -QString QMLRewriter::removeIndentationFromLine(const QString &text, int depth) -{ - int charsToRemove = 0; - for (int i = 0; i < depth && i < text.length(); ++i) { - if (text.at(i).isSpace()) - charsToRemove++; - else - break; - } - - if (charsToRemove == 0) - return text; - else - return text.mid(charsToRemove); -} - -QString QMLRewriter::removeIndentation(const QString &text, unsigned depth) -{ - const QLatin1Char lineSep('\n'); + constexpr char lineSep('\n'); const QStringList lines = text.split(lineSep); - QString result; - - for (int i = 0; i < lines.size(); ++i) { - if (i > 0) + for (const QString &line : lines) { + if (!result.isEmpty()) result += lineSep; - result += removeIndentationFromLine(lines.at(i), depth); + if (line.isEmpty()) + continue; + const int firstNoneSpace = TextEditor::TabSettings::firstNonSpace(line); + const int lineIndentColumn = tabSettings.indentationColumn(line) + int(depth); + result.append(tabSettings.indentationString(0, lineIndentColumn, 0)); + result.append(line.midRef(firstNoneSpace)); } - return result; } diff --git a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h index c773de35bec..9a081a8b292 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h +++ b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h @@ -59,12 +59,9 @@ protected: QString textBetween(int startPosition, int endPosition) const; QString textAt(const QmlJS::SourceLocation &location) const; - int indentDepth() const - { return textModifier()->indentDepth(); } + int indentDepth() const; unsigned calculateIndentDepth(const QmlJS::SourceLocation &position) const; - static QString addIndentation(const QString &text, unsigned depth); - static QString removeIndentation(const QString &text, unsigned depth); - static QString removeIndentationFromLine(const QString &text, int depth); + QString addIndentation(const QString &text, unsigned depth); static QmlJS::SourceLocation calculateLocation(QmlJS::AST::UiQualifiedId *id); static bool isMissingSemicolon(QmlJS::AST::UiObjectMember *member); diff --git a/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h b/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h index 640ff367bc1..2e3ff689035 100644 --- a/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h @@ -44,7 +44,7 @@ public: void indentLines(int startLine, int endLine) override; void indent(int offset, int length) override; - int indentDepth() const override; + TextEditor::TabSettings tabSettings() const override; bool renameId(const QString &oldId, const QString &newId) override; bool moveToComponent(int nodeOffset) override; diff --git a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h index 8cc2c235f76..d870f29622a 100644 --- a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h @@ -41,7 +41,7 @@ public: void indent(int offset, int length) override; void indentLines(int startLine, int endLine) override; - int indentDepth() const override; + TextEditor::TabSettings tabSettings() const override; void startGroup() override; void flushGroup() override; diff --git a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h index c18b4d8cfb4..3ef3a996a97 100644 --- a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h @@ -59,8 +59,6 @@ public: void indent(int offset, int length) override = 0; void indentLines(int startLine, int endLine) override = 0; - int indentDepth() const override = 0; - void startGroup() override; void flushGroup() override; void commitGroup() override; @@ -95,19 +93,28 @@ class QMLDESIGNERCORE_EXPORT NotIndentingTextEditModifier: public PlainTextEditM public: NotIndentingTextEditModifier(QPlainTextEdit *textEdit) : PlainTextEditModifier(textEdit) - {} + { + m_tabSettings.m_tabSize = 0; + m_tabSettings.m_indentSize = 0; + } NotIndentingTextEditModifier(QTextDocument *document, const QTextCursor &textCursor) : PlainTextEditModifier{document, textCursor} - {} + { + m_tabSettings.m_tabSize = 0; + m_tabSettings.m_indentSize = 0; + } void indent(int /*offset*/, int /*length*/) override {} void indentLines(int /*offset*/, int /*length*/) override {} - int indentDepth() const override - { return 0; } + TextEditor::TabSettings tabSettings() const override + { return m_tabSettings; } + +private: + TextEditor::TabSettings m_tabSettings; }; } diff --git a/src/plugins/qmldesigner/designercore/include/textmodifier.h b/src/plugins/qmldesigner/designercore/include/textmodifier.h index 617d0b9b7b2..648f9e15c4c 100644 --- a/src/plugins/qmldesigner/designercore/include/textmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/textmodifier.h @@ -28,11 +28,15 @@ #include "qmldesignercorelib_global.h" #include +#include +#include #include #include #include +namespace TextEditor { class TabSettings; } + namespace QmlDesigner { class QMLDESIGNERCORE_EXPORT TextModifier: public QObject @@ -66,7 +70,7 @@ public: virtual void indent(int offset, int length) = 0; virtual void indentLines(int startLine, int endLine) = 0; - virtual int indentDepth() const = 0; + virtual TextEditor::TabSettings tabSettings() const = 0; virtual void startGroup() = 0; virtual void flushGroup() = 0; diff --git a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp index 8113e628468..4639fd101c3 100644 --- a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp @@ -31,7 +31,9 @@ #include #include #include +#include #include +#include #include #include @@ -80,12 +82,11 @@ void BaseTextEditModifier::indent(int offset, int length) indentLines(startLine, endLine); } -int BaseTextEditModifier::indentDepth() const +TextEditor::TabSettings BaseTextEditModifier::tabSettings() const { if (m_textEdit) - return m_textEdit->textDocument()->tabSettings().m_indentSize; - else - return 0; + return m_textEdit->textDocument()->tabSettings(); + return QmlJSTools::QmlJSToolsSettings::globalCodeStyle()->tabSettings(); } bool BaseTextEditModifier::renameId(const QString &oldId, const QString &newId) diff --git a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp index 1d500b84963..5f984a1f348 100644 --- a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp @@ -83,9 +83,9 @@ void ComponentTextModifier::indentLines(int startLine, int endLine) m_originalModifier->indentLines(startLine, endLine); } -int ComponentTextModifier::indentDepth() const +TextEditor::TabSettings ComponentTextModifier::tabSettings() const { - return m_originalModifier->indentDepth(); + return m_originalModifier->tabSettings(); } void ComponentTextModifier::startGroup() diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp index 1f8c23048dd..b2f36b54565 100644 --- a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp @@ -81,12 +81,13 @@ void ModelToTextMerger::propertiesRemoved(const QList& propert void ModelToTextMerger::propertiesChanged(const QList& propertyList, PropertyChangeFlags propertyChange) { + const TextEditor::TabSettings tabSettings = m_rewriterView->textModifier()->tabSettings(); foreach (const AbstractProperty &property, propertyList) { ModelNode containedModelNode; - const int indentDepth = m_rewriterView->textModifier()->indentDepth(); const QString propertyTextValue = QmlTextGenerator(propertyOrder(), - indentDepth)(property); + tabSettings, + tabSettings.m_indentSize)(property); switch (propertyChange) { case AbstractView::PropertiesAdded: @@ -162,14 +163,18 @@ void ModelToTextMerger::nodeReparented(const ModelNode &node, const NodeAbstract switch (propertyChange) { case AbstractView::PropertiesAdded: schedule(new AddPropertyRewriteAction(newPropertyParent, - QmlTextGenerator(propertyOrder())(node), + QmlTextGenerator(propertyOrder(), + m_rewriterView->textModifier() + ->tabSettings())(node), propertyType(newPropertyParent), node)); break; case AbstractView::NoAdditionalChanges: schedule(new ChangePropertyRewriteAction(newPropertyParent, - QmlTextGenerator(propertyOrder())(node), + QmlTextGenerator(propertyOrder(), + m_rewriterView->textModifier() + ->tabSettings())(node), propertyType(newPropertyParent), node)); break; @@ -213,7 +218,7 @@ void ModelToTextMerger::applyChanges() dumpRewriteActions(QStringLiteral("Before compression")); RewriteActionCompressor compress(propertyOrder()); - compress(m_rewriteActions); + compress(m_rewriteActions, m_rewriterView->textModifier()->tabSettings()); dumpRewriteActions(QStringLiteral("After compression")); if (m_rewriteActions.isEmpty()) diff --git a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp index 3349a5df54b..0a22c352b27 100644 --- a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp @@ -85,9 +85,12 @@ static QString unicodeEscape(const QString &stringValue) return stringValue; } -QmlTextGenerator::QmlTextGenerator(const PropertyNameList &propertyOrder, int indentDepth): - m_propertyOrder(propertyOrder), - m_indentDepth(indentDepth) +QmlTextGenerator::QmlTextGenerator(const PropertyNameList &propertyOrder, + const TextEditor::TabSettings &tabSettings, + const int startIndentDepth) + : m_propertyOrder(propertyOrder) + , m_tabSettings(tabSettings) + , m_startIndentDepth(startIndentDepth) { } @@ -106,13 +109,13 @@ QString QmlTextGenerator::toQml(const AbstractProperty &property, int indentDept for (int i = 0; i < nodes.length(); ++i) { if (i > 0) result += QStringLiteral("\n\n"); - result += QString(indentDepth, QLatin1Char(' ')); + result += m_tabSettings.indentationString(0, indentDepth, 0); result += toQml(nodes.at(i), indentDepth); } return result; } else { QString result = QStringLiteral("["); - const int arrayContentDepth = indentDepth + 4; + const int arrayContentDepth = indentDepth + m_tabSettings.m_indentSize; const QString arrayContentIndentation(arrayContentDepth, QLatin1Char(' ')); for (int i = 0; i < nodes.length(); ++i) { if (i > 0) @@ -208,11 +211,12 @@ QString QmlTextGenerator::toQml(const ModelNode &node, int indentDepth) const result += type; result += QStringLiteral(" {\n"); - const int propertyIndentDepth = indentDepth + 4; + const int propertyIndentDepth = indentDepth + m_tabSettings.m_indentSize; const QString properties = propertiesToQml(node, propertyIndentDepth); - return result + properties + QString(indentDepth, QLatin1Char(' ')) + QLatin1Char('}'); + return result + properties + m_tabSettings.indentationString(0, indentDepth, 0) + + QLatin1Char('}'); } QString QmlTextGenerator::propertiesToQml(const ModelNode &node, int indentDepth) const @@ -227,7 +231,7 @@ QString QmlTextGenerator::propertiesToQml(const ModelNode &node, int indentDepth if (propertyName == "id") { // the model handles the id property special, so: if (!node.id().isEmpty()) { - QString idLine(indentDepth, QLatin1Char(' ')); + QString idLine = m_tabSettings.indentationString(0, indentDepth, 0); idLine += QStringLiteral("id: "); idLine += node.id(); idLine += QLatin1Char('\n'); @@ -264,7 +268,7 @@ QString QmlTextGenerator::propertyToQml(const AbstractProperty &property, int in result = toQml(property, indentDepth); } else { if (property.isDynamic()) { - result = QString(indentDepth, QLatin1Char(' ')) + result = m_tabSettings.indentationString(0, indentDepth, 0) + QStringLiteral("property ") + QString::fromUtf8(property.dynamicTypeName()) + QStringLiteral(" ") @@ -272,7 +276,7 @@ QString QmlTextGenerator::propertyToQml(const AbstractProperty &property, int in + QStringLiteral(": ") + toQml(property, indentDepth); } else { - result = QString(indentDepth, QLatin1Char(' ')) + result = m_tabSettings.indentationString(0, indentDepth, 0) + QString::fromUtf8(property.name()) + QStringLiteral(": ") + toQml(property, indentDepth); diff --git a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h index 5c2823573e2..0138dd149a4 100644 --- a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h +++ b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h @@ -27,6 +27,8 @@ #include +#include + #include "abstractproperty.h" #include "modelnode.h" @@ -36,13 +38,15 @@ namespace Internal { class QmlTextGenerator { public: - explicit QmlTextGenerator(const PropertyNameList &propertyOrder, int indentDepth = 0); + explicit QmlTextGenerator(const PropertyNameList &propertyOrder, + const TextEditor::TabSettings &tabSettings, + const int startIndentDepth = 0); QString operator()(const AbstractProperty &property) const - { return toQml(property, m_indentDepth); } + { return toQml(property, m_startIndentDepth); } QString operator()(const ModelNode &modelNode) const - { return toQml(modelNode, m_indentDepth); } + { return toQml(modelNode, m_startIndentDepth); } private: QString toQml(const AbstractProperty &property, int indentDepth) const; @@ -54,7 +58,8 @@ private: private: PropertyNameList m_propertyOrder; - int m_indentDepth; + TextEditor::TabSettings m_tabSettings; + const int m_startIndentDepth; }; } // namespace Internal diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp index d84b088db85..24342002b38 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp @@ -50,14 +50,15 @@ static bool nodeOrParentInSet(const ModelNode &modelNode, const QSet return false; } -void RewriteActionCompressor::operator()(QList &actions) const +void RewriteActionCompressor::operator()(QList &actions, + const TextEditor::TabSettings &tabSettings) const { compressImports(actions); compressRereparentActions(actions); compressReparentIntoSamePropertyActions(actions); compressPropertyActions(actions); compressAddEditRemoveNodeActions(actions); - compressAddEditActions(actions); + compressAddEditActions(actions, tabSettings); compressAddReparentActions(actions); } @@ -256,7 +257,8 @@ void RewriteActionCompressor::compressPropertyActions(QList &ac } } -void RewriteActionCompressor::compressAddEditActions(QList &actions) const +void RewriteActionCompressor::compressAddEditActions( + QList &actions, const TextEditor::TabSettings &tabSettings) const { QList actionsToRemove; QSet addedNodes; @@ -303,7 +305,7 @@ void RewriteActionCompressor::compressAddEditActions(QList &act delete action; } - QmlTextGenerator gen(m_propertyOrder); + QmlTextGenerator gen(m_propertyOrder, tabSettings); foreach (RewriteAction *action, dirtyActions) { RewriteAction *newAction = nullptr; if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) { diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h index 2702ab0d60c..57139f98115 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h @@ -35,7 +35,7 @@ class RewriteActionCompressor public: RewriteActionCompressor(const PropertyNameList &propertyOrder): m_propertyOrder(propertyOrder) {} - void operator()(QList &actions) const; + void operator()(QList &actions, const TextEditor::TabSettings &tabSettings) const; private: void compressImports(QList &actions) const; @@ -44,7 +44,7 @@ private: void compressReparentIntoSamePropertyActions(QList &actions) const; void compressAddEditRemoveNodeActions(QList &actions) const; void compressPropertyActions(QList &actions) const; - void compressAddEditActions(QList &actions) const; + void compressAddEditActions(QList &actions, const TextEditor::TabSettings &tabSettings) const; void compressAddReparentActions(QList &actions) const; private: