Skip to content

Commit 2d69ab4

Browse files
committed
Introduce line marker for wasm_bindgen attributes
1 parent e9c32ee commit 2d69ab4

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Use of this source code is governed by the MIT license that can be
3+
* found in the LICENSE file.
4+
*/
5+
6+
package org.rust.js
7+
8+
import com.intellij.codeInsight.daemon.DefaultGutterIconNavigationHandler
9+
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
10+
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider
11+
import com.intellij.lang.javascript.psi.JSElement
12+
import com.intellij.lang.javascript.psi.ecma6.TypeScriptClass
13+
import com.intellij.lang.javascript.psi.ecma6.TypeScriptEnum
14+
import com.intellij.lang.javascript.psi.ecma6.TypeScriptFunction
15+
import com.intellij.navigation.GotoRelatedItem
16+
import com.intellij.openapi.diagnostic.Logger
17+
import com.intellij.openapi.editor.markup.GutterIconRenderer
18+
import com.intellij.openapi.vfs.LocalFileSystem
19+
import com.intellij.psi.PsiElement
20+
import com.intellij.psi.PsiFile
21+
import com.intellij.psi.PsiManager
22+
import com.intellij.psi.util.findDescendantOfType
23+
import icons.JavaScriptPsiIcons
24+
import org.rust.lang.core.psi.RsEnumItem
25+
import org.rust.lang.core.psi.RsFunction
26+
import org.rust.lang.core.psi.RsImplItem
27+
import org.rust.lang.core.psi.RsStructItem
28+
import org.rust.lang.core.psi.ext.RsOuterAttributeOwner
29+
import org.rust.lang.core.psi.ext.RsVisibilityOwner
30+
import org.rust.lang.core.psi.ext.containingCargoPackage
31+
import org.rust.lang.core.psi.ext.findOuterAttr
32+
import org.rust.lang.core.psi.impl.RsBaseTypeImpl
33+
import java.nio.file.InvalidPathException
34+
import java.nio.file.Paths
35+
36+
class RsWasmBindgenLineMarkerProvider : RelatedItemLineMarkerProvider() {
37+
override fun getLineMarkerInfo(element: PsiElement): RelatedItemLineMarkerInfo<*>? {
38+
val element = element as? RsOuterAttributeOwner ?: return null
39+
if (element !is RsFunction && element !is RsEnumItem && element !is RsStructItem && element !is RsImplItem) {
40+
return null
41+
}
42+
43+
// Check the package has wasm-bindgen as dependency
44+
val cargoPackage = element.containingCargoPackage ?: return null
45+
if (cargoPackage.dependencies.none { it.pkg.name == "wasm-bindgen" }) {
46+
return null
47+
}
48+
49+
// Only public elements are exposed in bindings
50+
if (element is RsVisibilityOwner && element !is RsImplItem && !element.isPublic) {
51+
return null
52+
}
53+
54+
val attr = element.findOuterAttr("wasm_bindgen") ?: return null
55+
56+
val basePath = cargoPackage.contentRoot?.path ?: return null
57+
val expectedName = cargoPackage.normName
58+
59+
// Expecting to find related generated typescript declarations in pkg/ folder of current package
60+
val expectedPath = try {
61+
Paths.get(basePath, "pkg/$expectedName.d.ts").toString()
62+
} catch (e: InvalidPathException) {
63+
LOG.error(e)
64+
return null
65+
}
66+
val tsFile = LocalFileSystem.getInstance().findFileByPath(expectedPath) ?: return null
67+
val tsPsiFile = PsiManager.getInstance(element.project).findFile(tsFile) ?: return null
68+
69+
// Trying to find the correlating element with the same name
70+
val destination = when (element) {
71+
// If it is impl, then resolving to the related struct and using its name
72+
is RsImplItem -> {
73+
val reference = (element.typeReference as? RsBaseTypeImpl) ?: return null
74+
val struct = (reference.path?.reference?.resolve() as? RsStructItem) ?: return null
75+
findRelatedTsElement(struct, tsPsiFile)
76+
}
77+
else -> findRelatedTsElement(element, tsPsiFile)
78+
} ?: return null
79+
80+
return RelatedItemLineMarkerInfo(
81+
attr,
82+
attr.textRange,
83+
JavaScriptPsiIcons.FileTypes.TypeScriptFile,
84+
{ "Related generated declaration" },
85+
DefaultGutterIconNavigationHandler(listOf(destination), "Generated declarations"),
86+
GutterIconRenderer.Alignment.RIGHT,
87+
{ listOf(GotoRelatedItem(destination)) }
88+
)
89+
}
90+
91+
private fun findRelatedTsElement(element: RsOuterAttributeOwner, tsPsiFile: PsiFile): JSElement? =
92+
when (element) {
93+
is RsFunction -> tsPsiFile.findDescendantOfType<TypeScriptFunction> { it.name == element.name }
94+
is RsEnumItem -> tsPsiFile.findDescendantOfType<TypeScriptEnum> { it.name == element.name }
95+
is RsStructItem -> tsPsiFile.findDescendantOfType<TypeScriptClass> { it.name == element.name }
96+
else -> null
97+
}
98+
99+
companion object {
100+
private val LOG: Logger = Logger.getInstance(RsWasmBindgenLineMarkerProvider::class.java)
101+
}
102+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<idea-plugin>
22
<extensions defaultExtensionNs="com.intellij">
3+
<codeInsight.lineMarkerProvider language="Rust" implementationClass="org.rust.js.RsWasmBindgenLineMarkerProvider"/>
34
</extensions>
45
</idea-plugin>

0 commit comments

Comments
 (0)