aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmlls/quick/qqmllsquickplugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmlls/quick/qqmllsquickplugin.cpp')
-rw-r--r--src/plugins/qmlls/quick/qqmllsquickplugin.cpp187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/plugins/qmlls/quick/qqmllsquickplugin.cpp b/src/plugins/qmlls/quick/qqmllsquickplugin.cpp
new file mode 100644
index 0000000000..67b95b074a
--- /dev/null
+++ b/src/plugins/qmlls/quick/qqmllsquickplugin.cpp
@@ -0,0 +1,187 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qqmllsquickplugin_p.h"
+#include <QtQmlLS/private/qqmllsutils_p.h>
+#include <QtQmlLS/private/qqmllscompletion_p.h>
+
+using namespace QLspSpecification;
+using namespace QQmlJS::Dom;
+
+QT_BEGIN_NAMESPACE
+
+std::unique_ptr<QQmlLSCompletionPlugin> QQmlLSQuickPlugin::createCompletionPlugin() const
+{
+ return std::make_unique<QQmlLSQuickCompletionPlugin>();
+}
+
+void QQmlLSQuickCompletionPlugin::suggestSnippetsForLeftHandSideOfBinding(
+ const DomItem &itemAtPosition, BackInsertIterator result) const
+{
+ auto file = itemAtPosition.containingFile().as<QmlFile>();
+ if (!file)
+ return;
+
+ // check if QtQuick has been imported
+ const auto &imports = file->imports();
+ auto it = std::find_if(imports.constBegin(), imports.constEnd(), [](const Import &import) {
+ return import.uri.moduleUri() == u"QtQuick";
+ });
+ if (it == imports.constEnd()) {
+ return;
+ }
+
+ // for default bindings:
+ suggestSnippetsForRightHandSideOfBinding(itemAtPosition, result);
+
+ // check if the user already typed some qualifier, remove its dot and compare it to QtQuick's
+ // qualified name
+ const QString userTypedQualifier = QQmlLSUtils::qualifiersFrom(itemAtPosition);
+ if (!userTypedQualifier.isEmpty()
+ && !it->importId.startsWith(QStringView(userTypedQualifier).chopped(1))) {
+ return;
+ }
+
+ const QByteArray prefixForSnippet =
+ userTypedQualifier.isEmpty() ? it->importId.toUtf8() : QByteArray();
+ const QByteArray prefixWithDotForSnippet =
+ prefixForSnippet.isEmpty() ? QByteArray() : QByteArray(prefixForSnippet).append(u'.');
+
+ auto resolver = file->typeResolver();
+ if (!resolver)
+ return;
+ const auto qquickItemScope = resolver->typeForName(prefixWithDotForSnippet + u"Item"_s);
+ const QQmlJSScope::ConstPtr ownerScope = itemAtPosition.qmlObject().semanticScope();
+ if (!ownerScope || !qquickItemScope)
+ return;
+
+ if (ownerScope->inherits(qquickItemScope)) {
+ result = QQmlLSCompletion::makeSnippet(
+ "states binding with PropertyChanges in State",
+ "states: [\n"
+ "\t"_ba.append(prefixWithDotForSnippet)
+ .append("State {\n"
+ "\t\tname: \"${1:name}\"\n"
+ "\t\t"_ba.append(prefixWithDotForSnippet)
+ .append("PropertyChanges {\n"
+ "\t\t\ttarget: ${2:object}\n"
+ "\t\t}\n"
+ "\t}\n"
+ "]")));
+ result = QQmlLSCompletion::makeSnippet("transitions binding with Transition",
+ "transitions: [\n"
+ "\t"_ba.append(prefixWithDotForSnippet)
+ .append("Transition {\n"
+ "\t\tfrom: \"${1:fromState}\"\n"
+ "\t\tto: \"${2:fromState}\"\n"
+ "\t}\n"
+ "]"));
+ }
+}
+
+void QQmlLSQuickCompletionPlugin::suggestSnippetsForRightHandSideOfBinding(
+ const DomItem &itemAtPosition, BackInsertIterator result) const
+{
+ auto file = itemAtPosition.containingFile().as<QmlFile>();
+ if (!file)
+ return;
+
+ // check if QtQuick has been imported
+ const auto &imports = file->imports();
+ auto it = std::find_if(imports.constBegin(), imports.constEnd(), [](const Import &import) {
+ return import.uri.moduleUri() == u"QtQuick";
+ });
+ if (it == imports.constEnd()) {
+ return;
+ }
+
+ // check if the user already typed some qualifier, remove its dot and compare it to QtQuick's
+ // qualified name
+ const QString userTypedQualifier = QQmlLSUtils::qualifiersFrom(itemAtPosition);
+ if (!userTypedQualifier.isEmpty()
+ && !it->importId.startsWith(QStringView(userTypedQualifier).chopped(1))) {
+ return;
+ }
+
+ const QByteArray prefixForSnippet =
+ userTypedQualifier.isEmpty() ? it->importId.toUtf8() : QByteArray();
+ const QByteArray prefixWithDotForSnippet =
+ prefixForSnippet.isEmpty() ? QByteArray() : QByteArray(prefixForSnippet).append(u'.');
+
+ // Quick completions from Qt Creator's code model
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "BorderImage snippet",
+ "BorderImage {\n"
+ "\tid: ${1:name}\n"
+ "\tsource: \"${2:file}\"\n"
+ "\twidth: ${3:100}; height: ${4:100}\n"
+ "\tborder.left: ${5: 5}; border.top: ${5}\n"
+ "\tborder.right: ${5}; border.bottom: ${5}\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "ColorAnimation snippet",
+ "ColorAnimation {\n"
+ "\tfrom: \"${1:white}\"\n"
+ "\tto: \"${2:black}\"\n"
+ "\tduration: ${3:200}\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "Image snippet",
+ "Image {\n"
+ "\tid: ${1:name}\n"
+ "\tsource: \"${2:file}\"\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "Item snippet",
+ "Item {\n"
+ "\tid: ${1:name}\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "NumberAnimation snippet",
+ "NumberAnimation {\n"
+ "\ttarget: ${1:object}\n"
+ "\tproperty: \"${2:name}\"\n"
+ "\tduration: ${3:200}\n"
+ "\teasing.type: "_ba.append(prefixWithDotForSnippet)
+ .append("Easing.${4:InOutQuad}\n"
+ "}"));
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "NumberAnimation with targets snippet",
+ "NumberAnimation {\n"
+ "\ttargets: [${1:object}]\n"
+ "\tproperties: \"${2:name}\"\n"
+ "\tduration: ${3:200}\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "PauseAnimation snippet",
+ "PauseAnimation {\n"
+ "\tduration: ${1:200}\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "PropertyAction snippet",
+ "PropertyAction {\n"
+ "\ttarget: ${1:object}\n"
+ "\tproperty: \"${2:name}\"\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "PropertyAction with targets snippet",
+ "PropertyAction {\n"
+ "\ttargets: [${1:object}]\n"
+ "\tproperties: \"${2:name}\"\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "PropertyChanges snippet",
+ "PropertyChanges {\n"
+ "\ttarget: ${1:object}\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "State snippet",
+ "State {\n"
+ "\tname: ${1:name}\n"
+ "\t"_ba.append(prefixWithDotForSnippet)
+ .append("PropertyChanges {\n"
+ "\t\ttarget: ${2:object}\n"
+ "\t}\n"
+ "}"));
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "Text snippet",
+ "Text {\n"
+ "\tid: ${1:name}\n"
+ "\ttext: qsTr(\"${2:text}\")\n"
+ "}");
+ result = QQmlLSCompletion::makeSnippet(prefixForSnippet, "Transition snippet",
+ "Transition {\n"
+ "\tfrom: \"${1:fromState}\"\n"
+ "\tto: \"${2:toState}\"\n"
+ "}");
+}
+
+QT_END_NAMESPACE