IDEA-115359 Gradle: generate apply plugin dsl code with alt-insert

This commit is contained in:
Vladislav.Soroka
2013-10-24 12:30:26 +04:00
parent a57dfa4584
commit 0fb461e070
14 changed files with 379 additions and 6 deletions
+2
View File
@@ -6,6 +6,7 @@
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/testSources" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/testData" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
@@ -176,6 +177,7 @@
</library>
</orderEntry>
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
<orderEntry type="module" module-name="maven" />
</component>
</module>
@@ -22,4 +22,8 @@ gradle.action.open.script.description=Allows to open project file of the linked
gradle.notifications.use.distribution.with.sources=You can configure Gradle wrapper to use distribution with sources. \
It will provide IDE with Gradle API/DSL documentation.
gradle.notifications.hide.tip=Hide the tip
gradle.notifications.apply.suggestion=Ok, apply suggestion!
gradle.notifications.apply.suggestion=Ok, apply suggestion!
gradle.codeInsight.action.apply_plugin.text=Add Gradle plugin
gradle.codeInsight.action.apply_plugin.description=Add selected gradle plugin to the project
gradle.codeInsight.action.apply_plugin.popup.title=Choose plugin
@@ -42,13 +42,13 @@ gradle.documentation.org.gradle.api.Project.apply.plugin.announce=\
gradle.documentation.org.gradle.api.Project.apply.plugin.build-announcements=\
<p>Sends local announcements to your desktop about interesting events in the build lifecycle.</p>
gradle.documentation.org.gradle.api.Project.apply.plugin.checkstyle=\
<p>Performs quality checks on your project's Java source files using\
<p>Performs quality checks on your project's Java source files using \
<a class="ulink" href="http://checkstyle.sourceforge.net/index.html" target="_top">Checkstyle</a> \
and generates reports from these checks.\
</p>
gradle.documentation.org.gradle.api.Project.apply.plugin.codenarc=\
<p>Performs quality checks on your project's Groovy source files using \
<a class="ulink" href="http://codenarc.sourceforge.net/index.html" target="_top">CodeNarc</a>\
<a class="ulink" href="http://codenarc.sourceforge.net/index.html" target="_top">CodeNarc</a> \
and generates reports from these checks.\
</p>
gradle.documentation.org.gradle.api.Project.apply.plugin.eclipse=\
@@ -62,7 +62,7 @@ gradle.documentation.org.gradle.api.Project.apply.plugin.eclipse-wtp=\
</p>
gradle.documentation.org.gradle.api.Project.apply.plugin.findbugs=\
<p>Performs quality checks on your project's Java source files using \
<a class="ulink" href="http://findbugs.sourceforge.net" target="_top">FindBugs</a>\
<a class="ulink" href="http://findbugs.sourceforge.net" target="_top">FindBugs</a> \
and generates reports from these checks.\
</p>
gradle.documentation.org.gradle.api.Project.apply.plugin.idea=\
@@ -76,7 +76,7 @@ gradle.documentation.org.gradle.api.Project.apply.plugin.jdepend=\
</p>
gradle.documentation.org.gradle.api.Project.apply.plugin.pmd=\
<p>Performs quality checks on your project's Java source files using \
<a class="ulink" href="http://pmd.sourceforge.net" target="_top">PMD</a>\
<a class="ulink" href="http://pmd.sourceforge.net" target="_top">PMD</a> \
and generates reports from these checks.\
</p>
gradle.documentation.org.gradle.api.Project.apply.plugin.project-report=\
Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

