Skip to content

Commit 21de673

Browse files
committed
imrovements and fixes
1 parent 8cdef89 commit 21de673

16 files changed

+262
-110
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class EmberAttributeDescriptor(val context: XmlTag, value: String, isYield: Bool
4343
val ref = reference
4444
this.hasNonLiteralTypes = true
4545
if (ref != null) {
46-
val type = PsiTreeUtil.collectElementsOfType(ref.element, TypeScriptPropertySignatureImpl::class.java).firstOrNull()
46+
val type = PsiTreeUtil.collectElementsOfType(ref.resolve(), TypeScriptPropertySignatureImpl::class.java).firstOrNull()
4747
val types = (type?.jsType?.asRecordType()?.sourceElement as? TypeScriptUnionOrIntersectionTypeImpl?)?.types
4848
val typesStr = types?.map { (it as? TypeScriptLiteralType?)?.let { it.innerText } }?.filterNotNull() ?: arrayListOf()
4949
val isOptional = (type?.isOptional ?: true) || typesStr.isEmpty() || (typesStr.contains("undefined") || typesStr.contains("null") || typesStr.contains("*"))

src/main/kotlin/com/emberjs/EmberXmlElementDescriptor.kt

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
package com.emberjs
2+
import com.emberjs.glint.GlintLanguageServiceProvider
23
import com.emberjs.index.EmberNameIndex
34
import com.emberjs.psi.EmberNamedElement
45
import com.emberjs.utils.*
6+
import com.intellij.codeInsight.completion.CompletionParameters
7+
import com.intellij.codeInsight.completion.CompletionProcess
8+
import com.intellij.codeInsight.completion.CompletionType
59
import com.intellij.codeInsight.documentation.DocumentationManager.ORIGINAL_ELEMENT_KEY
6-
import com.intellij.lang.Language
7-
import com.intellij.lang.injection.InjectedLanguageManager
810
import com.intellij.lang.javascript.psi.JSFile
911
import com.intellij.lang.javascript.psi.JSNamedElement
10-
import com.intellij.lang.javascript.psi.ecma6.JSStringTemplateExpression
11-
import com.intellij.lang.javascript.psi.ecma6.JSTypedEntity
1212
import com.intellij.psi.*
1313
import com.intellij.psi.impl.source.html.dtd.HtmlNSDescriptorImpl
1414
import com.intellij.psi.impl.source.xml.XmlDescriptorUtil
15-
import com.intellij.psi.search.ProjectScope
16-
import com.intellij.psi.util.PsiTreeUtil
1715
import com.intellij.psi.xml.XmlAttribute
1816
import com.intellij.psi.xml.XmlTag
1917
import com.intellij.xml.XmlAttributeDescriptor
@@ -22,6 +20,15 @@ import com.intellij.xml.XmlElementsGroup
2220
import com.intellij.xml.XmlNSDescriptor
2321

2422

23+
class GlintReference(val elem: PsiElement): PsiReferenceBase<PsiElement>(elem) {
24+
override fun resolve(): PsiElement? {
25+
val psiFile = PsiManager.getInstance(elem.project).findFile(elem.originalVirtualFile!!)
26+
val document = PsiDocumentManager.getInstance(elem.project).getDocument(psiFile!!)!!
27+
val service = GlintLanguageServiceProvider(elem.project).getService(elem.originalVirtualFile!!)
28+
return service?.getNavigationFor(document, elem)?.firstOrNull()
29+
}
30+
31+
}
2532

2633
class EmberXmlElementDescriptor(private val tag: XmlTag, private val declaration: PsiElement?) : XmlElementDescriptor {
2734
val project = tag.project
@@ -142,7 +149,10 @@ class EmberXmlElementDescriptor(private val tag: XmlTag, private val declaration
142149
}
143150
return EmberAttributeDescriptor(context, attributeName, true, "yield", null, emptyArray())
144151
}
145-
return this.getAttributesDescriptors(context).find { it.name == attributeName }
152+
val attr = context.attributes.find { it.name == attributeName }
153+
return this.getAttributesDescriptors(context).find { it.name == attributeName } ?:
154+
attr?.let { EmberAttributeDescriptor(context, attributeName, true, "yield", GlintReference(it), emptyArray()) }
155+
146156
}
147157
override fun getAttributeDescriptor(attribute: XmlAttribute?): XmlAttributeDescriptor?
148158
= getAttributeDescriptor(attribute?.name, attribute?.parent)

src/main/kotlin/com/emberjs/glint/GlintLanguageService.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,11 @@ class GlintTypeScriptService(private val project: Project) : TypeScriptService,
113113
return completedFuture(items.map { GlintCompletionEntry(descriptor.getResolvedCompletionItem((it as GlintCompletionEntry).item)) })
114114
}
115115

