Revision control
++ // Copyright (C) 2024 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++ // Qt-Security score:significant reason:default
++
++ #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 =
++ it->importId.isEmpty() ? QByteArray() : it->importId.toUtf8().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 =
++ it->importId.isEmpty() ? QByteArray() : it->importId.toUtf8().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