Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigating to message, enum or service by name (Ctrl+N) #26

Merged
merged 1 commit into from
Oct 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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);
}
}

}
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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();

}
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading