Skip to content

Commit 32a0dc4

Browse files
#24: Support for IntelliJ IDEA 13 and compatible products
Add support for IntelliJ IDEA 13, PhpStorm 7, PyCharm 3.1, WebStorm 7, RubyMine 7, Android Studio 1.3, AppCode 3.3, CLion 1.2, DataGrip 1.0
1 parent 6db6dd2 commit 32a0dc4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+465
-201
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,19 @@
77

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

10-
Plugin is compatible with IntelliJ IDEA 2016.1. Other JetBrains IDEs of the same or higher version should be supported as well.
10+
Plugin is compatible with following JetBrains IDE releases (and higher versions):
11+
12+
| Product | Version |
13+
|--------------------|---------|
14+
| Android Studio | 1.3 |
15+
| AppCode | 3.3 |
16+
| CLion | 1.2 |
17+
| DataGrip | 1.0 |
18+
| **IntelliJ IDEA** | 13 |
19+
| PhpStorm | 7 |
20+
| PyCharm | 3.1 |
21+
| RubyMine | 7 |
22+
| WebStorm | 7 |
1123

1224
### Roadmap
1325

build.gradle

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ repositories {
2222

2323
dependencies {
2424
compile 'org.antlr:antlr4-runtime:4.5.1'
25-
compile 'org.antlr:antlr4-jetbrains-adapter:1.0.0'
25+
compile ('org.antlr:antlr4-jetbrains-adapter:1.1.0') {
26+
exclude group: 'com.jetbrains'
27+
}
2628
compile 'com.google.guava:guava:19.0'
27-
compile 'io.protostuff:protostuff-parser:2.0.0-alpha25'
29+
compile 'io.protostuff:protostuff-parser:2.0.0-alpha26'
2830
}
2931

3032
apply plugin: 'idea'
@@ -39,11 +41,7 @@ apply plugin: 'org.jetbrains.intellij'
3941
intellij {
4042
version = ideaVersion
4143
updateSinceUntilBuild = false
42-
// TODO: we do not need dependency on this plugin in runtime
43-
// TODO: should be removed, but then tests are failing with
44-
// TODO: ERROR: java.lang.ClassNotFoundException: com.intellij.lang.properties.PropertiesFileTypeFactory
45-
// plugins 'properties'
46-
downloadSources = false
44+
downloadSources = true
4745
publish {
4846
username = project.hasProperty('jetbrainsUser') \
4947
? project.property('jetbrainsUser') \

gradle.properties

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
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
5-
ideaVersion=145.258.11
4+
version=0.6.0
5+
ideaVersion=14.1.7
66
# https://intellij-support.jetbrains.com/hc/en-us/articles/206544879-Selecting-the-JDK-version-the-IDE-will-run-under
7-
# Java 8 is required to run IntelliJ IDEA starting from version 16
8-
javaVersion=1.8
7+
# Java 8 is required to run IntelliJ IDEA starting from version 16.
8+
# Java 6 is required for previous versions.
9+
javaVersion=1.6

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class ProtoColorSettingsPage implements ColorSettingsPage {
2525
private Map<String, TextAttributesKey> additionalTags;
2626

2727
public ProtoColorSettingsPage() {
28-
additionalTags = new HashMap<>();
28+
additionalTags = new HashMap<String, TextAttributesKey>();
2929
additionalTags.put("keyword", ProtoSyntaxHighlighter.KEYWORD);
3030
additionalTags.put("constant", ProtoSyntaxHighlighter.ENUM_CONSTANT);
3131

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

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.protostuff.jetbrains.plugin;
22

3+
import com.google.common.base.Throwables;
34
import com.intellij.lang.ASTNode;
45
import com.intellij.lang.ParserDefinition;
56
import com.intellij.lang.PsiParser;
@@ -23,10 +24,10 @@
2324
import org.antlr.v4.runtime.tree.ParseTree;
2425
import org.jetbrains.annotations.NotNull;
2526

27+
import java.lang.reflect.Constructor;
2628
import java.util.HashMap;
2729
import java.util.List;
2830
import java.util.Map;
29-
import java.util.function.Function;
3031

3132
import static io.protostuff.compiler.parser.ProtoLexer.*;
3233

@@ -211,43 +212,43 @@ public static RuleIElementType rule(int rule) {
211212
return RULE_TYPES.get(rule);
212213
}
213214

214-
private final Map<Integer, Function<ASTNode, ANTLRPsiNode>> elementFactories = new HashMap<>();
215+
private final Map<Integer, Class<? extends ANTLRPsiNode>> classByRuleIndex = new HashMap<Integer, Class<? extends ANTLRPsiNode>>();
215216

216217
public ProtoParserDefinition() {
217-
register(ProtoParser.RULE_syntax, SyntaxNode::new);
218-
register(ProtoParser.RULE_packageStatement, PackageStatement::new);
219-
register(ProtoParser.RULE_importStatement, ImportNode::new);
220-
register(ProtoParser.RULE_fileReference, FileReferenceNode::new);
221-
register(ProtoParser.RULE_messageBlock, MessageNode::new);
222-
register(ProtoParser.RULE_messageName, MessageNameNode::new);
223-
register(ProtoParser.RULE_field, FieldNode::new);
224-
register(ProtoParser.RULE_typeReference, TypeReferenceNode::new);
225-
register(ProtoParser.RULE_groupBlock, GroupNode::new);
226-
register(ProtoParser.RULE_enumBlock, EnumNode::new);
227-
register(ProtoParser.RULE_enumField, EnumConstantNode::new);
228-
register(ProtoParser.RULE_serviceBlock, ServiceNode::new);
229-
register(ProtoParser.RULE_rpcMethod, RpcMethodNode::new);
230-
register(ProtoParser.RULE_optionEntry, OptionEntryNode::new);
231-
register(ProtoParser.RULE_option, OptionNode::new);
232-
register(ProtoParser.RULE_oneof, OneOfNode::new);
233-
register(ProtoParser.RULE_oneofField, OneofFieldNode::new);
234-
register(ProtoParser.RULE_extendBlock, ExtendNode::new);
235-
register(ProtoParser.RULE_extensions, ExtensionsNode::new);
236-
register(ProtoParser.RULE_map, MapNode::new);
237-
register(ProtoParser.RULE_mapKey, MapKeyNode::new);
238-
register(ProtoParser.RULE_optionValue, OptionValueNode::new);
239-
register(ProtoParser.RULE_range, RangeNode::new);
240-
register(ProtoParser.RULE_reservedFieldRanges, ReservedFieldRangesNode::new);
241-
register(ProtoParser.RULE_reservedFieldNames, ReservedFieldNamesNode::new);
242-
register(ProtoParser.RULE_rpcType, RpcMethodTypeNode::new);
243-
register(ProtoParser.RULE_proto, ProtoRootNode::new);
218+
register(ProtoParser.RULE_syntax, SyntaxNode.class);
219+
register(ProtoParser.RULE_packageStatement, PackageStatement.class);
220+
register(ProtoParser.RULE_importStatement, ImportNode.class);
221+
register(ProtoParser.RULE_fileReference, FileReferenceNode.class);
222+
register(ProtoParser.RULE_messageBlock, MessageNode.class);
223+
register(ProtoParser.RULE_messageName, MessageNameNode.class);
224+
register(ProtoParser.RULE_field, FieldNode.class);
225+
register(ProtoParser.RULE_typeReference, TypeReferenceNode.class);
226+
register(ProtoParser.RULE_groupBlock, GroupNode.class);
227+
register(ProtoParser.RULE_enumBlock, EnumNode.class);
228+
register(ProtoParser.RULE_enumField, EnumConstantNode.class);
229+
register(ProtoParser.RULE_serviceBlock, ServiceNode.class);
230+
register(ProtoParser.RULE_rpcMethod, RpcMethodNode.class);
231+
register(ProtoParser.RULE_optionEntry, OptionEntryNode.class);
232+
register(ProtoParser.RULE_option, OptionNode.class);
233+
register(ProtoParser.RULE_oneof, OneOfNode.class);
234+
register(ProtoParser.RULE_oneofField, OneofFieldNode.class);
235+
register(ProtoParser.RULE_extendBlock, ExtendNode.class);
236+
register(ProtoParser.RULE_extensions, ExtensionsNode.class);
237+
register(ProtoParser.RULE_map, MapNode.class);
238+
register(ProtoParser.RULE_mapKey, MapKeyNode.class);
239+
register(ProtoParser.RULE_optionValue, OptionValueNode.class);
240+
register(ProtoParser.RULE_range, RangeNode.class);
241+
register(ProtoParser.RULE_reservedFieldRanges, ReservedFieldRangesNode.class);
242+
register(ProtoParser.RULE_reservedFieldNames, ReservedFieldNamesNode.class);
243+
register(ProtoParser.RULE_rpcType, RpcMethodTypeNode.class);
244+
register(ProtoParser.RULE_proto, ProtoRootNode.class);
244245
}
245246

246-
private void register(int rule, Function<ASTNode, ANTLRPsiNode> factory) {
247-
if (elementFactories.containsKey(rule)) {
247+
private void register(int rule, Class<? extends ANTLRPsiNode> resultNodeClass) {
248+
if (classByRuleIndex.containsKey(rule)) {
248249
throw new IllegalStateException("Duplicate rule");
249250
}
250-
elementFactories.put(rule, factory);
251+
classByRuleIndex.put(rule, resultNodeClass);
251252
}
252253

253254
@NotNull
@@ -309,9 +310,14 @@ public ANTLRPsiNode createElement(ASTNode node) {
309310
}
310311
RuleIElementType ruleElType = (RuleIElementType) elType;
311312
int ruleIndex = ruleElType.getRuleIndex();
312-
if (elementFactories.containsKey(ruleIndex)) {
313-
Function<ASTNode, ANTLRPsiNode> factory = elementFactories.get(ruleIndex);
314-
return factory.apply(node);
313+
if (classByRuleIndex.containsKey(ruleIndex)) {
314+
Class<? extends ANTLRPsiNode> nodeClass = classByRuleIndex.get(ruleIndex);
315+
try {
316+
Constructor<? extends ANTLRPsiNode> constructor = nodeClass.getConstructor(ASTNode.class);
317+
return constructor.newInstance(node);
318+
} catch (Exception e) {
319+
throw Throwables.propagate(e);
320+
}
315321
}
316322
return new ANTLRPsiNode(node);
317323
}

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

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

33
import com.intellij.ide.plugins.IdeaPluginDescriptor;
44
import com.intellij.ide.plugins.PluginManager;
5+
import com.intellij.notification.Notification;
56
import com.intellij.notification.NotificationGroup;
7+
import com.intellij.notification.NotificationListener;
68
import com.intellij.notification.NotificationType;
79
import com.intellij.openapi.application.Application;
810
import com.intellij.openapi.application.ApplicationManager;
@@ -56,17 +58,20 @@ private void checkConflictingPlugins() {
5658
}
5759
}
5860

59-
private void askUserToDisablePlugins(Collection<IdeaPluginDescriptor> conflictingPlugins) {
61+
private void askUserToDisablePlugins(final Collection<IdeaPluginDescriptor> conflictingPlugins) {
6062
final String text = formatMessage(conflictingPlugins);
6163
NotificationGroup ng = NotificationGroup.balloonGroup("Conflicting Plugins");
6264
ng.createNotification(PLUGIN_NAME, text, NotificationType.WARNING,
63-
(notification, event) -> {
64-
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
65-
for (IdeaPluginDescriptor foreignPlugin : conflictingPlugins) {
66-
PluginManager.disablePlugin(foreignPlugin.getPluginId().toString());
65+
new NotificationListener() {
66+
@Override
67+
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
68+
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
69+
for (IdeaPluginDescriptor foreignPlugin : conflictingPlugins) {
70+
PluginManager.disablePlugin(foreignPlugin.getPluginId().toString());
71+
}
72+
Application application = ApplicationManager.getApplication();
73+
application.restart();
6774
}
68-
Application application = ApplicationManager.getApplication();
69-
application.restart();
7075
}
7176
}).notify(project);
7277
}
@@ -78,10 +83,15 @@ private String formatMessage(Collection<IdeaPluginDescriptor> conflictingPlugins
7883
}
7984

8085
private String formatHtmlPluginList(Collection<IdeaPluginDescriptor> conflictingPlugins) {
81-
return String.join("\n", conflictingPlugins.stream()
82-
.map(IdeaPluginDescriptor::getName)
83-
.map(name -> "<li>" + name + "</li>")
84-
.collect(Collectors.toList()));
86+
StringBuilder sb = new StringBuilder();
87+
for (IdeaPluginDescriptor plugin : conflictingPlugins) {
88+
String name = plugin.getName();
89+
sb.append("<li>");
90+
sb.append(name);
91+
sb.append("</li>");
92+
sb.append("\n");
93+
}
94+
return sb.toString();
8595
}
8696

8797
@Override
@@ -101,7 +111,7 @@ public String getComponentName() {
101111
private static class FileTypeUtil {
102112

103113
private final IdeaPluginDescriptor self = PluginManager.getPlugin(PluginId.getId(PLUGIN_ID));
104-
private final Map<String, FileTypeEntry> fileTypes = new LinkedHashMap<>();
114+
private final Map<String, FileTypeEntry> fileTypes = new LinkedHashMap<String, FileTypeEntry>();
105115

106116
FileTypeUtil() {
107117
ExtensionPoint<FileTypeFactory> ep = Extensions.getRootArea().getExtensionPoint(FILE_TYPE_FACTORY_EP);
@@ -119,7 +129,7 @@ public void consume(@NotNull final FileType fileType, String extensions) {
119129

120130
@Override
121131
public void consume(@NotNull final FileType fileType, @NotNull final FileNameMatcher... matchers) {
122-
register(fileType, new ArrayList<>(Arrays.asList(matchers)));
132+
register(fileType, new ArrayList<FileNameMatcher>(Arrays.asList(matchers)));
123133
}
124134

125135
@Override
@@ -147,24 +157,24 @@ private List<FileNameMatcher> parse(@Nullable String semicolonDelimited) {
147157
}
148158

149159
StringTokenizer tokenizer = new StringTokenizer(semicolonDelimited, FileTypeConsumer.EXTENSION_DELIMITER, false);
150-
ArrayList<FileNameMatcher> list = new ArrayList<>();
160+
ArrayList<FileNameMatcher> list = new ArrayList<FileNameMatcher>();
151161
while (tokenizer.hasMoreTokens()) {
152162
list.add(new ExtensionFileNameMatcher(tokenizer.nextToken().trim()));
153163
}
154164
return list;
155165
}
156166

157167
Collection<IdeaPluginDescriptor> getPluginsForFile(String filename) {
158-
Map<PluginId, IdeaPluginDescriptor> plugins = new HashMap<>();
159-
fileTypes.values().forEach(type -> {
168+
Map<PluginId, IdeaPluginDescriptor> plugins = new HashMap<PluginId, IdeaPluginDescriptor>();
169+
for (FileTypeEntry type : fileTypes.values()) {
160170
if (type.match(filename)) {
161171
Class<? extends FileType> fileTypeClass = type.fileType.getClass();
162172
PluginId pluginId = PluginManager.getPluginByClassName(fileTypeClass.getName());
163173
if (pluginId != null && !Objects.equals(self.getPluginId(), pluginId)) {
164174
plugins.put(pluginId, PluginManager.getPlugin(pluginId));
165175
}
166176
}
167-
});
177+
}
168178
return plugins.values();
169179
}
170180

src/main/java/io/protostuff/jetbrains/plugin/annotator/ProtoErrorsAnnotator.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder hold
5858
}
5959

6060
private void checkDuplicateServiceMethodNames(List<RpcMethodNode> rpcMethods) {
61-
Map<String, RpcMethodNode> methodByName = new HashMap<>();
61+
Map<String, RpcMethodNode> methodByName = new HashMap<String, RpcMethodNode>();
6262
for (RpcMethodNode methods : rpcMethods) {
6363
String name = methods.getMethodName();
6464
if (methodByName.containsKey(name)) {
@@ -74,7 +74,7 @@ private void checkDuplicateEnumConstantValues(EnumNode anEnum, List<EnumConstant
7474
if (anEnum.allowAlias()) {
7575
return;
7676
}
77-
Map<Integer, EnumConstantNode> fieldByTag = new HashMap<>();
77+
Map<Integer, EnumConstantNode> fieldByTag = new HashMap<Integer, EnumConstantNode>();
7878
for (EnumConstantNode constant : constants) {
7979
int tag = constant.getConstantValue();
8080
if (fieldByTag.containsKey(tag)) {
@@ -87,7 +87,7 @@ private void checkDuplicateEnumConstantValues(EnumNode anEnum, List<EnumConstant
8787
}
8888

8989
private void checkDuplicateEnumConstantNames(List<EnumConstantNode> constants) {
90-
Map<String, EnumConstantNode> fieldByName = new HashMap<>();
90+
Map<String, EnumConstantNode> fieldByName = new HashMap<String, EnumConstantNode>();
9191
for (EnumConstantNode constant : constants) {
9292
String name = constant.getConstantName();
9393
if (fieldByName.containsKey(name)) {
@@ -164,7 +164,7 @@ boolean isValidTagValue(int tag) {
164164
}
165165

166166
private void checkDuplicateFieldTags(Collection<MessageField> fields) {
167-
Map<Integer, MessageField> fieldByTag = new HashMap<>();
167+
Map<Integer, MessageField> fieldByTag = new HashMap<Integer, MessageField>();
168168
for (MessageField field : fields) {
169169
int tag = field.getTag();
170170
if (fieldByTag.containsKey(tag)) {
@@ -177,7 +177,7 @@ private void checkDuplicateFieldTags(Collection<MessageField> fields) {
177177
}
178178

179179
private void checkDuplicateFieldNames(Collection<MessageField> fields) {
180-
Map<String, MessageField> fieldByName = new HashMap<>();
180+
Map<String, MessageField> fieldByName = new HashMap<String, MessageField>();
181181
for (MessageField field : fields) {
182182
String name = field.getFieldName();
183183
if (fieldByName.containsKey(name)) {

0 commit comments

Comments
 (0)