Skip to content

Commit 2deba80

Browse files
committed
## 2023.1.16
- update: add completions for helper positional parameters - update: add event types for on modifier - fix: gts tag references to classes
1 parent 6f386b1 commit 2deba80

File tree

10 files changed

+82
-29
lines changed

10 files changed

+82
-29
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
Changelog
44
===============================================================================
5+
## 2023.1.16
6+
- update: add completions for helper positional parameters
7+
- update: add event types for on modifier
8+
- fix: gts tag references to classes
9+
510
## 2023.1.15
611
- fix: support older glint lsp messages
712

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ plugins {
1313

1414

1515
group = "com.emberjs"
16-
version = "2023.1.15"
16+
version = "2023.1.16"
1717

1818
// Configure project's dependencies
1919
repositories {

src/main/kotlin/com/emberjs/hbs/HbsCompletionContributor.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import com.emberjs.hbs.HbsPatterns.BLOCK_MUSTACHE_NAME_ID
44
import com.emberjs.hbs.HbsPatterns.BLOCK_MUSTACHE_PARAM
55
import com.emberjs.hbs.HbsPatterns.IMPORT_NAMES
66
import com.emberjs.hbs.HbsPatterns.IMPORT_PATH_AUTOCOMPLETE
7-
import com.emberjs.hbs.HbsPatterns.MUSTACHE_ID_MISSING
87
import com.emberjs.hbs.HbsPatterns.MUSTACHE_ID
8+
import com.emberjs.hbs.HbsPatterns.MUSTACHE_ID_MISSING
99
import com.emberjs.hbs.HbsPatterns.SIMPLE_MUSTACHE_NAME_ID
10+
import com.emberjs.hbs.HbsPatterns.STRING_PARAM_OTHER
1011
import com.emberjs.hbs.HbsPatterns.SUB_EXPR_NAME_ID
1112
import com.emberjs.hbs.HbsPatterns.inXmlTag
1213
import com.intellij.codeInsight.completion.CompletionContributor
1314
import com.intellij.codeInsight.completion.CompletionType
14-
import com.intellij.patterns.XmlTagPattern
1515

1616

1717
val InternalsWithBlock = arrayListOf(
@@ -77,6 +77,7 @@ class HbsCompletionContributor : CompletionContributor() {
7777
extend(CompletionType.BASIC, IMPORT_PATH_AUTOCOMPLETE, HbsLocalCompletion())
7878
extend(CompletionType.BASIC, BLOCK_MUSTACHE_PARAM, HbsLocalCompletion())
7979
extend(CompletionType.BASIC, MUSTACHE_ID_MISSING, HbsLocalCompletion())
80+
extend(CompletionType.BASIC, STRING_PARAM_OTHER, HbsLocalCompletion())
8081
extend(CompletionType.BASIC, inXmlTag, HbsLocalCompletion())
8182
}
8283
}

src/main/kotlin/com/emberjs/hbs/HbsLocalCompletion.kt

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package com.emberjs.hbs
22

33
import com.dmarcotte.handlebars.parsing.HbTokenTypes
4-
import com.dmarcotte.handlebars.psi.HbData
5-
import com.dmarcotte.handlebars.psi.HbMustache
6-
import com.dmarcotte.handlebars.psi.HbParam
7-
import com.dmarcotte.handlebars.psi.HbStringLiteral
4+
import com.dmarcotte.handlebars.psi.*
85
import com.dmarcotte.handlebars.psi.impl.HbBlockWrapperImpl
96
import com.dmarcotte.handlebars.psi.impl.HbPathImpl
107
import com.emberjs.glint.GlintLanguageServiceProvider
@@ -157,16 +154,32 @@ class HbsLocalCompletion : CompletionProvider<CompletionParameters>() {
157154
resolve(followed, result)
158155
}
159156

160-
fun addHelperCompletions(element: PsiElement, result: MutableList<LookupElement>) {
157+
fun addHelperCompletions(element: PsiElement, result: MutableList<LookupElement>, currentPosition: Int) {
161158
val file = EmberUtils.followReferences(element.children.firstOrNull())
159+
val hashNames = element.parent.children.filter { it is HbHash }.map { (it as HbHash).hashName }
160+
val params = element.parent.children.filter { it is HbParam }
161+
val param = params.getOrNull(currentPosition)
162+
163+
val isLiteral = PsiTreeUtil.findChildOfType(param, HbStringLiteral::class.java) != null
164+
|| PsiTreeUtil.findChildOfType(param, HbNumberLiteral::class.java) != null
162165

163-
if (file is JSClass) {
164-
val ref = EmberUtils.getComponentReferenceData(file.containingFile)
165-
result.addAll(ref.args.map { LookupElementBuilder.create(it.value + "=") })
166-
}
167166
val map = EmberUtils.getArgsAndPositionals(element)
168-
val named = map.named.map { LookupElementBuilder.create(it + "=") }
169-
result.addAll(named.map { PrioritizedLookupElement.withPriority(it, 100.0) })
167+
168+
if (!isLiteral) {
169+
if (file is JSClass) {
170+
val ref = EmberUtils.getComponentReferenceData(file.containingFile)
171+
val args = ref.args.filter { !hashNames.contains(it.value) }
172+
result.addAll(args.map { LookupElementBuilder.create("${it.value}=") })
173+
}
174+
val named = map.named.filter { !hashNames.contains(it) }.map { LookupElementBuilder.create("$it=") }
175+
result.addAll(named.map { PrioritizedLookupElement.withPriority(it, 100.0) })
176+
}
177+
178+
if (currentPosition >= 0) {
179+
map.positionalOptions.getOrDefault(currentPosition, null)
180+
?.map { isLiteral.ifTrue { it.replace("'", "").replace("\"", "") } ?: it }
181+
?.map { LookupElementBuilder.create(it) }?.toCollection(result)
182+
}
170183
}
171184

172185
fun addImportPathCompletions(element: PsiElement, result: CompletionResultSet) {
@@ -253,7 +266,7 @@ class HbsLocalCompletion : CompletionProvider<CompletionParameters>() {
253266
val children = PsiTreeUtil.collectElements(f) { it is JSVariable || it is ES6ImportDeclaration }
254267
children.forEach {
255268
if (it is JSVariable) {
256-
val useScope = JSUseScopeProvider.getUseScopeElement(it)
269+
val useScope = JSUseScopeProvider.getBlockScopeElement(it)
257270
if (useScope.isAncestor(tpl)) {
258271
result.addElement(LookupElementBuilder.create(it.name!!))
259272
}
@@ -317,10 +330,13 @@ class HbsLocalCompletion : CompletionProvider<CompletionParameters>() {
317330

318331
val helperElement = EmberUtils.findFirstHbsParamFromParam(element)
319332
if (helperElement != null && parameters.position.parent.prevSibling.elementType != HbTokenTypes.SEP) {
320-
addHelperCompletions(helperElement, result)
333+
val params = helperElement.parent.children.filter { it is HbParam }
334+
val currentParam = params.find { it.textRange.contains(element.textRange) }
335+
val pos = params.indexOf(currentParam)
336+
addHelperCompletions(helperElement, result, pos)
321337
val r = EmberUtils.handleEmberHelpers(helperElement.parent)
322338
if (r != null) {
323-
addHelperCompletions(r.children[0].children[0], result)
339+
addHelperCompletions(r.children[0].children[0], result, pos)
324340
}
325341
}
326342

src/main/kotlin/com/emberjs/hbs/HbsLocalReference.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class HbsLocalReference(private val leaf: PsiElement, val resolved: Any?) : HbRe
149149
val children = PsiTreeUtil.collectElements(f) { it is JSVariable || it is ES6ImportDeclaration }
150150
current = children.mapNotNull {
151151
if (it is JSVariable && it.name?.equals(parts.first()) == true) {
152-
val useScope = JSUseScopeProvider.getUseScopeElement(it)
152+
val useScope = JSUseScopeProvider.getBlockScopeElement(it)
153153
if (useScope.isAncestor(tpl as PsiElement)) {
154154
return@mapNotNull it
155155
}

src/main/kotlin/com/emberjs/hbs/HbsPatterns.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ package com.emberjs.hbs
22

33
import com.dmarcotte.handlebars.parsing.HbTokenTypes
44
import com.dmarcotte.handlebars.psi.*
5-
import com.intellij.codeInsight.template.HtmlContextType
65
import com.intellij.patterns.PlatformPatterns.psiElement
76
import com.intellij.patterns.PsiElementPattern.Capture
87
import com.intellij.psi.PsiElement
98
import com.intellij.psi.PsiWhiteSpace
10-
import com.intellij.psi.html.HtmlTag
119
import com.intellij.psi.impl.source.html.HtmlTagImpl
1210

1311
object HbsPatterns {
@@ -84,6 +82,13 @@ object HbsPatterns {
8482
.withParent(psiElement(HbParam::class.java))
8583
.afterSiblingSkipping(psiElement(PsiWhiteSpace::class.java), psiElement(HbParam::class.java).withText("t"))
8684

85+
val STRING_PARAM_OTHER: Capture<PsiElement> = psiElement(HbTokenTypes.STRING).withAncestor(10, STRING_PARAM.andNot(COMPONENT_KEY)
86+
.andNot(COMPONENT_KEY_IN_SEXPR)
87+
.andNot(LINK_TO_BLOCK_TARGET)
88+
.andNot(LINK_TO_SIMPLE_TARGET)
89+
.andNot(TRANSLATION_KEY)
90+
.andNot(TRANSLATION_KEY_IN_SEXPR))
91+
8792
val CONTENT: Capture<PsiElement> = psiElement(HbTokenTypes.STATEMENTS).withParent(HbPsiFile::class.java)
8893
val inXmlTag: Capture<PsiElement> = psiElement().withAncestor(10, psiElement(HtmlTagImpl::class.java))
8994
}

src/main/kotlin/com/emberjs/hbs/TagReferencesProvider.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.intellij.lang.javascript.psi.JSTypeOwner
2525
import com.intellij.lang.javascript.psi.JSVariable
2626
import com.intellij.lang.javascript.psi.ecma6.ES6TaggedTemplateExpression
2727
import com.intellij.lang.javascript.psi.ecma6.TypeScriptTypeofType
28+
import com.intellij.lang.javascript.psi.ecmal4.JSClass
2829
import com.intellij.lang.javascript.psi.impl.JSOuterLanguageElementExpressionImpl
2930
import com.intellij.lang.javascript.psi.impl.JSUseScopeProvider
3031
import com.intellij.lang.javascript.psi.resolve.JSContextResolver
@@ -162,10 +163,17 @@ class TagReferencesProvider : PsiReferenceProvider() {
162163
if (parts.first() == "this") {
163164
current = JSContextResolver.resolveThisReference(tpl as PsiElement)
164165
} else {
165-
val children = PsiTreeUtil.collectElements(f) { it is JSVariable || it is ES6ImportDeclaration }
166+
val children = PsiTreeUtil.collectElements(f) { it is JSVariable || it is ES6ImportDeclaration || it is JSClass }
166167
current = children.mapNotNull {
167168
if (it is JSVariable && it.name?.equals(parts.first()) == true) {
168-
val useScope = JSUseScopeProvider.getUseScopeElement(it)
169+
val useScope = JSUseScopeProvider.getBlockScopeElement(it)
170+
if (useScope.isAncestor(tpl as PsiElement)) {
171+
return@mapNotNull it
172+
}
173+
}
174+
175+
if (it is JSClass && it.name?.equals(parts.first()) == true) {
176+
val useScope = JSUseScopeProvider.getBlockScopeElement(it)
169177
if (useScope.isAncestor(tpl as PsiElement)) {
170178
return@mapNotNull it
171179
}

src/main/kotlin/com/emberjs/utils/EmberUtils.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.emberjs.resolver.ProjectFile
1919
import com.emberjs.xml.AttrPsiReference
2020
import com.emberjs.xml.EmberAttrDec
2121
import com.emberjs.xml.EmberXmlElementDescriptor
22+
import com.intellij.application.options.CodeStyle
2223
import com.intellij.framework.detection.impl.FrameworkDetectionManager
2324
import com.intellij.injected.editor.VirtualFileWindow
2425
import com.intellij.lang.Language
@@ -32,16 +33,16 @@ import com.intellij.lang.javascript.psi.*
3233
import com.intellij.lang.javascript.psi.ecma6.*
3334
import com.intellij.lang.javascript.psi.ecma6.impl.TypeScriptClassImpl
3435
import com.intellij.lang.javascript.psi.ecma6.impl.TypeScriptTupleTypeImpl
36+
import com.intellij.lang.javascript.psi.ecma6.impl.TypeScriptUnionOrIntersectionTypeImpl
3537
import com.intellij.lang.javascript.psi.ecmal4.JSClass
3638
import com.intellij.lang.javascript.psi.impl.JSDestructuringParameterImpl
3739
import com.intellij.lang.javascript.psi.jsdoc.JSDocComment
38-
import com.intellij.lang.javascript.psi.types.JSArrayType
39-
import com.intellij.lang.javascript.psi.types.JSGenericTypeImpl
40-
import com.intellij.lang.javascript.psi.types.JSTupleType
41-
import com.intellij.lang.javascript.psi.types.JSTypeImpl
40+
import com.intellij.lang.javascript.psi.types.*
4241
import com.intellij.openapi.project.Project
4342
import com.intellij.openapi.project.guessProjectDir
4443
import com.intellij.psi.*
44+
import com.intellij.psi.codeStyle.CodeStyleSettings
45+
import com.intellij.psi.formatter.xml.HtmlCodeStyleSettings
4546
import com.intellij.psi.impl.file.PsiDirectoryImpl
4647
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference
4748
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet
@@ -371,7 +372,9 @@ class EmberUtils {
371372

372373
class ArgsAndPositionals {
373374
val positional: MutableList<String?> = mutableListOf()
375+
val positionalOptions = mutableMapOf<Int, List<String>>()
374376
val named: MutableList<String?> = mutableListOf()
377+
val namedOptions = mapOf<String, List<String>>()
375378
val namedRefs: MutableList<PsiElement?> = mutableListOf()
376379
var restparamnames: String? = null
377380
}
@@ -438,10 +441,22 @@ class EmberUtils {
438441
args = args.asRecordType()
439442
}
440443

444+
val settings = CodeStyle.getCustomSettings(helperhelperOrModifier.containingFile, HtmlCodeStyleSettings::class.java)
445+
val quote = (settings.HTML_QUOTE_STYLE == CodeStyleSettings.QuoteStyle.Double).ifTrue { '"' } ?: "'"
441446
if (args is JSRecordType) {
442447
array = args.findPropertySignature("positional")?.jsType
443448
named = args.findPropertySignature("named")?.jsType?.asRecordType()?.propertyNames
444449
refs = args.findPropertySignature("named")?.jsType?.asRecordType()?.properties?.toList()
450+
val options = (array as? JSTupleType)?.types?.mapIndexed { index, it ->
451+
if (it is TypeScriptTypeOperatorJSTypeImpl && it.typeText.startsWith("keyof ")) {
452+
return@mapIndexed Pair(index, it.referencedType.asRecordType().propertyNames.map { "${quote}${it}${quote}" })
453+
}
454+
val types = (it.asRecordType().sourceElement as? TypeScriptUnionOrIntersectionTypeImpl)?.types
455+
val typesStr = types?.map { (it as? TypeScriptLiteralType?)?.let { it.innerText } }?.filterNotNull() ?: arrayListOf()
456+
457+
return@mapIndexed Pair(index, typesStr.map { "${quote}${it}${quote}" })
458+
}
459+
options?.toMap(data.positionalOptions)
445460
arrayName = "positional"
446461
}
447462

src/main/kotlin/com/emberjs/xml/EmberAttributeDescriptor.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.emberjs.xml
33
import com.intellij.lang.javascript.psi.ecma6.TypeScriptLiteralType
44
import com.intellij.lang.javascript.psi.ecma6.impl.TypeScriptPropertySignatureImpl
55
import com.intellij.lang.javascript.psi.ecma6.impl.TypeScriptUnionOrIntersectionTypeImpl
6+
import com.intellij.lang.javascript.psi.types.TypeScriptTypeOperatorJSTypeImpl
67
import com.intellij.psi.PsiElement
78
import com.intellij.psi.PsiReference
89
import com.intellij.psi.util.PsiTreeUtil
@@ -16,7 +17,7 @@ class EmberAttributeDescriptor(val context: XmlTag, value: String, isYield: Bool
1617
private val description: String
1718
private val declaration: PsiElement?
1819
private val isRequired: Boolean
19-
private val values: List<String>
20+
private var values: List<String>
2021
private var hasNonLiteralTypes: Boolean
2122
val reference: PsiReference?
2223
val xmlattr: XmlAttribute?
@@ -42,7 +43,9 @@ class EmberAttributeDescriptor(val context: XmlTag, value: String, isYield: Bool
4243
if (ref != null) {
4344
val type = PsiTreeUtil.collectElementsOfType(ref.resolve(), TypeScriptPropertySignatureImpl::class.java).firstOrNull()
4445
val types = (type?.jsType?.asRecordType()?.sourceElement as? TypeScriptUnionOrIntersectionTypeImpl?)?.types
45-
val typesStr = types?.map { (it as? TypeScriptLiteralType?)?.let { it.innerText } }?.filterNotNull() ?: arrayListOf()
46+
val typesStr = types?.map { (it as? TypeScriptLiteralType?)?.let { it.innerText } }?.filterNotNull()
47+
?: (type?.jsType as? TypeScriptTypeOperatorJSTypeImpl)?.let { it.referencedType.asRecordType().propertyNames.toList() }
48+
?: arrayListOf()
4649
val isOptional = (type?.isOptional ?: true) || typesStr.isEmpty() || (typesStr.contains("undefined") || typesStr.contains("null") || typesStr.contains("*"))
4750
this.isRequired = !isOptional
4851
this.values = typesStr

src/main/resources/com/emberjs/external/ember-modifiers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
type OnArgs = {
3-
positional: [event: string, fn: Function]
3+
positional: [event: keyof GlobalEventHandlersEventMap, fn: Function]
44
}
55
function on(_, __, args: OnArgs): any {}
66

0 commit comments

Comments
 (0)