116-
override fun getNavigationFor(document: Document, sourceElement: PsiElement): Array<PsiElement> =
117-
getDescriptor()?.getElementDefinitions(sourceElement)?.toTypedArray() ?: emptyArray()
116+
override fun getNavigationFor(document: Document, sourceElement: PsiElement): Array<PsiElement> {
117+
val element = sourceElement.getContainingFile().getOriginalFile().findElementAt(sourceElement.textOffset)
118+
return getDescriptor()?.getElementDefinitions(element)?.toTypedArray() ?: emptyArray()
119+
}
120+
118121

119122
override fun getSignatureHelp(file: PsiFile, context: CreateParameterInfoContext): Future<Stream<JSFunctionType>?>? = null
120123

@@ -173,6 +176,7 @@ class GlintTypeScriptService(private val project: Project) : TypeScriptService,
173176

174177
class GlintCompletionEntry(internal val item: LspCompletionItem) : TypeScriptService.CompletionEntry {
175178
override val name: String get() = item.label
179+
val detail: String? get() = item.detail
176180

177181
override fun intoLookupElement() = item.intoLookupElement()
178182
}

src/main/kotlin/com/emberjs/glint/GlintLspSupportProvider.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project
1515
import com.intellij.openapi.project.guessProjectDir
1616
import com.intellij.openapi.vfs.VfsUtilCore
1717
import com.intellij.openapi.vfs.VirtualFile
18+
import com.intellij.util.FileContentUtil
1819
import java.nio.charset.StandardCharsets
1920

2021
class GlintLspSupportProvider : LspServerSupportProvider {
@@ -41,13 +42,23 @@ class GlintLanguageServerConnectorStdio(serverDescriptor: LspServerDescriptor, p
4142
}
4243
return path
4344
}
45+
46+
override fun initializeServer() {
47+
super.initializeServer()
48+
ApplicationManager.getApplication().invokeLater {
49+
ApplicationManager.getApplication().runWriteAction {
50+
FileContentUtil.reparseOpenedFiles()
51+
}
52+
}
53+
}
4454
}
4555

4656

4757
fun getGlintDescriptor(project: Project): GlintLspServerDescriptor {
4858
return project.getService(GlintLspServerDescriptor::class.java)
4959
}
5060