+6 -1
View File
@@ -93,5 +93,10 @@
<referenceTypeEnhancer implementation="org.jetbrains.plugins.gradle.service.resolve.NamedDomainObjectCollectionTypeEnhancer"/>
<unresolvedHighlightFilter implementation="org.jetbrains.plugins.gradle.service.resolve.GradleUnresolvedReferenceFilter"/>
</extensions>
<actions>
<action id="Gradle.GenerateGroup" class="org.jetbrains.plugins.gradle.codeInsight.actions.GradleGenerateActionGroup" text="Generate">
<add-to-group group-id="GenerateGroup" anchor="first"/>
</action>
</actions>
</idea-plugin>
@@ -31,6 +31,7 @@ public class GradleIcons {
public static final Icon Gradle = load("/icons/gradle.png"); // 16x16
public static final Icon GradleImport = load("/icons/gradleImport.png"); // 16x16
public static final Icon GradleNavigate = load("/icons/gradleNavigate.png"); // 16x16
public static final Icon GradlePlugin = load("/icons/gradlePlugin.png"); // 16x16
public static final Icon GradleSync = load("/icons/gradleSync.png"); // 16x16
public static final Icon ToolWindowGradle = load("/icons/toolWindowGradle.png"); // 13x13
}
@@ -0,0 +1,90 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.gradle.codeInsight.actions;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.actions.CodeInsightAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.KeyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import icons.GradleIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.jetbrains.plugins.gradle.util.GradleDocumentationBundle;
import org.jetbrains.plugins.groovy.GroovyFileType;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* @author Vladislav.Soroka
* @since 10/22/13
*/
public class AddGradleDslPluginAction extends CodeInsightAction {
public static final ThreadLocal<String> TEST_THREAD_LOCAL = new ThreadLocal<String>();
private final KeyValue[] myPlugins;
public AddGradleDslPluginAction() {
getTemplatePresentation().setDescription(GradleBundle.message("gradle.codeInsight.action.apply_plugin.description"));
getTemplatePresentation().setText(GradleBundle.message("gradle.codeInsight.action.apply_plugin.text"));
getTemplatePresentation().setIcon(GradleIcons.GradlePlugin);
final List<String> plugins = StringUtil.split(
"java,groovy,idea,eclipse,scala,antlr,application,ear,jetty,maven,osgi,war,announce," +
"build-announcements,checkstyle,codenarc,eclipse-wtp,findbugs,jdepend,pmd,project-report,signing,sonar", ",");
myPlugins = new KeyValue[plugins.size()];
ContainerUtil.map2Array(plugins, myPlugins, new Function<String, KeyValue>() {
@Override
public KeyValue fun(String o) {
return createPluginKey(o);
}
});
Arrays.sort(myPlugins, new Comparator<KeyValue>() {
@Override
public int compare(KeyValue o1, KeyValue o2) {
return String.valueOf(o1.getKey()).compareTo(String.valueOf(o2.getKey()));
}
});
}
@NotNull
@Override
protected CodeInsightActionHandler getHandler() {
return new AddGradleDslPluginActionHandler(myPlugins);
}
@Override
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
if (file instanceof PsiCompiledElement) return false;
if (!GroovyFileType.GROOVY_FILE_TYPE.equals(file.getFileType())) return false;
return !GradleConstants.SETTINGS_FILE_NAME.equals(file.getName()) && file.getName().endsWith(GradleConstants.EXTENSION);
}
@NotNull
private static KeyValue<String, String> createPluginKey(@NotNull String pluginName) {
String description =
GradleDocumentationBundle.messageOrDefault("gradle.documentation.org.gradle.api.Project.apply.plugin." + pluginName, "");
return KeyValue.create(pluginName, description);
}
}
@@ -0,0 +1,165 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.gradle.codeInsight.actions;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.EditorFontType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.KeyValue;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.components.JBList;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import javax.swing.*;
import java.awt.*;
/**
* @author Vladislav.Soroka
* @since 10/24/13
*/
class AddGradleDslPluginActionHandler implements CodeInsightActionHandler {
private final KeyValue[] myPlugins;
public AddGradleDslPluginActionHandler(KeyValue[] plugins) {
myPlugins = plugins;
}
@Override
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return;
final JBList list = new JBList(myPlugins);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(new MyListCellRenderer());
Runnable runnable = new Runnable() {
@Override
public void run() {
final KeyValue selected = (KeyValue)list.getSelectedValue();
new WriteCommandAction.Simple(project, GradleBundle.message("gradle.codeInsight.action.apply_plugin.text"), file) {
@Override
protected void run() {
if (selected == null) return;
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
GrStatement grStatement = factory.createStatementFromText(
String.format("apply plugin: '%s'", selected.getKey()), null);
PsiElement anchor = file.findElementAt(editor.getCaretModel().getOffset());
PsiElement currentElement = PsiTreeUtil.getParentOfType(anchor, GrClosableBlock.class, GroovyFile.class);
if (currentElement != null) {
currentElement.addAfter(grStatement, anchor);
}
else {
file.addAfter(grStatement, file.findElementAt(editor.getCaretModel().getOffset() - 1));
}
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
Document document = documentManager.getDocument(file);
if (document != null) {
documentManager.commitDocument(document);
}
}
}.execute();
}
};
if (ApplicationManager.getApplication().isUnitTestMode()) {
KeyValue descriptor = ContainerUtil.find(myPlugins, new Condition<KeyValue>() {
@Override
public boolean value(KeyValue value) {
return value.getKey().equals(AddGradleDslPluginAction.TEST_THREAD_LOCAL.get());
}
});
list.setSelectedValue(descriptor, false);
runnable.run();
}
else {
JBPopupFactory.getInstance().createListPopupBuilder(list)
.setTitle(GradleBundle.message("gradle.codeInsight.action.apply_plugin.popup.title"))
.setItemChoosenCallback(runnable)
.setFilteringEnabled(new Function<Object, String>() {
@Override
public String fun(Object o) {
return String.valueOf(((KeyValue)o).getKey());
}
})
.createPopup()
.showInBestPositionFor(editor);
}
}
@Override
public boolean startInWriteAction() {
return false;
}
private static class MyListCellRenderer implements ListCellRenderer {
private final JPanel myPanel;
private final JLabel myNameLabel;
private final JLabel myDescLabel;
public MyListCellRenderer() {
myPanel = new JPanel(new BorderLayout());
myPanel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
myNameLabel = new JLabel();
myPanel.add(myNameLabel, BorderLayout.WEST);
myPanel.add(new JLabel(" "));
myDescLabel = new JLabel();
myPanel.add(myDescLabel, BorderLayout.EAST);
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
Font font = scheme.getFont(EditorFontType.PLAIN);
myNameLabel.setFont(font);
myDescLabel.setFont(font);
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
KeyValue descriptor = (KeyValue)value;
Color backgroundColor = isSelected ? list.getSelectionBackground() : list.getBackground();
myNameLabel.setText(String.valueOf(descriptor.getKey()));
myNameLabel.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
myPanel.setBackground(backgroundColor);
String description = String.format("<html><div WIDTH=%d>%s</div><html>", 400, String.valueOf(descriptor.getValue()));
myDescLabel.setText(description);
myDescLabel.setForeground(LookupCellRenderer.getGrayedForeground(isSelected));
myDescLabel.setBackground(backgroundColor);
return myPanel;
}
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.gradle.codeInsight.actions;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
/**
* @author Vladislav.Soroka
* @since 10/22/13
*/
public class GradleGenerateActionGroup extends DefaultActionGroup {
public GradleGenerateActionGroup() {
add(new AddGradleDslPluginAction());
}
}
@@ -0,0 +1 @@
//empty file
@@ -0,0 +1,6 @@
apply plugin: "groovy"
allprojects {
//<caret>
}
@@ -0,0 +1,6 @@
apply plugin: "groovy"
allprojects {
//
apply plugin: 'java'}
@@ -0,0 +1,2 @@
//empty file
apply plugin: 'java'
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.gradle.codeInsight.actions;
import com.intellij.testFramework.IdeaTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.fixtures.CodeInsightTestUtil;
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
import java.io.File;
/**
* @author Vladislav.Soroka
* @since 10/23/13
*/
public class AddGradleDslPluginActionTest extends LightPlatformCodeInsightFixtureTestCase {
public AddGradleDslPluginActionTest() {
IdeaTestCase.initPlatformPrefix();
}
public void testApplyPlugin() throws Exception {
doTest("testApplyPlugin.gradle", "java");
}
public void testApplyPluginInsideClosure() throws Exception {
myFixture.configureByFile("testApplyPluginInsideClosure.gradle");
doTest("testApplyPluginInsideClosure.gradle", "java");
}
private void doTest(String file, String pluginName) {
AddGradleDslPluginAction.TEST_THREAD_LOCAL.set(pluginName);
CodeInsightTestUtil.doActionTest(new AddGradleDslPluginAction(), file, myFixture);
}
@Override
public void setUp() throws Exception {
super.setUp();
}
@Override
protected String getBasePath() {
return "/plugins/gradle/testData";
}
@Override
protected String getTestDataPath() {
return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + getBasePath();
}
}