diff options
Diffstat (limited to 'src/plugins/qmlls/quick/qqmllsquickplugin.cpp')
-rw-r--r-- | src/plugins/qmlls/quick/qqmllsquickplugin.cpp | 187 |
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 |