Skip to content

Commit d5ef60a

Browse files
Navigating to message, enum or service by name (Ctrl+N)
1 parent 343d50a commit d5ef60a

38 files changed

+709
-89
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
[Protobuf Support Plugin](https://plugins.jetbrains.com/plugin/8277) for IntelliJ IDEA & other JetBrains products.
77

8-
Based on [antlr4-jetbrains-adapter](https://github.com/antlr/jetbrains/) and ANTLR 4 grammar from [protostuff-compiler](https://github.com/protostuff/protostuff-compiler/tree/master/protostuff-parser/src/main/antlr4/io/protostuff/compiler/parser).
9-
108
Plugin is compatible with IntelliJ IDEA 2016.1. Other JetBrains IDEs of the same or higher version should be supported as well.
119

1210
### Roadmap
@@ -36,3 +34,4 @@ Requirements:
3634
### Links
3735

3836
https://github.com/protostuff/protobuf-jetbrains-plugin/wiki/Links
37+

build.gradle

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,7 @@ apply plugin: 'org.jetbrains.intellij'
4141
intellij {
4242
version = ideaVersion
4343
updateSinceUntilBuild = false
44-
// TODO: we do not need dependency on this plugin in runtime
45-
// TODO: should be removed, but then tests are failing with
46-
// TODO: ERROR: java.lang.ClassNotFoundException: com.intellij.lang.properties.PropertiesFileTypeFactory
47-
// plugins 'properties'
48-
downloadSources = false
44+
downloadSources = true
4945
publish {
5046
username = project.hasProperty('jetbrainsUser') \
5147
? project.property('jetbrainsUser') \

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Available idea versions:
22
# https://www.jetbrains.com/intellij-repository/releases
33
# https://www.jetbrains.com/intellij-repository/snapshots
4-
version=0.5.0
4+
version=0.7.0
55
ideaVersion=145.258.11
66
# https://intellij-support.jetbrains.com/hc/en-us/articles/206544879-Selecting-the-JDK-version-the-IDE-will-run-under
77
# Java 8 is required to run IntelliJ IDEA starting from version 16
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package io.protostuff.jetbrains.plugin;
2+
3+
import com.intellij.navigation.GotoClassContributor;
4+
import com.intellij.navigation.NavigationItem;
5+
import com.intellij.openapi.project.Project;
6+
import com.intellij.openapi.vfs.VirtualFile;
7+
import com.intellij.psi.PsiManager;
8+
import com.intellij.psi.search.FileTypeIndex;
9+
import com.intellij.psi.search.GlobalSearchScope;
10+
import com.intellij.util.indexing.FileBasedIndex;
11+
import io.protostuff.jetbrains.plugin.psi.ProtoPsiFileRoot;
12+
import io.protostuff.jetbrains.plugin.psi.ProtoType;
13+
import io.protostuff.jetbrains.plugin.settings.ProtobufSettings;
14+
import org.jetbrains.annotations.NotNull;
15+
import org.jetbrains.annotations.Nullable;
16+
17+
import java.util.ArrayList;
18+
import java.util.Collection;
19+
import java.util.List;
20+
import java.util.function.Predicate;
21+
22+
/**
23+
* @author Kostiantyn Shchepanovskyi
24+
*/
25+
public class GoToClassContributor implements GotoClassContributor {
26+
27+
public static String getQualifiedNameUserType(ProtoType protoType) {
28+
return protoType.getFullName();
29+
}
30+
31+
@Nullable
32+
@Override
33+
public String getQualifiedName(final NavigationItem item) {
34+
if (item instanceof ProtoType) {
35+
return getQualifiedNameUserType((ProtoType) item);
36+
}
37+
return null;
38+
}
39+
40+
@Nullable
41+
@Override
42+
public String getQualifiedNameSeparator() {
43+
return ".";
44+
}
45+
46+
@NotNull
47+
@Override
48+
public String[] getNames(Project project, boolean includeNonProjectItems) {
49+
List<ProtoType> types = findUserTypes(project, includeNonProjectItems);
50+
List<String> names = new ArrayList<>(types.size());
51+
for (ProtoType type : types) {
52+
if (type.getName().length() > 0) {
53+
names.add(type.getName());
54+
}
55+
}
56+
return names.toArray(new String[names.size()]);
57+
}
58+
59+
@NotNull
60+
@Override
61+
public NavigationItem[] getItemsByName(String name, String pattern, Project project, boolean includeNonProjectItems) {
62+
List<ProtoType> types = findUserTypes(project, includeNonProjectItems, name);
63+
return types.toArray(new NavigationItem[types.size()]);
64+
}
65+
66+
private List<ProtoType> findUserTypes(Project project, boolean includeNonProjectItems) {
67+
return getProtoTypes(project, includeNonProjectItems,
68+
protoType -> true);
69+
}
70+
71+
private List<ProtoType> findUserTypes(Project project, boolean includeNonProjectItems, String key) {
72+
return getProtoTypes(project, includeNonProjectItems,
73+
protoType -> key.equals(protoType.getName()));
74+
}
75+
76+
@NotNull
77+
private List<ProtoType> getProtoTypes(Project project, boolean includeNonProjectItems, Predicate<ProtoType> filter) {
78+
List<ProtoType> result = new ArrayList<>();
79+
List<VirtualFile> files = new ArrayList<>();
80+
addProjectAndLibraryFiles(project, includeNonProjectItems, files);
81+
if (includeNonProjectItems) {
82+
addFilesFromCustomIncludePath(project, files);
83+
}
84+
for (VirtualFile virtualFile : files) {
85+
ProtoPsiFileRoot file = (ProtoPsiFileRoot) PsiManager.getInstance(project).findFile(virtualFile);
86+
if (file != null) {
87+
Collection<ProtoType> types = file.getAllTypes();
88+
for (ProtoType type : types) {
89+
if (filter.test(type)) {
90+
result.add(type);
91+
}
92+
}
93+
}
94+
}
95+
return result;
96+
}
97+
98+
private void addProjectAndLibraryFiles(Project project, boolean includeNonProjectItems, List<VirtualFile> files) {
99+
FileBasedIndex index = FileBasedIndex.getInstance();
100+
GlobalSearchScope scope = getSearchScope(project, includeNonProjectItems);
101+
files.addAll(index.getContainingFiles(FileTypeIndex.NAME, ProtoFileType.INSTANCE, scope));
102+
}
103+
104+
private void addFilesFromCustomIncludePath(Project project, List<VirtualFile> files) {
105+
ProtobufSettings settings = project.getComponent(ProtobufSettings.class);
106+
List<VirtualFile> includePaths = settings.getIncludePathsVf();
107+
for (VirtualFile includePath : includePaths) {
108+
FileBasedIndex.iterateRecursively(includePath, file -> {
109+
if (!file.isDirectory() && isProtoFile(file)) {
110+
files.add(file);
111+
}
112+
return true;
113+
}, null, null, null);
114+
}
115+
}
116+
117+
private boolean isProtoFile(VirtualFile file) {
118+
return file.getName().toLowerCase().endsWith(ProtoFileType.FILE_EXTENSION);
119+
}
120+
121+
@NotNull
122+
private GlobalSearchScope getSearchScope(Project project, boolean includeNonProjectItems) {
123+
if (includeNonProjectItems) {
124+
return GlobalSearchScope.allScope(project);
125+
} else {
126+
return GlobalSearchScope.projectScope(project);
127+
}
128+
}
129+
130+
}

src/main/java/io/protostuff/jetbrains/plugin/ProtoFindUsagesProvider.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@
44
import com.intellij.lang.cacheBuilder.WordsScanner;
55
import com.intellij.lang.findUsages.FindUsagesProvider;
66
import com.intellij.psi.PsiElement;
7-
import com.intellij.psi.PsiNamedElement;
8-
import com.intellij.psi.tree.TokenSet;
9-
import io.protostuff.compiler.parser.ProtoLexer;
107
import io.protostuff.jetbrains.plugin.psi.EnumNode;
118
import io.protostuff.jetbrains.plugin.psi.MessageNode;
12-
import io.protostuff.jetbrains.plugin.psi.UserType;
13-
import org.antlr.jetbrains.adapter.lexer.PSIElementTypeFactory;
9+
import io.protostuff.jetbrains.plugin.psi.DataType;
1410
import org.jetbrains.annotations.NotNull;
1511
import org.jetbrains.annotations.Nullable;
1612

@@ -31,7 +27,7 @@ public WordsScanner getWordsScanner() {
3127

3228
@Override
3329
public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
34-
return psiElement instanceof UserType;
30+
return psiElement instanceof DataType;
3531
}
3632

3733
@Nullable
@@ -55,8 +51,8 @@ public String getType(@NotNull PsiElement element) {
5551
@NotNull
5652
@Override
5753
public String getDescriptiveName(@NotNull PsiElement element) {
58-
if (element instanceof UserType) {
59-
UserType type = (UserType) element;
54+
if (element instanceof DataType) {
55+
DataType type = (DataType) element;
6056
return type.getFullName();
6157
}
6258
return "";
@@ -65,8 +61,8 @@ public String getDescriptiveName(@NotNull PsiElement element) {
6561
@NotNull
6662
@Override
6763
public String getNodeText(@NotNull PsiElement element, boolean useFullName) {
68-
if (element instanceof UserType) {
69-
UserType type = (UserType) element;
64+
if (element instanceof DataType) {
65+
DataType type = (DataType) element;
7066
if (useFullName) {
7167
return type.getFullName();
7268
}

src/main/java/io/protostuff/jetbrains/plugin/psi/UserType.java renamed to src/main/java/io/protostuff/jetbrains/plugin/psi/DataType.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,22 @@
1111
import org.jetbrains.annotations.Nullable;
1212

1313
/**
14+
* User-defined proto type that can be used as a field - message or enum.
15+
*
1416
* @author Kostiantyn Shchepanovskyi
1517
*/
16-
public class UserType
18+
public class DataType
1719
extends IdentifierDefSubtree
18-
implements ScopeNode, KeywordsContainer {
20+
implements ScopeNode, KeywordsContainer, ProtoType {
1921

20-
public UserType(@NotNull ASTNode node, IElementType idElementType) {
22+
public DataType(@NotNull ASTNode node, IElementType idElementType) {
2123
super(node, idElementType);
2224
}
2325

2426
/**
2527
* Returns fully qualified name of this message (starting with dot).
2628
*/
29+
@NotNull
2730
public String getQualifiedName() {
2831
PsiElement parent = getParent();
2932
if (parent instanceof ProtoRootNode) {
@@ -46,6 +49,7 @@ public String getQualifiedName() {
4649
/**
4750
* Returns full name of this type without leading dot.
4851
*/
52+
@NotNull
4953
public String getFullName() {
5054
return getQualifiedName().substring(1);
5155
}

src/main/java/io/protostuff/jetbrains/plugin/psi/UserTypeContainer.java renamed to src/main/java/io/protostuff/jetbrains/plugin/psi/DataTypeContainer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
/**
66
* @author Kostiantyn Shchepanovskyi
77
*/
8-
public interface UserTypeContainer {
8+
public interface DataTypeContainer {
99

1010
/**
1111
* Returns string prefix that is common for all children full names.
1212
* For root container it is a dot if package is not set.
1313
*/
1414
String getNamespace();
1515

16-
Collection<UserType> getChildrenTypes();
16+
Collection<DataType> getDeclaredDataTypes();
17+
1718
}

src/main/java/io/protostuff/jetbrains/plugin/psi/EnumNode.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
import com.intellij.lang.ASTNode;
44
import com.intellij.navigation.ItemPresentation;
5-
import com.intellij.psi.PsiElement;
5+
import com.intellij.navigation.ItemPresentationProviders;
66
import io.protostuff.compiler.parser.ProtoParser;
7-
import io.protostuff.jetbrains.plugin.Icons;
87
import io.protostuff.jetbrains.plugin.ProtoParserDefinition;
9-
import io.protostuff.jetbrains.plugin.view.structure.ProtoItemPresentation;
108
import org.jetbrains.annotations.NotNull;
119

1210
import java.util.Arrays;
@@ -16,7 +14,7 @@
1614
* @author Kostiantyn Shchepanovskyi
1715
*/
1816
public class EnumNode
19-
extends UserType {
17+
extends DataType {
2018

2119
public static final String ALLOW_ALIAS = "allow_alias";
2220
public static final String TRUE = "true";
@@ -27,8 +25,7 @@ public EnumNode(@NotNull ASTNode node) {
2725

2826
@Override
2927
public ItemPresentation getPresentation() {
30-
String fullName = getFullName();
31-
return new ProtoItemPresentation(fullName, Icons.ENUM);
28+
return ItemPresentationProviders.getItemPresentation(this);
3229
}
3330

3431
public List<EnumConstantNode> getConstants() {

src/main/java/io/protostuff/jetbrains/plugin/psi/FileReferenceNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public ProtoPsiFileRoot getTarget() {
7373
}
7474

7575
public ProtoPsiFileRoot getTarget(@NotNull String filename, @NotNull Module module) {
76-
Collection<PsiFileSystemItem> roots = FilePathReferenceProvider.getRoots(module, true);
76+
Collection<PsiFileSystemItem> roots = FilePathReferenceProvider.getRoots(module);
7777
for (PsiFileSystemItem root : roots) {
7878
VirtualFile file = root.getVirtualFile().findFileByRelativePath(getFilename());
7979
if (file != null) {

src/main/java/io/protostuff/jetbrains/plugin/psi/MessageNode.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
import com.intellij.lang.ASTNode;
44
import com.intellij.navigation.ItemPresentation;
5+
import com.intellij.navigation.ItemPresentationProviders;
56
import io.protostuff.compiler.parser.ProtoParser;
6-
import io.protostuff.jetbrains.plugin.Icons;
77
import io.protostuff.jetbrains.plugin.ProtoParserDefinition;
8-
import io.protostuff.jetbrains.plugin.view.structure.ProtoItemPresentation;
98
import org.jetbrains.annotations.NotNull;
109
import org.jetbrains.annotations.Nullable;
1110

@@ -16,7 +15,7 @@
1615
/**
1716
* @author Kostiantyn Shchepanovskyi
1817
*/
19-
public class MessageNode extends UserType implements AntlrParserRuleNode, UserTypeContainer {
18+
public class MessageNode extends DataType implements AntlrParserRuleNode, DataTypeContainer {
2019

2120

2221
public static final int RULE_INDEX = ProtoParser.RULE_messageBlock;
@@ -43,8 +42,8 @@ public String getNamespace() {
4342
}
4443

4544
@Override
46-
public Collection<UserType> getChildrenTypes() {
47-
return Arrays.asList(findChildrenByClass(UserType.class));
45+
public Collection<DataType> getDeclaredDataTypes() {
46+
return Arrays.asList(findChildrenByClass(DataType.class));
4847
}
4948

5049
public Collection<MessageField> getFields() {
@@ -62,8 +61,7 @@ public Collection<MessageField> getFields() {
6261

6362
@Override
6463
public ItemPresentation getPresentation() {
65-
String fullName = getFullName();
66-
return new ProtoItemPresentation(fullName, Icons.MESSAGE);
64+
return ItemPresentationProviders.getItemPresentation(this);
6765
}
6866

6967
@NotNull

0 commit comments

Comments
 (0)