61+
5162
@Service
5263
class GlintLspServerDescriptor(private val myProject: Project) : LspServerDescriptor(), Disposable {
5364

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import com.emberjs.hbs.HbsPatterns.MUSTACHE_ID_MISSING
88
import com.emberjs.hbs.HbsPatterns.MUSTACHE_ID
99
import com.emberjs.hbs.HbsPatterns.SIMPLE_MUSTACHE_NAME_ID
1010
import com.emberjs.hbs.HbsPatterns.SUB_EXPR_NAME_ID
11+
import com.emberjs.hbs.HbsPatterns.inXmlTag
1112
import com.intellij.codeInsight.completion.CompletionContributor
1213
import com.intellij.codeInsight.completion.CompletionType
14+
import com.intellij.patterns.XmlTagPattern
1315

1416

1517
val InternalsWithBlock = arrayListOf(
@@ -75,5 +77,6 @@ class HbsCompletionContributor : CompletionContributor() {
7577
extend(CompletionType.BASIC, IMPORT_PATH_AUTOCOMPLETE, HbsLocalCompletion())
7678
extend(CompletionType.BASIC, BLOCK_MUSTACHE_PARAM, HbsLocalCompletion())
7779
extend(CompletionType.BASIC, MUSTACHE_ID_MISSING, HbsLocalCompletion())
80+
extend(CompletionType.BASIC, inXmlTag, HbsLocalCompletion())
7881
}
7982
}

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

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import com.dmarcotte.handlebars.psi.HbParam
77
import com.dmarcotte.handlebars.psi.HbStringLiteral
88
import com.dmarcotte.handlebars.psi.impl.HbBlockWrapperImpl
99
import com.dmarcotte.handlebars.psi.impl.HbPathImpl
10+
import com.emberjs.glint.GlintCompletionEntry
1011
import com.emberjs.glint.GlintLanguageServiceProvider
1112
import com.emberjs.lookup.HbsInsertHandler
1213
import com.emberjs.psi.EmberNamedElement
1314
import com.emberjs.utils.*
1415
import com.intellij.codeInsight.completion.CompletionParameters
1516
import com.intellij.codeInsight.completion.CompletionProvider
1617
import com.intellij.codeInsight.completion.CompletionResultSet
18+
import com.intellij.ide.highlighter.HtmlFileType
1719
import com.intellij.injected.editor.VirtualFileWindow
1820
import com.intellij.lang.Language
1921
import com.intellij.lang.ecmascript6.psi.ES6ImportDeclaration
@@ -33,6 +35,7 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement
3335
import com.intellij.psi.util.PsiTreeUtil
3436
import com.intellij.psi.util.elementType
3537
import com.intellij.psi.xml.XmlAttribute
38+
import com.intellij.util.FileContentUtil
3639
import com.intellij.util.ProcessingContext
3740
import com.intellij.codeInsight.lookup.LookupElementBuilder as IntelijLookupElementBuilder
3841

@@ -155,22 +158,14 @@ class HbsLocalCompletion : CompletionProvider<CompletionParameters>() {
155158

156159
fun addHelperCompletions(element: PsiElement, result: CompletionResultSet) {
157160
val file = EmberUtils.followReferences(element.children.firstOrNull())
158-
var func: JSFunction? = null
159-
if (file is JSFunction) {
160-
func = file
161-
}
161+
162162
if (file is JSClass) {
163163
val ref = EmberUtils.getComponentReferenceData(file.containingFile)
164164
result.addAllElements(ref.args.map { LookupElementBuilder.create(it.value + "=") })
165165
}
166-
if (file is PsiFile) {
167-
func = EmberUtils.resolveHelper(file)
168-
}
169-
170-
if (func != null) {
171-
val hash = func.parameterList?.parameters?.last()
172-
resolveJsType(hash?.jsType ?: hash?.inferredType, result, "=")
173-
}
166+
val map = EmberUtils.getArgsAndPositionals(element)
167+
val named = map.getOrDefault("named", listOf())?.map { LookupElementBuilder.create(it + "=") }
168+
named?.let { result.addAllElements(it) }
174169
}
175170

176171
fun addImportPathCompletions(element: PsiElement, result: CompletionResultSet) {
@@ -229,6 +224,8 @@ class HbsLocalCompletion : CompletionProvider<CompletionParameters>() {
229224
val importNames = it.children[2].text
230225
.replace("\"", "")
231226
.replace("'", "")
227+
.replace("}", "")
228+
.replace("{", "")
232229
if (importNames.contains("*")) {
233230
val name = importNames.split(" as ").last()
234231
result.addElement(LookupElementBuilder.create(name))
@@ -285,8 +282,22 @@ class HbsLocalCompletion : CompletionProvider<CompletionParameters>() {
285282
element = element.parent
286283
}
287284
val languageService = GlintLanguageServiceProvider(element.project)
285+
val service = languageService.getService(element.originalVirtualFile!!)
288286
val txt = (element.parents.find { it is HbPathImpl || it is HbStringLiteral }?.text ?: element.text).replace("IntellijIdeaRulezzz", "")
289287

288+
if (element.containingFile.fileType is HtmlFileType) {
289+
val results = service?.updateAndGetCompletionItems(element.originalVirtualFile!!, parameters)?.get()?.map { it as GlintCompletionEntry }?.map {
290+
if (result.prefixMatcher.prefix == "@") {
291+
LookupElementBuilder.create("@" + it.name)
292+
} else {
293+
LookupElementBuilder.create(it.name)
294+
}
295+
296+
}
297+
results?.let { result.addAllElements(it) }
298+
return
299+
}
300+
290301
val helperElement = EmberUtils.findFirstHbsParamFromParam(element)
291302
if (helperElement != null) {
292303
addHelperCompletions(helperElement, result)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ class ImportNameReferences(element: PsiElement) : PsiPolyVariantReferenceBase<Ps
6464
if (fileRef == null) {
6565
return emptyArray()
6666
}
67-
val ref = EmberUtils.resolveToEmber(fileRef as PsiFile)
68-
return arrayOf(PsiElementResolveResult(ref))
67+
val ref = EmberUtils.resolveToEmber(fileRef)
68+
return ref?.let { arrayOf(PsiElementResolveResult(it)) } ?: arrayOf()
6969
}
7070
}
7171

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ open class HbsModuleReference(element: PsiElement, val moduleType: String) :
3535
private val internalModifiersFile = PsiFileFactory.getInstance(project).createFileFromText("intellij-emberjs/internal/modifiers-stub", Language.findLanguageByID("TypeScript")!!, this::class.java.getResource("/com/emberjs/external/ember-modifiers.ts").readText())
3636
private val internalComponentsFile = PsiFileFactory.getInstance(project).createFileFromText("intellij-emberjs/internal/components-stub", Language.findLanguageByID("TypeScript")!!, this::class.java.getResource("/com/emberjs/external/ember-components.ts").readText())
3737

38+
3839
private val internalHelpers = EmberUtils.resolveDefaultExport(internalHelpersFile) as JSObjectLiteralExpression
3940
private val internalModifiers = EmberUtils.resolveDefaultExport(internalModifiersFile) as JSObjectLiteralExpression
4041
protected val internalComponents = EmberUtils.resolveDefaultExport(internalComponentsFile) as JSObjectLiteralExpression

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ package com.emberjs.hbs
22

33
import com.dmarcotte.handlebars.psi.HbParam
44
import com.emberjs.utils.*
5+
import com.intellij.codeInsight.hints.InlayInfo
56
import com.intellij.codeInsight.lookup.LookupElement
67
import com.intellij.lang.javascript.psi.*
8+
import com.intellij.lang.javascript.psi.ecma6.TypeScriptCallSignature
9+
import com.intellij.lang.javascript.psi.ecma6.TypeScriptVariable
710
import com.intellij.lang.javascript.psi.types.JSArrayType
811
import com.intellij.lang.javascript.psi.types.JSTupleType
912
import com.intellij.lang.parameterInfo.*
1013
import com.intellij.psi.PsiElement
14+
import com.intellij.refactoring.suggested.startOffset
1115

1216

1317
class HbsParameterInfoHandler : ParameterInfoHandler<PsiElement, Any?> {
@@ -30,9 +34,23 @@ class HbsParameterInfoHandler : ParameterInfoHandler<PsiElement, Any?> {
3034
val psiElement = context.file.findElementAt(context.offset)
3135
val block = EmberUtils.findFirstHbsParamFromParam(psiElement)
3236
val ref = EmberUtils.followReferences(block)
33-
if (ref == null || ref !is JSFunction) {
37+
if (ref == null || ref !is JSFunction || ref !is TypeScriptCallSignature) {
3438
return null
3539
}
40+
41+
if (ref is TypeScriptVariable) {
42+
val signatures = ref.jsType?.asRecordType()?.properties?.firstOrNull()?.jsType?.asRecordType()?.typeMembers;
43+
signatures?.mapNotNull { it as? TypeScriptCallSignature }?.firstOrNull()?.let {
44+
val namedParams = it.parameters[0].jsType?.asRecordType()
45+
val positional = it.parameters.slice(IntRange(1, it.parameters.lastIndex))
46+
val args = emptyList<Any>().toMutableList()
47+
args.add(positional)
48+
namedParams?.let { args.add(it) }
49+
context.itemsToShow = args.toTypedArray()
50+
}
51+
return null
52+
}
53+
3654
val func: JSFunction = ref
3755
val args = emptyList<Any>().toMutableList()
3856
val argType = func.parameters.last().jsType

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

Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ import com.intellij.lang.javascript.psi.JSDestructuringArray
1111
import com.intellij.lang.javascript.psi.JSFunction
1212
import com.intellij.lang.javascript.psi.JSRecordType
1313
import com.intellij.lang.javascript.psi.JSType
14+
import com.intellij.lang.javascript.psi.ecma6.TypeScriptCallSignature
1415
import com.intellij.lang.javascript.psi.ecma6.TypeScriptTupleType
16+
import com.intellij.lang.javascript.psi.ecma6.TypeScriptVariable
1517
import com.intellij.lang.javascript.psi.ecma6.impl.TypeScriptTupleTypeImpl
1618
import com.intellij.lang.javascript.psi.ecmal4.JSClass
19+
import com.intellij.lang.javascript.psi.types.JSGenericTypeImpl
20+
import com.intellij.lang.javascript.psi.types.JSSimpleRecordTypeImpl
1721
import com.intellij.lang.javascript.psi.types.JSTupleType
1822
import com.intellij.lang.javascript.psi.types.JSTypeImpl
1923
import com.intellij.psi.PsiElement
@@ -33,6 +37,10 @@ class HbsParameterNameHints : InlayParameterHintsProvider {
3337
if (firstParam == null) {
3438
return emptyList<InlayInfo>().toMutableList()
3539
}
40+
val positonalLen = max(
41+
firstParam.parent.children.filter { it is HbParam }.size,
42+
firstParam.parent.parent.children.filter { it is HbParam }.size
43+
)
3644
var index = max(
3745
firstParam.parent.children.filter { it is HbParam }.indexOf(psiElement),
3846
firstParam.parent.parent.children.filter { it is HbParam }.indexOf(psiElement)
@@ -45,55 +53,11 @@ class HbsParameterNameHints : InlayParameterHintsProvider {
4553
return emptyList<InlayInfo>().toMutableList()
4654
}
4755

48-
var func = EmberUtils.followReferences(firstParam)
49-
if (func == firstParam && firstParam.children.isNotEmpty()) {
50-
func = EmberUtils.followReferences(firstParam.children[0])
51-
if (func == firstParam.children[0]) {
52-
val id = PsiTreeUtil.collectElements(firstParam) { it !is LeafPsiElement && it.elementType == HbTokenTypes.ID }.lastOrNull()
53-
func = EmberUtils.followReferences(id, psiElement.text)
54-
}
55-
}
56-
57-
if (func is JSFunction) {
58-
var arrayName: String? = null
59-
var array: JSType?
60-
61-
var args = func.parameters.lastOrNull()?.jsType
62-
array = null
63-
64-
if (args is JSTypeImpl) {
65-
args = args.asRecordType()
66-
}
56+
index -= 1
6757

68-
if (args is JSRecordType) {
69-
array = args.findPropertySignature("positional")?.jsType
70-
arrayName = "positional"
71-
}
72-
73-
if (array == null) {
74-
arrayName = func.parameters.first().name ?: arrayName
75-
array = func.parameters.first().jsType
76-
}
77-
78-
val type = array
79-
if (type is JSTupleType) {
80-
var name: String? = null
81-
if (type.sourceElement is TypeScriptTupleTypeImpl) {
82-
name = (type.sourceElement as TypeScriptTupleTypeImpl).members.getOrNull(index - 1)?.tupleMemberName
83-
}
84-
if (type.sourceElement is JSDestructuringArray) {
85-
name = (type.sourceElement as JSDestructuringArray).elementsWithRest.getOrNull(index - 1)?.text
86-
}
87-
if (name != null) {
88-
return mutableListOf(InlayInfo(name, psiElement.startOffset))
89-
} else {
90-
if (index == 1 && arrayName != null) {
91-
return mutableListOf(InlayInfo(arrayName, psiElement.startOffset))
92-
}
93-
}
94-
95-
}
96-
}
58+
val map = EmberUtils.getArgsAndPositionals(firstParam, positonalLen)
59+
val n = map.get("positional")?.getOrNull(index) ?: map.get("restparamnames")?.firstOrNull()
60+
return n?.let { mutableListOf(InlayInfo(it, psiElement.startOffset)) } ?: emptyList<InlayInfo>().toMutableList()
9761
}
9862
return emptyList<InlayInfo>().toMutableList()
9963
}

0 commit comments

Comments
 (0)