Merge remote-tracking branch 'origin/master'

This commit is contained in:
Maxim.Mossienko
2015-01-13 10:45:02 +01:00
17 changed files with 293 additions and 348 deletions
@@ -1226,42 +1226,6 @@ public class Test {
assert !lookup
}
public void testBlockSelection() {
doTestBlockSelection """
class Foo {{
<caret>tx;
tx;
}}""", '\n', '''
class Foo {{
toString()x;
toString()<caret>x;
}}'''
}
public void testBlockSelectionTab() {
doTestBlockSelection """
class Foo {{
<caret>tx;
tx;
}}""", '\t', '''
class Foo {{
toString();
toString()<caret>;
}}'''
}
public void testBlockSelectionBackspace() {
doTestBlockSelection """
class Foo {{
<caret>t;
t;
}}""", '\b\t', '''
class Foo {{
toString();
toString()<caret>;
}}'''
}
public void testMulticaret() {
doTestMulticaret """
class Foo {{
@@ -196,7 +196,8 @@
<applicationService serviceImplementation="com.intellij.application.options.editor.WebEditorOptions"/>
<applicationConfigurable groupId="editor" key="emmet.configuration.title" bundle="messages.XmlBundle" id="reference.idesettings.emmet" provider="com.intellij.application.options.emmet.EmmetConfigurableProvider"/>
<applicationConfigurable groupId="editor" key="emmet.configuration.title" bundle="messages.XmlBundle" id="reference.idesettings.emmet"
dynamic="true" provider="com.intellij.application.options.emmet.EmmetConfigurableProvider"/>
<applicationService serviceImplementation="com.intellij.application.options.emmet.EmmetOptions"/>
<applicationService serviceImplementation="com.intellij.application.options.editor.XmlFoldingSettings"/>
@@ -18,6 +18,7 @@
<generalCodeStyleOptionsProvider instance="org.editorconfig.settings.EditorConfigConfigurable"/>
<codeStyleSettingsProvider implementation="org.editorconfig.settings.EditorConfigConfigurable"/>
<fileIndentOptionsProvider implementation="org.editorconfig.configmanagement.EditorConfigIndentOptionsProvider" />
<editorNotificationProvider implementation="org.editorconfig.plugincomponents.EditorConfigNotifierProvider"/>
</extensions>
<application-components>
@@ -1,127 +0,0 @@
package org.editorconfig.annotations;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import icons.EditorconfigIcons;
import org.editorconfig.Utils;
import org.editorconfig.core.EditorConfig;
import org.editorconfig.plugincomponents.SettingsProviderComponent;
import org.editorconfig.settings.EditorConfigSettings;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.List;
/**
* @author Dennis.Ushakov
*/
public class EditorConfigAnnotator implements Annotator {
private static final String EDITOR_CONFIG_ACCEPTED = "editor.config.accepted";
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
PsiFile file = ObjectUtils.tryCast(element, PsiFile.class);
if (file == null || file.getVirtualFile() instanceof VirtualFileWindow) {
return;
}
final Project project = file.getProject();
final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings();
if (!Utils.isEnabled(settings) || PropertiesComponent.getInstance(project).getBoolean(EDITOR_CONFIG_ACCEPTED, false)) return;
final List<EditorConfig.OutPair> pairs = SettingsProviderComponent.getInstance().getOutPairs(project, Utils.getFilePath(project, file.getVirtualFile()));
if (!pairs.isEmpty()) {
final Annotation annotation = holder.createInfoAnnotation(file, "EditorConfig is overriding Code Style settings for this file");
annotation.setFileLevelAnnotation(true);
annotation.setGutterIconRenderer(new MyGutterIconRenderer());
annotation.registerFix(new IntentionAction() {
@NotNull
@Override
public String getText() {
return "Disable EditorConfig support";
}
@NotNull
@Override
public String getFamilyName() {
return "EditorConfig";
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
settings.getCustomSettings(EditorConfigSettings.class).ENABLED = false;
DaemonCodeAnalyzer.getInstance(project).restart();
}
@Override
public boolean startInWriteAction() {
return false;
}
});
annotation.registerFix(new IntentionAction() {
@NotNull
@Override
public String getText() {
return "Dismiss";
}
@NotNull
@Override
public String getFamilyName() {
return "EditorConfig";
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
PropertiesComponent.getInstance(project).setValue(EDITOR_CONFIG_ACCEPTED, "true");
DaemonCodeAnalyzer.getInstance(project).restart();
}
@Override
public boolean startInWriteAction() {
return false;
}
});
}
}
private static class MyGutterIconRenderer extends GutterIconRenderer {
@NotNull
@Override
public Icon getIcon() {
return EditorconfigIcons.Editorconfig;
}
@Override
public boolean equals(Object obj) {
return obj instanceof MyGutterIconRenderer;
}
@Override
public int hashCode() {
return EditorconfigIcons.Editorconfig.hashCode();
}
}
}
@@ -0,0 +1,70 @@
package org.editorconfig.plugincomponents;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.ui.EditorNotificationPanel;
import com.intellij.ui.EditorNotifications;
import com.intellij.ui.LightColors;
import icons.EditorconfigIcons;
import org.editorconfig.Utils;
import org.editorconfig.core.EditorConfig;
import org.editorconfig.settings.EditorConfigSettings;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.List;
/**
* @author Dennis.Ushakov
*/
public class EditorConfigNotifierProvider extends EditorNotifications.Provider<EditorNotificationPanel> {
private static final Key<EditorNotificationPanel> KEY = Key.create("editor.config.notification.panel");
private static final String EDITOR_CONFIG_ACCEPTED = "editor.config.accepted";
@NotNull
@Override
public Key<EditorNotificationPanel> getKey() {
return KEY;
}
@Override
public EditorNotificationPanel createNotificationPanel(@NotNull final VirtualFile file, @NotNull final FileEditor fileEditor) {
if (!(fileEditor instanceof TextEditor)) return null;
final Project project = ((TextEditor)fileEditor).getEditor().getProject();
final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings();
if (!Utils.isEnabled(settings) || PropertiesComponent.getInstance(project).getBoolean(EDITOR_CONFIG_ACCEPTED, false)) return null;
final List<EditorConfig.OutPair> pairs = SettingsProviderComponent.getInstance().getOutPairs(project, Utils.getFilePath(project, file));
if (!pairs.isEmpty()) {
final EditorNotificationPanel panel = new EditorNotificationPanel() {
@Override
public Color getBackground() {
return LightColors.GREEN;
}
}.text("EditorConfig is overriding Code Style settings for this file").
icon(EditorconfigIcons.Editorconfig);
panel.createActionLabel("Disable EditorConfig support", new Runnable() {
@Override
public void run() {
settings.getCustomSettings(EditorConfigSettings.class).ENABLED = false;
EditorNotifications.getInstance(project).updateAllNotifications();
}
});
panel.createActionLabel("Dismiss", new Runnable() {
@Override
public void run() {
PropertiesComponent.getInstance(project).setValue(EDITOR_CONFIG_ACCEPTED, "true");
EditorNotifications.getInstance(project).updateAllNotifications();
}
});
return panel;
}
return null;
}
}
@@ -1,12 +1,7 @@
package org.editorconfig.plugincomponents;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageAnnotators;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
@@ -18,7 +13,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import org.editorconfig.Utils;
import org.editorconfig.annotations.EditorConfigAnnotator;
import org.editorconfig.core.EditorConfig;
import org.editorconfig.core.EditorConfig.OutPair;
import org.editorconfig.core.EditorConfigException;
@@ -30,25 +24,8 @@ import java.util.*;
public class SettingsProviderComponent implements ApplicationComponent {
private EditorConfig editorConfig;
public SettingsProviderComponent(FileTypeManager manager) {
public SettingsProviderComponent() {
editorConfig = new EditorConfig();
registerAnnotator(manager);
}
public void registerAnnotator(FileTypeManager manager) {
final Set<String> languages = new HashSet<String>();
final EditorConfigAnnotator annotator = new EditorConfigAnnotator();
for (FileType type : manager.getRegisteredFileTypes()) {
if (type instanceof LanguageFileType) {
final Language lang = ((LanguageFileType)type).getLanguage();
final String id = lang.getID();
// don't add annotator for language twice
// don't add annotator for languages not having own annotators - they may rely on parent annotators
if (languages.contains(id) || (lang.getBaseLanguage() != null/* && LanguageAnnotators.INSTANCE.forKey(lang).isEmpty()*/)) continue;
LanguageAnnotators.INSTANCE.addExplicitExtension(lang, annotator);
languages.add(id);
}
}
}
public static SettingsProviderComponent getInstance() {
@@ -15,16 +15,13 @@
*/
package com.intellij.application.options.emmet;
import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGenerator;
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
import com.intellij.codeInsight.template.impl.TemplateExpandShortcutPanel;
import com.intellij.openapi.options.CompositeConfigurable;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -32,12 +29,21 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Collection;
import java.util.Collections;
public class EmmetCompositeConfigurable extends CompositeConfigurable<UnnamedConfigurable> implements SearchableConfigurable {
public class EmmetCompositeConfigurable extends SearchableConfigurable.Parent.Abstract {
private final Configurable[] myNestedConfigurables;
@NotNull private final Configurable[] myInnerConfigurables;
private TemplateExpandShortcutPanel myTemplateExpandShortcutPanel;
public EmmetCompositeConfigurable(@NotNull Configurable... innerConfigurables) {
this(Collections.<Configurable>emptyList(), innerConfigurables);
}
public EmmetCompositeConfigurable() {
public EmmetCompositeConfigurable(Collection<Configurable> nestedConfigurables, @NotNull Configurable... innerConfigurables) {
myNestedConfigurables = nestedConfigurables.toArray(new Configurable[nestedConfigurables.size()]);
myInnerConfigurables = innerConfigurables;
myTemplateExpandShortcutPanel = new TemplateExpandShortcutPanel(XmlBundle.message("emmet.expand.abbreviation.with"));
}
@@ -55,20 +61,19 @@ public class EmmetCompositeConfigurable extends CompositeConfigurable<UnnamedCon
@Nullable
@Override
public JComponent createComponent() {
final List<UnnamedConfigurable> configurables = getConfigurables();
final JPanel rootPanel = new JPanel(new GridLayoutManager(configurables.size() + 1, 1, new Insets(0, 0, 0, 0), -1, -1, false, false));
public JComponent createComponent() {
final JPanel rootPanel = new JPanel(new GridLayoutManager(myInnerConfigurables.length + 1, 1, new Insets(0, 0, 0, 0), -1, -1, false, false));
rootPanel.add(myTemplateExpandShortcutPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_NORTH,
GridConstraints.FILL_HORIZONTAL,
GridConstraints.SIZEPOLICY_CAN_GROW |
GridConstraints.SIZEPOLICY_CAN_SHRINK,
GridConstraints.SIZEPOLICY_FIXED, null, null, null));
for (int i = 0; i < configurables.size(); i++) {
UnnamedConfigurable configurable = configurables.get(i);
for (int i = 0; i < myInnerConfigurables.length; i++) {
UnnamedConfigurable configurable = myInnerConfigurables[i];
final JComponent component = configurable.createComponent();
assert component != null;
int vSizePolicy = GridConstraints.SIZEPOLICY_CAN_GROW | GridConstraints.SIZEPOLICY_CAN_SHRINK;
if (i + 1 == configurables.size()) {
if (i + 1 == myInnerConfigurables.length) {
vSizePolicy |= GridConstraints.SIZEPOLICY_WANT_GROW;
}
rootPanel.add(component, new GridConstraints(i + 1, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_BOTH,
@@ -82,21 +87,33 @@ public class EmmetCompositeConfigurable extends CompositeConfigurable<UnnamedCon
@Override
public void reset() {
final EmmetOptions emmetOptions = EmmetOptions.getInstance();
myTemplateExpandShortcutPanel.setSelectedChar((char)emmetOptions.getEmmetExpandShortcut());
myTemplateExpandShortcutPanel.setSelectedChar((char)EmmetOptions.getInstance().getEmmetExpandShortcut());
for (Configurable configurable : myInnerConfigurables) {
configurable.reset();
}
super.reset();
}
@Override
public void apply() throws ConfigurationException {
final EmmetOptions emmetOptions = EmmetOptions.getInstance();
emmetOptions.setEmmetExpandShortcut(myTemplateExpandShortcutPanel.getSelectedChar());
EmmetOptions.getInstance().setEmmetExpandShortcut(myTemplateExpandShortcutPanel.getSelectedChar());
for (Configurable configurable : myInnerConfigurables) {
configurable.reset();
}
super.apply();
}
@Override
public boolean isModified() {
return EmmetOptions.getInstance().getEmmetExpandShortcut() != myTemplateExpandShortcutPanel.getSelectedChar() || super.isModified();
if (EmmetOptions.getInstance().getEmmetExpandShortcut() != myTemplateExpandShortcutPanel.getSelectedChar() || super.isModified()) {
return true;
}
for (Configurable configurable : myInnerConfigurables) {
if (configurable.isModified()) {
return true;
}
}
return false;
}
@Override
@@ -105,30 +122,25 @@ public class EmmetCompositeConfigurable extends CompositeConfigurable<UnnamedCon
super.disposeUIResources();
}
@Override
protected List<UnnamedConfigurable> createConfigurables() {
List<UnnamedConfigurable> xmlConfigurables = ContainerUtil.newSmartList();
List<UnnamedConfigurable> configurables = ContainerUtil.newSmartList();
for (ZenCodingGenerator zenCodingGenerator : ZenCodingGenerator.getInstances()) {
if (zenCodingGenerator instanceof XmlZenCodingGenerator) {
ContainerUtil.addIfNotNull(xmlConfigurables, zenCodingGenerator.createConfigurable());
}
else {
ContainerUtil.addIfNotNull(configurables, zenCodingGenerator.createConfigurable());
}
}
return ContainerUtil.concat(xmlConfigurables, configurables);
}
@NotNull
@Override
public String getId() {
return "reference.idesettings.emmet";
}
@Override
public boolean hasOwnContent() {
return true;
}
@Nullable
@Override
public Runnable enableSearch(String option) {
return null;
}
@Override
protected Configurable[] buildConfigurables() {
return myNestedConfigurables;
}
}
@@ -15,18 +15,31 @@
*/
package com.intellij.application.options.emmet;
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurableProvider;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: zolotov
* Date: 2/20/13
*/
import java.util.List;
public class EmmetConfigurableProvider extends ConfigurableProvider {
@Nullable
@Override
public Configurable createConfigurable() {
return new EmmetCompositeConfigurable();
final List<Configurable> availableConfigurables = getAvailableConfigurables();
return availableConfigurables.size() == 1
? new EmmetCompositeConfigurable(ContainerUtil.getFirstItem(availableConfigurables))
: new EmmetCompositeConfigurable(availableConfigurables);
}
@NotNull
public static List<Configurable> getAvailableConfigurables() {
List<Configurable> configurables = ContainerUtil.newSmartList();
for (ZenCodingGenerator zenCodingGenerator : ZenCodingGenerator.getInstances()) {
ContainerUtil.addIfNotNull(configurables, zenCodingGenerator.createConfigurable());
}
return configurables;
}
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.application.options.emmet.XmlEmmetConfigurable">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="999" height="135"/>
@@ -8,59 +8,39 @@
<properties/>
<border type="none"/>
<children>
<grid id="369dc" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<component id="446a3" class="com.intellij.ui.components.JBCheckBox" binding="myEnableEmmetJBCheckBox" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/XmlBundle" key="emmet.enable.label"/>
</properties>
</component>
<component id="c52c1" class="com.intellij.ui.components.JBCheckBox" binding="myEnablePreviewJBCheckBox">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/XmlBundle" key="emmet.enable.preview"/>
</properties>
</component>
<grid id="cdbb7" binding="myFiltersListPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<clientProperties>
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
</clientProperties>
<border type="none" title="XML"/>
<children>
<component id="446a3" class="com.intellij.ui.components.JBCheckBox" binding="myEnableEmmetJBCheckBox" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/XmlBundle" key="emmet.enable.label"/>
</properties>
</component>
<component id="c52c1" class="com.intellij.ui.components.JBCheckBox" binding="myEnablePreviewJBCheckBox">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/XmlBundle" key="emmet.enable.preview"/>
</properties>
</component>
<grid id="cdbb7" binding="myFiltersListPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="3282c" class="com.intellij.ui.CheckBoxList" binding="myFiltersCheckBoxList">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
</children>
</grid>
<component id="d49b0" class="com.intellij.ui.components.JBCheckBox" binding="myEnableHrefAutodetectJBCheckBox">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/XmlBundle" key="emmet.href.autodetect"/>
</properties>
</component>
</children>
<border type="none"/>
<children/>
</grid>
<component id="d49b0" class="com.intellij.ui.components.JBCheckBox" binding="myEnableHrefAutodetectJBCheckBox">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/XmlBundle" key="emmet.href.autodetect"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -19,46 +19,59 @@ import com.intellij.codeInsight.template.emmet.filters.ZenCodingFilter;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.ui.CheckBoxList;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Configurable.NoScroll {
public class XmlEmmetConfigurable implements Configurable, Disposable, Configurable.NoScroll {
private JPanel myPanel;
private JBCheckBox myEnableEmmetJBCheckBox;
private JBCheckBox myEnablePreviewJBCheckBox;
private CheckBoxList<ZenCodingFilter> myFiltersCheckBoxList;
private JPanel myFiltersListPanel;
private JBCheckBox myEnableHrefAutodetectJBCheckBox;
private Map<String, JBCheckBox> myFilterCheckboxes = ContainerUtil.newHashMap();
public XmlEmmetConfigurable() {
myEnableEmmetJBCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
boolean selected = myEnableEmmetJBCheckBox.isSelected();
myEnablePreviewJBCheckBox.setEnabled(selected);
myFiltersCheckBoxList.setEnabled(selected);
myFiltersListPanel.setEnabled(selected);
myEnableHrefAutodetectJBCheckBox.setEnabled(selected);
}
});
myFiltersListPanel.setBorder(IdeBorderFactory.createTitledBorder(XmlBundle.message("emmet.filters.enabled.by.default"), false));
myFiltersCheckBoxList.setItems(ZenCodingFilter.getInstances(), new Function<ZenCodingFilter, String>() {
@Override
public String fun(ZenCodingFilter filter) {
return filter.getDisplayName();
}
});
myFiltersListPanel.setBorder(IdeBorderFactory.createTitledBorder(XmlBundle.message("emmet.filters.enabled.by.default")));
createFiltersCheckboxes();
}
public void createFiltersCheckboxes() {
final List<ZenCodingFilter> filters = ZenCodingFilter.getInstances();
final GridBagLayout layoutManager = new GridBagLayout();
final GridBagConstraints constraints = new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0);
myFiltersListPanel.setLayout(layoutManager);
for (int i = 0; i < filters.size(); i++) {
ZenCodingFilter filter = filters.get(i);
final JBCheckBox checkBox = new JBCheckBox(filter.getDisplayName());
myFilterCheckboxes.put(filter.getSuffix(), checkBox);
constraints.gridy = i;
myFiltersListPanel.add(checkBox, constraints);
}
myFiltersListPanel.revalidate();
}
@Override
@@ -101,7 +114,11 @@ public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Co
Set<String> enabledByDefault = emmetOptions.getFiltersEnabledByDefault();
for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
myFiltersCheckBoxList.setItemSelected(filter, enabledByDefault.contains(filter.getSuffix()));
final String filterSuffix = filter.getSuffix();
final JBCheckBox checkBox = myFilterCheckboxes.get(filterSuffix);
if (checkBox != null) {
checkBox.setSelected(enabledByDefault.contains(filterSuffix));
}
}
}
@@ -112,11 +129,23 @@ public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Co
@NotNull
private Set<String> enabledFilters() {
Set<String> result = ContainerUtil.newHashSet();
for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
if (myFiltersCheckBoxList.isItemSelected(filter)) {
result.add(filter.getSuffix());
for (Map.Entry<String, JBCheckBox> checkbox : myFilterCheckboxes.entrySet()) {
if (checkbox.getValue().isSelected()) {
result.add(checkbox.getKey());
}
}
return result;
}
@Nls
@Override
public String getDisplayName() {
return "XML";
}
@Nullable
@Override
public String getHelpTopic() {
return XmlBundle.message("emmet.configuration.title");
}
}
@@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.util.PsiTreeUtil;
@@ -170,32 +171,34 @@ public class EmmetUpdateTagAction extends BaseCodeInsightAction implements DumbA
@Override
protected void run(@NotNull Result<Void> result) throws Throwable {
if (tag.isValid()) {
tag.setAttribute(HtmlUtil.CLASS_ATTRIBUTE_NAME, StringUtil.join(classes, " ").trim());
if (!ReadonlyStatusHandler.getInstance(file.getProject()).ensureFilesWritable(file.getVirtualFile()).hasReadonlyFiles()) {
tag.setAttribute(HtmlUtil.CLASS_ATTRIBUTE_NAME, StringUtil.join(classes, " ").trim());
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
final String attributeName = attribute.getKey();
if (StringUtil.startsWithChar(attributeName, '+')) {
final XmlAttribute existingAttribute = tag.getAttribute(attributeName.substring(1));
if (existingAttribute != null) {
existingAttribute.setValue(StringUtil.notNullize(existingAttribute.getValue() + attribute.getValue()));
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
final String attributeName = attribute.getKey();
if (StringUtil.startsWithChar(attributeName, '+')) {
final XmlAttribute existingAttribute = tag.getAttribute(attributeName.substring(1));
if (existingAttribute != null) {
existingAttribute.setValue(StringUtil.notNullize(existingAttribute.getValue() + attribute.getValue()));
}
else {
tag.setAttribute(attributeName.substring(1), attribute.getValue());
}
}
else if (StringUtil.startsWithChar(attributeName, '-')) {
final XmlAttribute existingAttribute = tag.getAttribute(attributeName.substring(1));
if (existingAttribute != null) {
existingAttribute.delete();
}
}
else {
tag.setAttribute(attributeName.substring(1), attribute.getValue());
tag.setAttribute(attributeName, attribute.getValue());
}
}
else if (StringUtil.startsWithChar(attributeName, '-')) {
final XmlAttribute existingAttribute = tag.getAttribute(attributeName.substring(1));
if (existingAttribute != null) {
existingAttribute.delete();
}
}
else {
tag.setAttribute(attributeName, attribute.getValue());
}
}
if (newTagName != null) {
tag.setName(newTagName);
if (newTagName != null) {
tag.setName(newTagName);
}
}
}
}
@@ -16,17 +16,20 @@
package com.intellij.codeInsight.template.emmet.completion;
import com.intellij.application.options.emmet.EmmetCompositeConfigurable;
import com.intellij.application.options.emmet.EmmetOptions;
import com.intellij.application.options.emmet.XmlEmmetConfigurable;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupActionProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementAction;
import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.util.Consumer;
import com.intellij.util.PlatformIcons;
@@ -35,36 +38,44 @@ public class EmmetLookupActionProvider implements LookupActionProvider {
public void fillActions(LookupElement element, final Lookup lookup, Consumer<LookupElementAction> consumer) {
if (element instanceof CustomLiveTemplateLookupElement &&
((CustomLiveTemplateLookupElement)element).getCustomLiveTemplate() instanceof ZenCodingTemplate) {
consumer.consume(new LookupElementAction(PlatformIcons.EDIT, "Edit Emmet settings") {
@Override
public Result performLookupAction() {
final Project project = lookup.getEditor().getProject();
assert project != null;
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (project.isDisposed()) return;
final EmmetCompositeConfigurable configurable = new EmmetCompositeConfigurable();
ShowSettingsUtil.getInstance().editConfigurable(project, configurable);
}
});
return Result.HIDE_LOOKUP;
}
});
final PsiElement context = lookup.getPsiElement();
final ZenCodingGenerator generator = context != null ? ZenCodingTemplate.findApplicableDefaultGenerator(context, false) : null;
if (generator != null) {
consumer.consume(new LookupElementAction(PlatformIcons.EDIT, "Edit Emmet settings") {
@Override
public Result performLookupAction() {
final Project project = lookup.getEditor().getProject();
assert project != null;
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (project.isDisposed()) return;
consumer.consume(new LookupElementAction(AllIcons.Actions.Delete, String.format("Disable Emmet")) {
@Override
public Result performLookupAction() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
EmmetOptions.getInstance().setEmmetEnabled(false);
}
});
return Result.HIDE_LOOKUP;
}
});
final Configurable generatorSpecificConfigurable = generator.createConfigurable();
EmmetCompositeConfigurable configurable = generatorSpecificConfigurable != null
? new EmmetCompositeConfigurable(generatorSpecificConfigurable)
: new EmmetCompositeConfigurable(new XmlEmmetConfigurable());
ShowSettingsUtil.getInstance().editConfigurable(project, configurable);
}
});
return Result.HIDE_LOOKUP;
}
});
consumer.consume(new LookupElementAction(AllIcons.Actions.Delete, "Disable Emmet") {
@Override
public Result performLookupAction() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
generator.disableEmmet();
}
});
return Result.HIDE_LOOKUP;
}
});
}
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.template.emmet.generators;
import com.intellij.application.options.emmet.EmmetOptions;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
@@ -118,4 +119,9 @@ public abstract class XmlZenCodingGenerator extends ZenCodingGenerator {
String key = computeKey(documentText.subSequence(startOffset, currentOffset));
return !StringUtil.isEmpty(key) && ZenCodingTemplate.checkTemplateKey(key, callback, this) ? key : null;
}
@Override
public void disableEmmet() {
EmmetOptions.getInstance().setEmmetEnabled(false);
}
}
@@ -27,7 +27,7 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -154,7 +154,7 @@ public class XmlZenCodingGeneratorImpl extends XmlZenCodingGenerator {
@Nullable
@Override
public UnnamedConfigurable createConfigurable() {
public Configurable createConfigurable() {
return new XmlEmmetConfigurable();
}
}
@@ -24,7 +24,7 @@ import com.intellij.codeInsight.template.emmet.tokens.ZenCodingToken;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
@@ -140,11 +140,14 @@ public abstract class ZenCodingGenerator {
}
@Nullable
public UnnamedConfigurable createConfigurable() {
public Configurable createConfigurable() {
return null;
}
public boolean hasCompletionItem() {
return false;
}
public void disableEmmet() {
}
}
@@ -28,6 +28,7 @@ import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGeneratorI
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.ide.highlighter.HtmlFileType;
import com.intellij.injected.editor.DocumentWindowImpl;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.command.undo.UndoConstants;
@@ -281,7 +282,7 @@ public class GenerationNode extends UserDataHolderBase {
final XmlFile xmlFile = token.getFile();
PsiFileFactory fileFactory = PsiFileFactory.getInstance(xmlFile.getProject());
XmlFile dummyFile = (XmlFile)fileFactory.createFileFromText("dummy.html", StdFileTypes.HTML, xmlFile.getText());
XmlFile dummyFile = (XmlFile)fileFactory.createFileFromText("dummy.html", HtmlFileType.INSTANCE, xmlFile.getText());
final XmlTag tag = dummyFile.getRootTag();
if (tag != null) {
@@ -307,7 +308,7 @@ public class GenerationNode extends UserDataHolderBase {
}
XmlTag tag1 = hasChildren ? expandEmptyTagIfNecessary(tag) : tag;
setAttributeValues(tag1, attributes, callback);
XmlFile physicalFile = (XmlFile)fileFactory.createFileFromText("dummy.html", StdFileTypes.HTML, tag1.getContainingFile().getText(),
XmlFile physicalFile = (XmlFile)fileFactory.createFileFromText("dummy.html", HtmlFileType.INSTANCE, tag1.getContainingFile().getText(),
LocalTimeCounter.currentTime(), true);
VirtualFile vFile = physicalFile.getVirtualFile();
if (vFile != null) {
@@ -18,6 +18,7 @@ package com.intellij.codeInsight.template.emmet.tokens;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.emmet.XmlEmmetParser;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.ide.highlighter.HtmlFileType;
import com.intellij.openapi.command.undo.UndoConstants;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.vfs.VirtualFile;
@@ -99,7 +100,7 @@ public class TemplateToken extends ZenCodingToken {
String templateString = template.getString();
final PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(callback.getProject());
if (!containsAttrsVar(template)) {
XmlFile dummyFile = (XmlFile)psiFileFactory.createFileFromText("dummy.xml", StdFileTypes.HTML, templateString);
XmlFile dummyFile = (XmlFile)psiFileFactory.createFileFromText("dummy.xml", HtmlFileType.INSTANCE, templateString);
dummyRootTag = dummyFile.getRootTag();
if (dummyRootTag != null) {
addMissingAttributes(dummyRootTag, attributes);