1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qqmllsquickplugin_p.h"
5#include <QtQmlLS/private/qqmllsutils_p.h>
6#include <QtQmlLS/private/qqmllscompletion_p.h>
7
8using namespace QLspSpecification;
9using namespace QQmlJS::Dom;
10
11QT_BEGIN_NAMESPACE
12
13std::unique_ptr<QQmlLSCompletionPlugin> QQmlLSQuickPlugin::createCompletionPlugin() const
14{
15 return std::make_unique<QQmlLSQuickCompletionPlugin>();
16}
17
18void QQmlLSQuickCompletionPlugin::suggestSnippetsForLeftHandSideOfBinding(
19 const DomItem &itemAtPosition, BackInsertIterator result) const
20{
21 auto file = itemAtPosition.containingFile().as<QmlFile>();
22 if (!file)
23 return;
24
25 // check if QtQuick has been imported
26 const auto &imports = file->imports();
27 auto it = std::find_if(first: imports.constBegin(), last: imports.constEnd(), pred: [](const Import &import) {
28 return import.uri.moduleUri() == u"QtQuick";
29 });
30 if (it == imports.constEnd()) {
31 return;
32 }
33
34 // for default bindings:
35 suggestSnippetsForRightHandSideOfBinding(items: itemAtPosition, result);
36
37 // check if the user already typed some qualifier, remove its dot and compare it to QtQuick's
38 // qualified name
39 const QString userTypedQualifier = QQmlLSUtils::qualifiersFrom(el: itemAtPosition);
40 if (!userTypedQualifier.isEmpty()
41 && !it->importId.startsWith(s: QStringView(userTypedQualifier).chopped(n: 1))) {
42 return;
43 }
44
45 const QByteArray prefixForSnippet =
46 userTypedQualifier.isEmpty() ? it->importId.toUtf8() : QByteArray();
47 const QByteArray prefixWithDotForSnippet =
48 it->importId.isEmpty() ? QByteArray() : it->importId.toUtf8().append(c: u'.');
49
50 auto resolver = file->typeResolver();
51 if (!resolver)
52 return;
53 const auto qquickItemScope = resolver->typeForName(name: prefixWithDotForSnippet + u"Item"_s);
54 const QQmlJSScope::ConstPtr ownerScope = itemAtPosition.qmlObject().semanticScope();
55 if (!ownerScope || !qquickItemScope)
56 return;
57
58 if (ownerScope->inherits(base: qquickItemScope)) {
59 result = QQmlLSCompletion::makeSnippet(
60 label: "states binding with PropertyChanges in State",
61 insertText: "states: [\n"
62 "\t"_ba.append(a: prefixWithDotForSnippet)
63 .append(a: "State {\n"
64 "\t\tname: \"${1:name}\"\n"
65 "\t\t"_ba.append(a: prefixWithDotForSnippet)
66 .append(s: "PropertyChanges {\n"
67 "\t\t\ttarget: ${2:object}\n"
68 "\t\t}\n"
69 "\t}\n"
70 "]")));
71 result = QQmlLSCompletion::makeSnippet(label: "transitions binding with Transition",
72 insertText: "transitions: [\n"
73 "\t"_ba.append(a: prefixWithDotForSnippet)
74 .append(s: "Transition {\n"
75 "\t\tfrom: \"${1:fromState}\"\n"
76 "\t\tto: \"${2:fromState}\"\n"
77 "\t}\n"
78 "]"));
79 }
80}
81
82void QQmlLSQuickCompletionPlugin::suggestSnippetsForRightHandSideOfBinding(
83 const DomItem &itemAtPosition, BackInsertIterator result) const
84{
85 auto file = itemAtPosition.containingFile().as<QmlFile>();
86 if (!file)
87 return;
88
89 // check if QtQuick has been imported
90 const auto &imports = file->imports();
91 auto it = std::find_if(first: imports.constBegin(), last: imports.constEnd(), pred: [](const Import &import) {
92 return import.uri.moduleUri() == u"QtQuick";
93 });
94 if (it == imports.constEnd()) {
95 return;
96 }
97
98 // check if the user already typed some qualifier, remove its dot and compare it to QtQuick's
99 // qualified name
100 const QString userTypedQualifier = QQmlLSUtils::qualifiersFrom(el: itemAtPosition);
101 if (!userTypedQualifier.isEmpty()
102 && !it->importId.startsWith(s: QStringView(userTypedQualifier).chopped(n: 1))) {
103 return;
104 }
105
106 const QByteArray prefixForSnippet =
107 userTypedQualifier.isEmpty() ? it->importId.toUtf8() : QByteArray();
108 const QByteArray prefixWithDotForSnippet =
109 it->importId.isEmpty() ? QByteArray() : it->importId.toUtf8().append(c: u'.');
110
111 // Quick completions from Qt Creator's code model
112 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "BorderImage snippet",
113 insertText: "BorderImage {\n"
114 "\tid: ${1:name}\n"
115 "\tsource: \"${2:file}\"\n"
116 "\twidth: ${3:100}; height: ${4:100}\n"
117 "\tborder.left: ${5: 5}; border.top: ${5}\n"
118 "\tborder.right: ${5}; border.bottom: ${5}\n"
119 "}");
120 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "ColorAnimation snippet",
121 insertText: "ColorAnimation {\n"
122 "\tfrom: \"${1:white}\"\n"
123 "\tto: \"${2:black}\"\n"
124 "\tduration: ${3:200}\n"
125 "}");
126 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "Image snippet",
127 insertText: "Image {\n"
128 "\tid: ${1:name}\n"
129 "\tsource: \"${2:file}\"\n"
130 "}");
131 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "Item snippet",
132 insertText: "Item {\n"
133 "\tid: ${1:name}\n"
134 "}");
135 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "NumberAnimation snippet",
136 insertText: "NumberAnimation {\n"
137 "\ttarget: ${1:object}\n"
138 "\tproperty: \"${2:name}\"\n"
139 "\tduration: ${3:200}\n"
140 "\teasing.type: "_ba.append(a: prefixWithDotForSnippet)
141 .append(s: "Easing.${4:InOutQuad}\n"
142 "}"));
143 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "NumberAnimation with targets snippet",
144 insertText: "NumberAnimation {\n"
145 "\ttargets: [${1:object}]\n"
146 "\tproperties: \"${2:name}\"\n"
147 "\tduration: ${3:200}\n"
148 "}");
149 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "PauseAnimation snippet",
150 insertText: "PauseAnimation {\n"
151 "\tduration: ${1:200}\n"
152 "}");
153 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "PropertyAction snippet",
154 insertText: "PropertyAction {\n"
155 "\ttarget: ${1:object}\n"
156 "\tproperty: \"${2:name}\"\n"
157 "}");
158 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "PropertyAction with targets snippet",
159 insertText: "PropertyAction {\n"
160 "\ttargets: [${1:object}]\n"
161 "\tproperties: \"${2:name}\"\n"
162 "}");
163 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "PropertyChanges snippet",
164 insertText: "PropertyChanges {\n"
165 "\ttarget: ${1:object}\n"
166 "}");
167 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "State snippet",
168 insertText: "State {\n"
169 "\tname: ${1:name}\n"
170 "\t"_ba.append(a: prefixWithDotForSnippet)
171 .append(s: "PropertyChanges {\n"
172 "\t\ttarget: ${2:object}\n"
173 "\t}\n"
174 "}"));
175 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "Text snippet",
176 insertText: "Text {\n"
177 "\tid: ${1:name}\n"
178 "\ttext: qsTr(\"${2:text}\")\n"
179 "}");
180 result = QQmlLSCompletion::makeSnippet(qualifier: prefixForSnippet, label: "Transition snippet",
181 insertText: "Transition {\n"
182 "\tfrom: \"${1:fromState}\"\n"
183 "\tto: \"${2:toState}\"\n"
184 "}");
185}
186
187QT_END_NAMESPACE
188

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/plugins/qmlls/quick/qqmllsquickplugin.cpp