Skip to content

Commit

Permalink
Navigating to message, enum or service by name (Ctrl+N)
Browse files Browse the repository at this point in the history
  • Loading branch information
kshchepanovskyi committed Oct 1, 2016
1 parent 343d50a commit d5ef60a
Show file tree
Hide file tree
Showing 38 changed files with 709 additions and 89 deletions.
3 changes: 1 addition & 2 deletions README.md
Expand Up @@ -5,8 +5,6 @@

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

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).

Plugin is compatible with IntelliJ IDEA 2016.1. Other JetBrains IDEs of the same or higher version should be supported as well.

### Roadmap
Expand Down Expand Up @@ -36,3 +34,4 @@ Requirements:
### Links

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

6 changes: 1 addition & 5 deletions build.gradle
Expand Up @@ -41,11 +41,7 @@ apply plugin: 'org.jetbrains.intellij'
intellij {
version = ideaVersion
updateSinceUntilBuild = false
// TODO: we do not need dependency on this plugin in runtime
// TODO: should be removed, but then tests are failing with
// TODO: ERROR: java.lang.ClassNotFoundException: com.intellij.lang.properties.PropertiesFileTypeFactory
// plugins 'properties'
downloadSources = false
downloadSources = true
publish {
username = project.hasProperty('jetbrainsUser') \
? project.property('jetbrainsUser') \
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
@@ -1,7 +1,7 @@
# Available idea versions:
# https://www.jetbrains.com/intellij-repository/releases
# https://www.jetbrains.com/intellij-repository/snapshots
version=0.5.0
version=0.7.0
ideaVersion=145.258.11
# https://intellij-support.jetbrains.com/hc/en-us/articles/206544879-Selecting-the-JDK-version-the-IDE-will-run-under
# Java 8 is required to run IntelliJ IDEA starting from version 16
Expand Down
130 changes: 130 additions & 0 deletions src/main/java/io/protostuff/jetbrains/plugin/GoToClassContributor.java
@@ -0,0 +1,130 @@
package io.protostuff.jetbrains.plugin;

import com.intellij.navigation.GotoClassContributor;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.FileTypeIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.indexing.FileBasedIndex;
import io.protostuff.jetbrains.plugin.psi.ProtoPsiFileRoot;
import io.protostuff.jetbrains.plugin.psi.ProtoType;
import io.protostuff.jetbrains.plugin.settings.ProtobufSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

/**
* @author Kostiantyn Shchepanovskyi
*/
public class GoToClassContributor implements GotoClassContributor {

public static String getQualifiedNameUserType(ProtoType protoType) {
return protoType.getFullName();
}

@Nullable
@Override
public String getQualifiedName(final NavigationItem item) {
if (item instanceof ProtoType) {
return getQualifiedNameUserType((ProtoType) item);
}
return null;
}

@Nullable
@Override
public String getQualifiedNameSeparator() {
return ".";
}

@NotNull
@Override
public String[] getNames(Project project, boolean includeNonProjectItems) {
List<ProtoType> types = findUserTypes(project, includeNonProjectItems);
List<String> names = new ArrayList<>(types.size());
for (ProtoType type : types) {
if (type.getName().length() > 0) {
names.add(type.getName());
}
}
return names.toArray(new String[names.size()]);
}

@NotNull
@Override
public NavigationItem[] getItemsByName(String name, String pattern, Project project, boolean includeNonProjectItems) {
List<ProtoType> types = findUserTypes(project, includeNonProjectItems, name);
return types.toArray(new NavigationItem[types.size()]);
}

private List<ProtoType> findUserTypes(Project project, boolean includeNonProjectItems) {
return getProtoTypes(project, includeNonProjectItems,
protoType -> true);
}

private List<ProtoType> findUserTypes(Project project, boolean includeNonProjectItems, String key) {
return getProtoTypes(project, includeNonProjectItems,
protoType -> key.equals(protoType.getName()));
}

@NotNull
private List<ProtoType> getProtoTypes(Project project, boolean includeNonProjectItems, Predicate<ProtoType> filter) {
List<ProtoType> result = new ArrayList<>();
List<VirtualFile> files = new ArrayList<>();
addProjectAndLibraryFiles(project, includeNonProjectItems, files);
if (includeNonProjectItems) {
addFilesFromCustomIncludePath(project, files);
}
for (VirtualFile virtualFile : files) {
ProtoPsiFileRoot file = (ProtoPsiFileRoot) PsiManager.getInstance(project).findFile(virtualFile);
if (file != null) {
Collection<ProtoType> types = file.getAllTypes();
for (ProtoType type : types) {
if (filter.test(type)) {
result.add(type);
}
}
}
}
return result;
}

private void addProjectAndLibraryFiles(Project project, boolean includeNonProjectItems, List<VirtualFile> files) {
FileBasedIndex index = FileBasedIndex.getInstance();
GlobalSearchScope scope = getSearchScope(project, includeNonProjectItems);
files.addAll(index.getContainingFiles(FileTypeIndex.NAME, ProtoFileType.INSTANCE, scope));
}

private void addFilesFromCustomIncludePath(Project project, List<VirtualFile> files) {
ProtobufSettings settings = project.getComponent(ProtobufSettings.class);
List<VirtualFile> includePaths = settings.getIncludePathsVf();
for (VirtualFile includePath : includePaths) {
FileBasedIndex.iterateRecursively(includePath, file -> {
if (!file.isDirectory() && isProtoFile(file)) {
files.add(file);
}
return true;
}, null, null, null);
}
}

private boolean isProtoFile(VirtualFile file) {
return file.getName().toLowerCase().endsWith(ProtoFileType.FILE_EXTENSION);
}

@NotNull
private GlobalSearchScope getSearchScope(Project project, boolean includeNonProjectItems) {
if (includeNonProjectItems) {
return GlobalSearchScope.allScope(project);
} else {
return GlobalSearchScope.projectScope(project);
}
}

}
Expand Up @@ -4,13 +4,9 @@
import com.intellij.lang.cacheBuilder.WordsScanner;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.tree.TokenSet;
import io.protostuff.compiler.parser.ProtoLexer;
import io.protostuff.jetbrains.plugin.psi.EnumNode;
import io.protostuff.jetbrains.plugin.psi.MessageNode;
import io.protostuff.jetbrains.plugin.psi.UserType;
import org.antlr.jetbrains.adapter.lexer.PSIElementTypeFactory;
import io.protostuff.jetbrains.plugin.psi.DataType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

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

@Override
public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
return psiElement instanceof UserType;
return psiElement instanceof DataType;
}

@Nullable
Expand All @@ -55,8 +51,8 @@ public String getType(@NotNull PsiElement element) {
@NotNull
@Override
public String getDescriptiveName(@NotNull PsiElement element) {
if (element instanceof UserType) {
UserType type = (UserType) element;
if (element instanceof DataType) {
DataType type = (DataType) element;
return type.getFullName();
}
return "";
Expand All @@ -65,8 +61,8 @@ public String getDescriptiveName(@NotNull PsiElement element) {
@NotNull
@Override
public String getNodeText(@NotNull PsiElement element, boolean useFullName) {
if (element instanceof UserType) {
UserType type = (UserType) element;
if (element instanceof DataType) {
DataType type = (DataType) element;
if (useFullName) {
return type.getFullName();
}
Expand Down
Expand Up @@ -11,19 +11,22 @@
import org.jetbrains.annotations.Nullable;

/**
* User-defined proto type that can be used as a field - message or enum.
*
* @author Kostiantyn Shchepanovskyi
*/
public class UserType
public class DataType
extends IdentifierDefSubtree
implements ScopeNode, KeywordsContainer {
implements ScopeNode, KeywordsContainer, ProtoType {

public UserType(@NotNull ASTNode node, IElementType idElementType) {
public DataType(@NotNull ASTNode node, IElementType idElementType) {
super(node, idElementType);
}

/**
* Returns fully qualified name of this message (starting with dot).
*/
@NotNull
public String getQualifiedName() {
PsiElement parent = getParent();
if (parent instanceof ProtoRootNode) {
Expand All @@ -46,6 +49,7 @@ public String getQualifiedName() {
/**
* Returns full name of this type without leading dot.
*/
@NotNull
public String getFullName() {
return getQualifiedName().substring(1);
}
Expand Down
Expand Up @@ -5,13 +5,14 @@
/**
* @author Kostiantyn Shchepanovskyi
*/
public interface UserTypeContainer {
public interface DataTypeContainer {

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

Collection<UserType> getChildrenTypes();
Collection<DataType> getDeclaredDataTypes();

}
Expand Up @@ -2,11 +2,9 @@

import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.psi.PsiElement;
import com.intellij.navigation.ItemPresentationProviders;
import io.protostuff.compiler.parser.ProtoParser;
import io.protostuff.jetbrains.plugin.Icons;
import io.protostuff.jetbrains.plugin.ProtoParserDefinition;
import io.protostuff.jetbrains.plugin.view.structure.ProtoItemPresentation;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
Expand All @@ -16,7 +14,7 @@
* @author Kostiantyn Shchepanovskyi
*/
public class EnumNode
extends UserType {
extends DataType {

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

@Override
public ItemPresentation getPresentation() {
String fullName = getFullName();
return new ProtoItemPresentation(fullName, Icons.ENUM);
return ItemPresentationProviders.getItemPresentation(this);
}

public List<EnumConstantNode> getConstants() {
Expand Down
Expand Up @@ -73,7 +73,7 @@ public ProtoPsiFileRoot getTarget() {
}

public ProtoPsiFileRoot getTarget(@NotNull String filename, @NotNull Module module) {
Collection<PsiFileSystemItem> roots = FilePathReferenceProvider.getRoots(module, true);
Collection<PsiFileSystemItem> roots = FilePathReferenceProvider.getRoots(module);
for (PsiFileSystemItem root : roots) {
VirtualFile file = root.getVirtualFile().findFileByRelativePath(getFilename());
if (file != null) {
Expand Down
Expand Up @@ -2,10 +2,9 @@

import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import io.protostuff.compiler.parser.ProtoParser;
import io.protostuff.jetbrains.plugin.Icons;
import io.protostuff.jetbrains.plugin.ProtoParserDefinition;
import io.protostuff.jetbrains.plugin.view.structure.ProtoItemPresentation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -16,7 +15,7 @@
/**
* @author Kostiantyn Shchepanovskyi
*/
public class MessageNode extends UserType implements AntlrParserRuleNode, UserTypeContainer {
public class MessageNode extends DataType implements AntlrParserRuleNode, DataTypeContainer {


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

@Override
public Collection<UserType> getChildrenTypes() {
return Arrays.asList(findChildrenByClass(UserType.class));
public Collection<DataType> getDeclaredDataTypes() {
return Arrays.asList(findChildrenByClass(DataType.class));
}

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

@Override
public ItemPresentation getPresentation() {
String fullName = getFullName();
return new ProtoItemPresentation(fullName, Icons.MESSAGE);
return ItemPresentationProviders.getItemPresentation(this);
}

@NotNull
Expand Down

0 comments on commit d5ef60a

Please sign in to comment.