Hmm I see, and let’s say I only want to support references and no syntax highlighting or full JInja support? Purely the ability to click on a reference in the SQL / YML file e.g. {{ ref('target') }}
and then jump to the definition?
I tried to implement this in a small PoC, and it works fine for Community Editions. However, I actually run into the problem where it doesn’t work for Ultimate Edition.
Community edition:
Ultimate edition:
… new members can only put in one media item per post, see next post …
Any idea what can be causing this problem, and if it is solvable? I tried quite some debugging already in Ultimate Edition.
The main problem seems to be around the JinjaReferenceContributor. In the Ultimate Edition (I think because of the built-in SQL support) there are no PsiElements being pushed to the registrar.registerReferenceProvider. For example when I remove the regex pattern and purely use **PlatformPatterns.psiElement()**
as filter (most broad filter I can think of), I only get the PsiElements for the comment blocks in the SQL, but no PsiElement that actually contains the SQL itself so that it can be pushed down to the JinjaReferenceProvider.
My implementation:
Or via Github: Comparing 47be2da215f3260ea1b0c85bef8d68c304210f48...4bbcf781c3b4f5db5017051badecf29d5e452a6b · ramonvermeulen/dbt-toolkit · GitHub
Entry in plugin.xml
<psi.referenceContributor implementation="com.github.ramonvermeulen.dbtToolkit.jinja.JinjaReferenceContributor" order="last"/>
JinjaPatterns.kt
package com.github.ramonvermeulen.dbtToolkit.jinja
object JinjaPatterns {
val REF_PATTERN = Regex("""\{\{.*?ref\s*\(\s*['"](.*?)['"]\s*\).*?\}\}""")
}
JinjaReferenceContributor.kt
package com.github.ramonvermeulen.dbtToolkit.jinja
import com.intellij.patterns.PatternCondition
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReferenceContributor
import com.intellij.psi.PsiReferenceRegistrar
import com.intellij.util.ProcessingContext
class JinjaReferenceContributor : PsiReferenceContributor() {
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
registrar.registerReferenceProvider(
PlatformPatterns.psiElement().with(object : PatternCondition<PsiElement>("jinjaRefPattern") {
override fun accepts(element: PsiElement, context: ProcessingContext?): Boolean {
return JinjaPatterns.REF_PATTERN.containsMatchIn(element.text)
}
}),
JinjaReferenceProvider(),
)
}
}
JinjaReferenceProvider.kt
package com.github.ramonvermeulen.dbtToolkit.jinja
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiReferenceProvider
import com.intellij.util.ProcessingContext
class JinjaReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
val fileContent = element.containingFile.text
val matches = JinjaPatterns.REF_PATTERN.findAll(fileContent)
return matches.map { match ->
val refValue = match.groupValues[1]
JinjaReference(element, TextRange(match.range.first, match.range.last + 1), refValue)
}.toList().toTypedArray()
}
}
JinjaReference.kt
package com.github.ramonvermeulen.dbtToolkit.jinja
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiReferenceBase
import com.intellij.psi.search.FilenameIndex
import com.intellij.psi.search.GlobalSearchScope
class JinjaReference(
element: PsiElement,
range: TextRange,
private val refValue: String,
) : PsiReferenceBase<PsiElement>(element, range) {
override fun resolve(): PsiElement? {
return findSqlFile(refValue)
}
private fun findSqlFile(refValue: String): PsiElement? {
val project = element.project
val sqlFileName = "$refValue.sql"
val files = FilenameIndex.getVirtualFilesByName(sqlFileName, GlobalSearchScope.allScope(project))
val psiFile = PsiManager.getInstance(project).findFile(files.first())
return psiFile
}
}