diff --git a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecAliasStatement.java b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecAliasStatement.java index 77297e3..f1fadbc 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecAliasStatement.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecAliasStatement.java @@ -4,6 +4,7 @@ import java.util.List; import org.jetbrains.annotations.*; import com.intellij.psi.PsiElement; +import com.intellij.navigation.ItemPresentation; public interface TypeSpecAliasStatement extends TypeSpecStatement { @@ -13,4 +14,7 @@ public interface TypeSpecAliasStatement extends TypeSpecStatement { @NotNull PsiElement getIdentifier(); + @Nullable + ItemPresentation getPresentation(); + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecEnumStatement.java b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecEnumStatement.java index 786d6f1..fde1211 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecEnumStatement.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecEnumStatement.java @@ -4,6 +4,7 @@ import java.util.List; import org.jetbrains.annotations.*; import com.intellij.psi.PsiElement; +import com.intellij.navigation.ItemPresentation; public interface TypeSpecEnumStatement extends TypeSpecStatement { @@ -16,4 +17,7 @@ public interface TypeSpecEnumStatement extends TypeSpecStatement { @NotNull PsiElement getIdentifier(); + @Nullable + ItemPresentation getPresentation(); + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecInterfaceStatement.java b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecInterfaceStatement.java index 74c5802..2acf364 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecInterfaceStatement.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecInterfaceStatement.java @@ -4,6 +4,7 @@ import java.util.List; import org.jetbrains.annotations.*; import com.intellij.psi.PsiElement; +import com.intellij.navigation.ItemPresentation; public interface TypeSpecInterfaceStatement extends TypeSpecStatement { @@ -16,4 +17,7 @@ public interface TypeSpecInterfaceStatement extends TypeSpecStatement { @NotNull PsiElement getIdentifier(); + @Nullable + ItemPresentation getPresentation(); + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecModelStatement.java b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecModelStatement.java index 96894d3..6ec5521 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecModelStatement.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecModelStatement.java @@ -4,6 +4,7 @@ import java.util.List; import org.jetbrains.annotations.*; import com.intellij.psi.PsiElement; +import com.intellij.navigation.ItemPresentation; public interface TypeSpecModelStatement extends TypeSpecStatement { @@ -22,4 +23,7 @@ public interface TypeSpecModelStatement extends TypeSpecStatement { @NotNull PsiElement getIdentifier(); + @Nullable + ItemPresentation getPresentation(); + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecOperationStatement.java b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecOperationStatement.java index d434d8e..eb3811a 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecOperationStatement.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecOperationStatement.java @@ -4,6 +4,7 @@ import java.util.List; import org.jetbrains.annotations.*; import com.intellij.psi.PsiElement; +import com.intellij.navigation.ItemPresentation; public interface TypeSpecOperationStatement extends TypeSpecStatement { @@ -13,4 +14,7 @@ public interface TypeSpecOperationStatement extends TypeSpecStatement { @NotNull TypeSpecOperation getOperation(); + @Nullable + ItemPresentation getPresentation(); + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecUnionStatement.java b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecUnionStatement.java index 4e6de88..63f93a9 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecUnionStatement.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/TypeSpecUnionStatement.java @@ -4,6 +4,7 @@ import java.util.List; import org.jetbrains.annotations.*; import com.intellij.psi.PsiElement; +import com.intellij.navigation.ItemPresentation; public interface TypeSpecUnionStatement extends TypeSpecStatement { @@ -16,4 +17,7 @@ public interface TypeSpecUnionStatement extends TypeSpecStatement { @NotNull PsiElement getIdentifier(); + @Nullable + ItemPresentation getPresentation(); + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecAliasStatementImpl.java b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecAliasStatementImpl.java index b9f8857..7bad042 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecAliasStatementImpl.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecAliasStatementImpl.java @@ -9,6 +9,7 @@ import com.intellij.psi.util.PsiTreeUtil; import static jp.s6n.idea.typespec.lang.psi.TypeSpecElementTypes.*; import jp.s6n.idea.typespec.lang.psi.*; +import com.intellij.navigation.ItemPresentation; public class TypeSpecAliasStatementImpl extends TypeSpecStatementImpl implements TypeSpecAliasStatement { @@ -39,4 +40,10 @@ public PsiElement getIdentifier() { return findNotNullChildByType(IDENTIFIER); } + @Override + @Nullable + public ItemPresentation getPresentation() { + return TypeSpecImplUtil.getPresentation(this); + } + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecEnumStatementImpl.java b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecEnumStatementImpl.java index 6767814..f31259d 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecEnumStatementImpl.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecEnumStatementImpl.java @@ -9,6 +9,7 @@ import com.intellij.psi.util.PsiTreeUtil; import static jp.s6n.idea.typespec.lang.psi.TypeSpecElementTypes.*; import jp.s6n.idea.typespec.lang.psi.*; +import com.intellij.navigation.ItemPresentation; public class TypeSpecEnumStatementImpl extends TypeSpecStatementImpl implements TypeSpecEnumStatement { @@ -45,4 +46,10 @@ public PsiElement getIdentifier() { return findNotNullChildByType(IDENTIFIER); } + @Override + @Nullable + public ItemPresentation getPresentation() { + return TypeSpecImplUtil.getPresentation(this); + } + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecInterfaceStatementImpl.java b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecInterfaceStatementImpl.java index c1f9c7b..eca17b4 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecInterfaceStatementImpl.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecInterfaceStatementImpl.java @@ -9,6 +9,7 @@ import com.intellij.psi.util.PsiTreeUtil; import static jp.s6n.idea.typespec.lang.psi.TypeSpecElementTypes.*; import jp.s6n.idea.typespec.lang.psi.*; +import com.intellij.navigation.ItemPresentation; public class TypeSpecInterfaceStatementImpl extends TypeSpecStatementImpl implements TypeSpecInterfaceStatement { @@ -45,4 +46,10 @@ public PsiElement getIdentifier() { return findNotNullChildByType(IDENTIFIER); } + @Override + @Nullable + public ItemPresentation getPresentation() { + return TypeSpecImplUtil.getPresentation(this); + } + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecModelStatementImpl.java b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecModelStatementImpl.java index 653550c..45da043 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecModelStatementImpl.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecModelStatementImpl.java @@ -9,6 +9,7 @@ import com.intellij.psi.util.PsiTreeUtil; import static jp.s6n.idea.typespec.lang.psi.TypeSpecElementTypes.*; import jp.s6n.idea.typespec.lang.psi.*; +import com.intellij.navigation.ItemPresentation; public class TypeSpecModelStatementImpl extends TypeSpecStatementImpl implements TypeSpecModelStatement { @@ -57,4 +58,10 @@ public PsiElement getIdentifier() { return findNotNullChildByType(IDENTIFIER); } + @Override + @Nullable + public ItemPresentation getPresentation() { + return TypeSpecImplUtil.getPresentation(this); + } + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecOperationStatementImpl.java b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecOperationStatementImpl.java index 1f7f3c4..d0d3707 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecOperationStatementImpl.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecOperationStatementImpl.java @@ -9,6 +9,7 @@ import com.intellij.psi.util.PsiTreeUtil; import static jp.s6n.idea.typespec.lang.psi.TypeSpecElementTypes.*; import jp.s6n.idea.typespec.lang.psi.*; +import com.intellij.navigation.ItemPresentation; public class TypeSpecOperationStatementImpl extends TypeSpecStatementImpl implements TypeSpecOperationStatement { @@ -39,4 +40,10 @@ public TypeSpecOperation getOperation() { return findNotNullChildByClass(TypeSpecOperation.class); } + @Override + @Nullable + public ItemPresentation getPresentation() { + return TypeSpecImplUtil.getPresentation(this); + } + } diff --git a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecUnionStatementImpl.java b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecUnionStatementImpl.java index 5fd0eed..8e53ba7 100644 --- a/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecUnionStatementImpl.java +++ b/gen/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecUnionStatementImpl.java @@ -9,6 +9,7 @@ import com.intellij.psi.util.PsiTreeUtil; import static jp.s6n.idea.typespec.lang.psi.TypeSpecElementTypes.*; import jp.s6n.idea.typespec.lang.psi.*; +import com.intellij.navigation.ItemPresentation; public class TypeSpecUnionStatementImpl extends TypeSpecStatementImpl implements TypeSpecUnionStatement { @@ -45,4 +46,10 @@ public PsiElement getIdentifier() { return findNotNullChildByType(IDENTIFIER); } + @Override + @Nullable + public ItemPresentation getPresentation() { + return TypeSpecImplUtil.getPresentation(this); + } + } diff --git a/grammars/TypeSpec.bnf b/grammars/TypeSpec.bnf index f6fd6c1..cd9842a 100644 --- a/grammars/TypeSpec.bnf +++ b/grammars/TypeSpec.bnf @@ -13,6 +13,7 @@ psiImplClassSuffix='Impl' psiPackage='jp.s6n.idea.typespec.lang.psi' psiImplPackage='jp.s6n.idea.typespec.lang.psi.impl' + psiImplUtilClass='jp.s6n.idea.typespec.lang.psi.impl.TypeSpecImplUtil' tokens=[ IMPORT = 'import' @@ -73,19 +74,28 @@ UsingStatement ::= USING Path SEMICOLON {extends=Statement} NamespaceStatement ::= Decorator* NAMESPACE Path (SEMICOLON | LBRACE Statement* RBRACE) {extends=Statement} -EnumStatement ::= Decorator* ENUM Identifier EnumVariantsBlock {extends=Statement} +EnumStatement ::= Decorator* ENUM Identifier EnumVariantsBlock { + extends=Statement + methods=[getPresentation] +} EnumVariantsBlock ::= LBRACE [EnumVariant (COMMA EnumVariant)* COMMA?] RBRACE EnumVariant ::= Decorator* Identifier -UnionStatement ::= Decorator* UNION Identifier UnionVariantsBlock {extends=Statement} +UnionStatement ::= Decorator* UNION Identifier UnionVariantsBlock { + extends=Statement + methods=[getPresentation] +} UnionVariantsBlock ::= LBRACE [UnionVariant (COMMA UnionVariant)* COMMA?] RBRACE UnionVariant ::= Decorator* Identifier COLON PathType -ModelStatement ::= Decorator* MODEL Identifier (ModelExtends | ModelIs)? ModelPropertiesBlock {extends=Statement} +ModelStatement ::= Decorator* MODEL Identifier (ModelExtends | ModelIs)? ModelPropertiesBlock { + extends=Statement + methods=[getPresentation] +} ModelExtends ::= EXTENDS PathType @@ -95,15 +105,24 @@ ModelPropertiesBlock ::= LBRACE ModelProperty* RBRACE ModelProperty ::= Decorator* Identifier QUEST? COLON Type SEMICOLON -InterfaceStatement ::= Decorator* INTERFACE Identifier InterfaceOperationsBlock {extends=Statement} +InterfaceStatement ::= Decorator* INTERFACE Identifier InterfaceOperationsBlock { + extends=Statement + methods=[getPresentation] +} InterfaceOperationsBlock ::= LBRACE InterfaceOperation* RBRACE InterfaceOperation ::= Decorator* Operation SEMICOLON -OperationStatement ::= Decorator* OP Operation SEMICOLON {extends=Statement} +OperationStatement ::= Decorator* OP Operation SEMICOLON { + extends=Statement + methods=[getPresentation] +} -AliasStatement ::= ALIAS Identifier EQ Type SEMICOLON {extends=Statement} +AliasStatement ::= ALIAS Identifier EQ Type SEMICOLON { + extends=Statement + methods=[getPresentation] +} Operation ::= Identifier OperationArgumentList COLON Type diff --git a/src/main/kotlin/jp/s6n/idea/typespec/lang/TypeSpecIconProvider.kt b/src/main/kotlin/jp/s6n/idea/typespec/lang/TypeSpecIconProvider.kt new file mode 100644 index 0000000..9c10f47 --- /dev/null +++ b/src/main/kotlin/jp/s6n/idea/typespec/lang/TypeSpecIconProvider.kt @@ -0,0 +1,21 @@ +package jp.s6n.idea.typespec.lang + +import com.intellij.icons.AllIcons +import com.intellij.ide.IconProvider +import com.intellij.psi.PsiElement +import jp.s6n.idea.typespec.lang.psi.* +import javax.swing.Icon + +class TypeSpecIconProvider : IconProvider() { + override fun getIcon(element: PsiElement, flags: Int): Icon? { + return when (element) { + is TypeSpecEnumStatement -> AllIcons.Nodes.Enum + is TypeSpecUnionStatement -> AllIcons.Nodes.Enum + is TypeSpecModelStatement -> AllIcons.Nodes.Class + is TypeSpecInterfaceStatement -> AllIcons.Nodes.Interface + is TypeSpecAliasStatement -> AllIcons.Nodes.Type + is TypeSpecOperationStatement -> AllIcons.Nodes.Function + else -> null + } + } +} diff --git a/src/main/kotlin/jp/s6n/idea/typespec/lang/TypeSpecStructureViewFactory.kt b/src/main/kotlin/jp/s6n/idea/typespec/lang/TypeSpecStructureViewFactory.kt new file mode 100644 index 0000000..a652329 --- /dev/null +++ b/src/main/kotlin/jp/s6n/idea/typespec/lang/TypeSpecStructureViewFactory.kt @@ -0,0 +1,41 @@ +package jp.s6n.idea.typespec.lang + +import com.intellij.ide.projectView.PresentationData +import com.intellij.ide.structureView.StructureViewBuilder +import com.intellij.ide.structureView.StructureViewModelBase +import com.intellij.ide.structureView.StructureViewTreeElement +import com.intellij.ide.structureView.TreeBasedStructureViewBuilder +import com.intellij.ide.util.treeView.smartTree.TreeElement +import com.intellij.lang.PsiStructureViewFactory +import com.intellij.navigation.ItemPresentation +import com.intellij.openapi.editor.Editor +import com.intellij.psi.NavigatablePsiElement +import com.intellij.psi.PsiFile +import jp.s6n.idea.typespec.lang.psi.TypeSpecFile + +class TypeSpecStructureViewFactory : PsiStructureViewFactory { + override fun getStructureViewBuilder(file: PsiFile) = object : TreeBasedStructureViewBuilder() { + override fun createStructureViewModel(editor: Editor?) = TypeSpecStructureViewModel(file, editor) + } +} + +class TypeSpecStructureViewModel(file: PsiFile, editor: Editor?) : StructureViewModelBase(file, editor, TypeSpecStructureViewElement(file)) + +class TypeSpecStructureViewElement(private val element: NavigatablePsiElement) : StructureViewTreeElement { + override fun getValue() = element + + override fun getPresentation(): ItemPresentation = element.presentation ?: PresentationData() + + override fun getChildren(): Array { + return when (element) { + is TypeSpecFile -> { + element.statements + .filterIsInstance() + .filter { it.presentation != null } + .map { TypeSpecStructureViewElement(it) } + .toTypedArray() + } + else -> TreeElement.EMPTY_ARRAY + } + } +} diff --git a/src/main/kotlin/jp/s6n/idea/typespec/lang/psi/TypeSpecFile.kt b/src/main/kotlin/jp/s6n/idea/typespec/lang/psi/TypeSpecFile.kt index 99210a4..e564e34 100644 --- a/src/main/kotlin/jp/s6n/idea/typespec/lang/psi/TypeSpecFile.kt +++ b/src/main/kotlin/jp/s6n/idea/typespec/lang/psi/TypeSpecFile.kt @@ -2,9 +2,12 @@ package jp.s6n.idea.typespec.lang.psi import com.intellij.extapi.psi.PsiFileBase import com.intellij.psi.FileViewProvider +import com.intellij.psi.util.childrenOfType import jp.s6n.idea.typespec.lang.TypeSpecFileType import jp.s6n.idea.typespec.lang.TypeSpecLanguage class TypeSpecFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, TypeSpecLanguage) { + val statements get() = childrenOfType() + override fun getFileType() = TypeSpecFileType } diff --git a/src/main/kotlin/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecImplUtil.kt b/src/main/kotlin/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecImplUtil.kt new file mode 100644 index 0000000..0b0c2de --- /dev/null +++ b/src/main/kotlin/jp/s6n/idea/typespec/lang/psi/impl/TypeSpecImplUtil.kt @@ -0,0 +1,43 @@ +package jp.s6n.idea.typespec.lang.psi.impl + +import com.intellij.navigation.ItemPresentation +import jp.s6n.idea.typespec.lang.psi.TypeSpecAliasStatement +import jp.s6n.idea.typespec.lang.psi.TypeSpecElement +import jp.s6n.idea.typespec.lang.psi.TypeSpecEnumStatement +import jp.s6n.idea.typespec.lang.psi.TypeSpecInterfaceStatement +import jp.s6n.idea.typespec.lang.psi.TypeSpecModelStatement +import jp.s6n.idea.typespec.lang.psi.TypeSpecOperationStatement +import jp.s6n.idea.typespec.lang.psi.TypeSpecUnionStatement + +object TypeSpecImplUtil { + @JvmStatic + fun getPresentation(element: TypeSpecElement): ItemPresentation? { + return when (element) { + is TypeSpecEnumStatement -> object : ItemPresentation { + override fun getPresentableText() = element.identifier.text + override fun getIcon(unused: Boolean) = element.getIcon(0) + } + is TypeSpecUnionStatement -> object : ItemPresentation { + override fun getPresentableText() = element.identifier.text + override fun getIcon(unused: Boolean) = element.getIcon(0) + } + is TypeSpecModelStatement -> object : ItemPresentation { + override fun getPresentableText() = element.identifier.text + override fun getIcon(unused: Boolean) = element.getIcon(0) + } + is TypeSpecInterfaceStatement -> object : ItemPresentation { + override fun getPresentableText() = element.identifier.text + override fun getIcon(unused: Boolean) = element.getIcon(0) + } + is TypeSpecOperationStatement -> object : ItemPresentation { + override fun getPresentableText() = element.operation.identifier.text + override fun getIcon(unused: Boolean) = element.getIcon(0) + } + is TypeSpecAliasStatement -> object : ItemPresentation { + override fun getPresentableText() = element.identifier.text + override fun getIcon(unused: Boolean) = element.getIcon(0) + } + else -> null + } + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index d9cfb87..95017dc 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -27,10 +27,14 @@ + + + +