Skip to content

Commit 3830ab1

Browse files
committed
Added structure view and element icons provider (#164)
1 parent e61732b commit 3830ab1

File tree

5 files changed

+527
-1
lines changed

5 files changed

+527
-1
lines changed

resources/META-INF/plugin.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
<fileTypeFactory implementation="com.intellij.lang.jsgraphql.GraphQLFileTypeFactory"/>
4949
<lang.parserDefinition language="GraphQL" implementationClass="com.intellij.lang.jsgraphql.GraphQLParserDefinition"/>
5050

51+
<!-- Icons -->
52+
<iconProvider implementation="com.intellij.lang.jsgraphql.GraphQLIconProvider" />
53+
5154
<!-- Project services -->
5255
<projectService serviceInterface="com.intellij.lang.jsgraphql.schema.GraphQLTypeDefinitionRegistryServiceImpl" serviceImplementation="com.intellij.lang.jsgraphql.schema.GraphQLTypeDefinitionRegistryServiceImpl" />
5356
<projectService serviceInterface="com.intellij.lang.jsgraphql.schema.SchemaIDLTypeDefinitionRegistry" serviceImplementation="com.intellij.lang.jsgraphql.schema.SchemaIDLTypeDefinitionRegistry" />
@@ -165,9 +168,9 @@
165168
<lang.braceMatcher language="GraphQL Schema" implementationClass="JSGraphQLBraceMatcher" />
166169
-->
167170
<lang.braceMatcher language="GraphQL Endpoint" implementationClass="com.intellij.lang.jsgraphql.endpoint.ide.editor.JSGraphQLEndpointBraceMatcher" />
171+
<lang.psiStructureViewFactory language="GraphQL" implementationClass="com.intellij.lang.jsgraphql.ide.structureView.GraphQLPsiStructureViewFactory"/>
168172
<!--
169173
<lang.fileViewProviderFactory language="GraphQL Schema" implementationClass="JSGraphQLSchemaFileViewProviderFactory" />
170-
<lang.psiStructureViewFactory language="GraphQL" implementationClass="JSGraphQLPsiStructureViewFactory"/>
171174
<lang.psiStructureViewFactory language="GraphQL Schema" implementationClass="JSGraphQLPsiStructureViewFactory"/>
172175
-->
173176
<lang.psiStructureViewFactory language="GraphQL Endpoint" implementationClass="com.intellij.lang.jsgraphql.endpoint.ide.structureView.JSGraphQLEndpointPsiStructureViewFactory"/>
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright (c) 2018-present, Jim Kynde Meyer
3+
* All rights reserved.
4+
* <p>
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
package com.intellij.lang.jsgraphql;
9+
10+
import com.intellij.ide.IconProvider;
11+
import com.intellij.lang.jsgraphql.icons.JSGraphQLIcons;
12+
import com.intellij.lang.jsgraphql.psi.GraphQLArgument;
13+
import com.intellij.lang.jsgraphql.psi.GraphQLElement;
14+
import com.intellij.lang.jsgraphql.psi.GraphQLEnumTypeDefinition;
15+
import com.intellij.lang.jsgraphql.psi.GraphQLEnumTypeExtensionDefinition;
16+
import com.intellij.lang.jsgraphql.psi.GraphQLEnumValue;
17+
import com.intellij.lang.jsgraphql.psi.GraphQLEnumValueDefinition;
18+
import com.intellij.lang.jsgraphql.psi.GraphQLField;
19+
import com.intellij.lang.jsgraphql.psi.GraphQLFieldDefinition;
20+
import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition;
21+
import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSpread;
22+
import com.intellij.lang.jsgraphql.psi.GraphQLInlineFragment;
23+
import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeDefinition;
24+
import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeExtensionDefinition;
25+
import com.intellij.lang.jsgraphql.psi.GraphQLInputValueDefinition;
26+
import com.intellij.lang.jsgraphql.psi.GraphQLInterfaceTypeDefinition;
27+
import com.intellij.lang.jsgraphql.psi.GraphQLInterfaceTypeExtensionDefinition;
28+
import com.intellij.lang.jsgraphql.psi.GraphQLObjectField;
29+
import com.intellij.lang.jsgraphql.psi.GraphQLObjectTypeDefinition;
30+
import com.intellij.lang.jsgraphql.psi.GraphQLObjectTypeExtensionDefinition;
31+
import com.intellij.lang.jsgraphql.psi.GraphQLOperationType;
32+
import com.intellij.lang.jsgraphql.psi.GraphQLScalarTypeDefinition;
33+
import com.intellij.lang.jsgraphql.psi.GraphQLScalarTypeExtensionDefinition;
34+
import com.intellij.lang.jsgraphql.psi.GraphQLSelectionSetOperationDefinition;
35+
import com.intellij.lang.jsgraphql.psi.GraphQLTypeDefinition;
36+
import com.intellij.lang.jsgraphql.psi.GraphQLTypeExtension;
37+
import com.intellij.lang.jsgraphql.psi.GraphQLTypeName;
38+
import com.intellij.lang.jsgraphql.psi.GraphQLTypeNameDefinition;
39+
import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition;
40+
import com.intellij.lang.jsgraphql.psi.GraphQLUnionMembers;
41+
import com.intellij.lang.jsgraphql.psi.GraphQLUnionTypeDefinition;
42+
import com.intellij.lang.jsgraphql.psi.GraphQLUnionTypeExtensionDefinition;
43+
import com.intellij.psi.PsiElement;
44+
import com.intellij.psi.util.PsiTreeUtil;
45+
import org.jetbrains.annotations.NotNull;
46+
import org.jetbrains.annotations.Nullable;
47+
48+
import javax.swing.*;
49+
50+
public class GraphQLIconProvider extends IconProvider {
51+
@Nullable
52+
@Override
53+
public Icon getIcon(@NotNull PsiElement element, int flags) {
54+
55+
if (element instanceof GraphQLElement) {
56+
57+
if (element instanceof GraphQLSelectionSetOperationDefinition) {
58+
return JSGraphQLIcons.Schema.Query;
59+
}
60+
61+
if (element instanceof GraphQLInlineFragment) {
62+
return JSGraphQLIcons.Schema.Fragment;
63+
}
64+
65+
if (element instanceof GraphQLTypedOperationDefinition) {
66+
return getOperationIcon((GraphQLTypedOperationDefinition) element);
67+
}
68+
69+
final PsiElement parent = element.getParent();
70+
71+
if (parent instanceof GraphQLTypedOperationDefinition) {
72+
return getOperationIcon((GraphQLTypedOperationDefinition) parent);
73+
}
74+
75+
if (parent instanceof GraphQLEnumValue) {
76+
return JSGraphQLIcons.Schema.Enum;
77+
}
78+
79+
if (parent instanceof GraphQLTypeNameDefinition) {
80+
final GraphQLTypeDefinition typeDefinition = PsiTreeUtil.getParentOfType(element, GraphQLTypeDefinition.class);
81+
if (typeDefinition instanceof GraphQLObjectTypeDefinition || typeDefinition instanceof GraphQLUnionTypeDefinition) {
82+
return JSGraphQLIcons.Schema.Type;
83+
}
84+
if (typeDefinition instanceof GraphQLInterfaceTypeDefinition || typeDefinition instanceof GraphQLInputObjectTypeDefinition) {
85+
return JSGraphQLIcons.Schema.Interface;
86+
}
87+
if (typeDefinition instanceof GraphQLScalarTypeDefinition) {
88+
return JSGraphQLIcons.Schema.Scalar;
89+
}
90+
if (typeDefinition instanceof GraphQLEnumTypeDefinition) {
91+
return JSGraphQLIcons.Schema.Enum;
92+
}
93+
}
94+
95+
if (parent instanceof GraphQLTypeName) {
96+
97+
final GraphQLTypeExtension typeDefinition = PsiTreeUtil.getParentOfType(element, GraphQLTypeExtension.class);
98+
if (typeDefinition instanceof GraphQLObjectTypeExtensionDefinition || typeDefinition instanceof GraphQLUnionTypeExtensionDefinition) {
99+
return JSGraphQLIcons.Schema.Type;
100+
}
101+
if (typeDefinition instanceof GraphQLInterfaceTypeExtensionDefinition || typeDefinition instanceof GraphQLInputObjectTypeExtensionDefinition) {
102+
return JSGraphQLIcons.Schema.Interface;
103+
}
104+
if (typeDefinition instanceof GraphQLScalarTypeExtensionDefinition) {
105+
return JSGraphQLIcons.Schema.Scalar;
106+
}
107+
if (typeDefinition instanceof GraphQLEnumTypeExtensionDefinition) {
108+
return JSGraphQLIcons.Schema.Enum;
109+
}
110+
111+
if (PsiTreeUtil.getParentOfType(element, GraphQLUnionMembers.class) != null) {
112+
return JSGraphQLIcons.Schema.Type;
113+
}
114+
115+
if (PsiTreeUtil.getParentOfType(element, GraphQLEnumValueDefinition.class) != null) {
116+
return JSGraphQLIcons.Schema.Enum;
117+
}
118+
119+
}
120+
121+
if (parent instanceof GraphQLFragmentDefinition || parent instanceof GraphQLInlineFragment || parent instanceof GraphQLFragmentSpread) {
122+
return JSGraphQLIcons.Schema.Fragment;
123+
}
124+
125+
if (PsiTreeUtil.findFirstParent(element, false, p -> p instanceof GraphQLArgument || p instanceof GraphQLInputValueDefinition) != null) {
126+
return JSGraphQLIcons.Schema.Attribute;
127+
}
128+
if (PsiTreeUtil.findFirstParent(element, false, p -> p instanceof GraphQLField || p instanceof GraphQLFieldDefinition || p instanceof GraphQLObjectField) != null) {
129+
return JSGraphQLIcons.Schema.Field;
130+
}
131+
132+
// fallback to just showing the GraphQL logo
133+
return JSGraphQLIcons.Logos.GraphQL;
134+
135+
}
136+
137+
return null;
138+
}
139+
140+
private Icon getOperationIcon(GraphQLTypedOperationDefinition typedOperationDefinition) {
141+
final GraphQLOperationType operationType = typedOperationDefinition.getOperationType();
142+
switch (operationType.getText()) {
143+
case "query":
144+
return JSGraphQLIcons.Schema.Query;
145+
case "mutation":
146+
return JSGraphQLIcons.Schema.Mutation;
147+
case "subscription":
148+
return JSGraphQLIcons.Schema.Subscription;
149+
default:
150+
return JSGraphQLIcons.Logos.GraphQL;
151+
}
152+
}
153+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright (c) 2018-present, Jim Kynde Meyer
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
package com.intellij.lang.jsgraphql.ide.structureView;
9+
10+
import com.intellij.ide.structureView.StructureViewBuilder;
11+
import com.intellij.ide.structureView.StructureViewModel;
12+
import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
13+
import com.intellij.lang.PsiStructureViewFactory;
14+
import com.intellij.openapi.editor.Editor;
15+
import com.intellij.psi.PsiFile;
16+
import org.jetbrains.annotations.NotNull;
17+
import org.jetbrains.annotations.Nullable;
18+
19+
public class GraphQLPsiStructureViewFactory implements PsiStructureViewFactory {
20+
21+
@Nullable
22+
@Override
23+
public StructureViewBuilder getStructureViewBuilder(@NotNull PsiFile psiFile) {
24+
return new TreeBasedStructureViewBuilder() {
25+
@NotNull
26+
public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
27+
return new GraphQLStructureViewModel(psiFile, editor);
28+
}
29+
30+
public boolean isRootNodeShown() {
31+
return false;
32+
}
33+
};
34+
}
35+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* Copyright (c) 2018-present, Jim Kynde Meyer
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
package com.intellij.lang.jsgraphql.ide.structureView;
9+
10+
import com.intellij.ide.structureView.StructureViewModel;
11+
import com.intellij.ide.structureView.StructureViewTreeElement;
12+
import com.intellij.ide.structureView.TextEditorBasedStructureViewModel;
13+
import com.intellij.lang.jsgraphql.psi.GraphQLElement;
14+
import com.intellij.lang.jsgraphql.psi.GraphQLElementTypes;
15+
import com.intellij.lang.jsgraphql.psi.GraphQLField;
16+
import com.intellij.openapi.editor.Editor;
17+
import com.intellij.psi.PsiElement;
18+
import com.intellij.psi.impl.source.tree.LeafPsiElement;
19+
import com.intellij.psi.util.PsiTreeUtil;
20+
import org.jetbrains.annotations.NotNull;
21+
22+
public class GraphQLStructureViewModel extends TextEditorBasedStructureViewModel implements StructureViewModel.ElementInfoProvider {
23+
24+
private final GraphQLStructureViewTreeElement root;
25+
26+
public GraphQLStructureViewModel(PsiElement root, Editor editor) {
27+
super(editor, root.getContainingFile());
28+
this.root = new GraphQLStructureViewTreeElement(root, root);
29+
}
30+
31+
@Override
32+
public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
33+
return false;
34+
}
35+
36+
@Override
37+
public boolean isAlwaysLeaf(StructureViewTreeElement element) {
38+
if (element instanceof GraphQLStructureViewTreeElement) {
39+
GraphQLStructureViewTreeElement treeElement = (GraphQLStructureViewTreeElement) element;
40+
if (treeElement.childrenBase instanceof LeafPsiElement) {
41+
return true;
42+
}
43+
if (treeElement.childrenBase instanceof GraphQLField) {
44+
final PsiElement[] children = treeElement.childrenBase.getChildren();
45+
if (children.length == 0) {
46+
// field with no sub selections, but we have to check if there's attributes
47+
final PsiElement nextVisible = PsiTreeUtil.nextVisibleLeaf(treeElement.childrenBase);
48+
if (nextVisible != null && nextVisible.getNode().getElementType() == GraphQLElementTypes.PAREN_L) {
49+
return false;
50+
}
51+
return true;
52+
}
53+
if (children.length == 1 && children[0] instanceof LeafPsiElement) {
54+
return true;
55+
}
56+
}
57+
}
58+
return false;
59+
}
60+
61+
@Override
62+
protected boolean isSuitable(PsiElement element) {
63+
return element instanceof GraphQLElement;
64+
}
65+
66+
@NotNull
67+
@Override
68+
public StructureViewTreeElement getRoot() {
69+
return root;
70+
}
71+
}

0 commit comments

Comments
 (0)