mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
WEB-20704 Emmet: allow to configure bem separators
This commit is contained in:
@@ -230,10 +230,14 @@ emmet.update.tag.title=Update tag with Emmet
|
||||
emmet.configuration.title=Emmet
|
||||
emmet.enable.label=&Enable XML/HTML Emmet
|
||||
emmet.filters.enabled.by.default=Filters enabled by default
|
||||
emmet.bem.title=BEM
|
||||
emmet.enable.preview=Enable &abbreviation preview
|
||||
emmet.expand.abbreviation.with=Expand &abbreviation with
|
||||
emmet.href.autodetect=Enable automatic &URL recognition while wrapping text with <a> tag
|
||||
emmet.add.edit.point.at.the.end.of.template=Add edit &point at the end of template
|
||||
emmet.bem.class.name.element.separator.label=Class name's element separator:
|
||||
emmet.bem.class.name.modifier.separator.label=Class name's modifier separator:
|
||||
emmet.bem.short.element.prefix.label=Short element prefix:
|
||||
|
||||
title.cannot.create.html.file=Cannot create HTML file
|
||||
new.html.file.action=HTML File
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -36,10 +37,15 @@ public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
private boolean myEmmetEnabled = true;
|
||||
private int myEmmetExpandShortcut = TemplateSettings.TAB_CHAR;
|
||||
private boolean myPreviewEnabled = false;
|
||||
@NotNull
|
||||
private Set<String> myFiltersEnabledByDefault = ContainerUtil.newHashSet();
|
||||
private boolean myHrefAutoDetectEnabled = true;
|
||||
private boolean myAddEditPointAtTheEndOfTemplate = false;
|
||||
|
||||
@NotNull private String myBemElementSeparator = "__";
|
||||
@NotNull private String myBemModifierSeparator = "_";
|
||||
@NotNull private String myBemShortElementPrefix = "-";
|
||||
|
||||
@NotNull
|
||||
public Set<String> getFiltersEnabledByDefault() {
|
||||
return myFiltersEnabledByDefault;
|
||||
@@ -76,7 +82,7 @@ public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
public void setEmmetEnabled(boolean emmetEnabled) {
|
||||
myEmmetEnabled = emmetEnabled;
|
||||
}
|
||||
|
||||
|
||||
public void setHrefAutoDetectEnabled(boolean hrefAutoDetectEnabled) {
|
||||
myHrefAutoDetectEnabled = hrefAutoDetectEnabled;
|
||||
}
|
||||
@@ -93,6 +99,33 @@ public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
myAddEditPointAtTheEndOfTemplate = addEditPointAtTheEndOfTemplate;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getBemElementSeparator() {
|
||||
return myBemElementSeparator;
|
||||
}
|
||||
|
||||
public void setBemElementSeparator(@Nullable String bemElementSeparator) {
|
||||
myBemElementSeparator = StringUtil.notNullize(bemElementSeparator);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getBemModifierSeparator() {
|
||||
return myBemModifierSeparator;
|
||||
}
|
||||
|
||||
public void setBemModifierSeparator(@Nullable String bemModifierSeparator) {
|
||||
myBemModifierSeparator = StringUtil.notNullize(bemModifierSeparator);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getBemShortElementPrefix() {
|
||||
return myBemShortElementPrefix;
|
||||
}
|
||||
|
||||
public void setBemShortElementPrefix(@Nullable String bemShortElementPrefix) {
|
||||
myBemShortElementPrefix = StringUtil.notNullize(bemShortElementPrefix);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EmmetOptions getState() {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?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="5" 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="6" 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="140"/>
|
||||
<xy x="20" y="20" width="1797" height="282"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
@@ -27,7 +27,7 @@
|
||||
<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="4" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="5" 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"/>
|
||||
@@ -49,6 +49,74 @@
|
||||
<text resource-bundle="messages/XmlBundle" key="emmet.add.edit.point.at.the.end.of.template"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="fb640" binding="myBemPanel" layout-manager="GridLayoutManager" row-count="4" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="4" 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/>
|
||||
<border type="none" title="BEM"/>
|
||||
<children>
|
||||
<component id="48744" class="com.intellij.ui.components.JBLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/XmlBundle" key="emmet.bem.class.name.element.separator.label"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="2356c">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<vspacer id="4ace0">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="3083" class="com.intellij.ui.components.JBLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/XmlBundle" key="emmet.bem.class.name.modifier.separator.label"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="9b3ce" class="com.intellij.ui.components.JBLabel">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/XmlBundle" key="emmet.bem.short.element.prefix.label"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="525" class="com.intellij.ui.components.JBTextField" binding="myBemElementSeparatorTextField">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="50" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="fddbf" class="com.intellij.ui.components.JBTextField" binding="myBemModifierSeparatorTextField">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="50" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="2659b" class="com.intellij.ui.components.JBTextField" binding="myBemShortElementPrefixTextField">
|
||||
<constraints>
|
||||
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="50" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -23,7 +23,10 @@ import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.xml.XmlBundle;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -44,6 +47,10 @@ public class XmlEmmetConfigurable implements SearchableConfigurable, Disposable,
|
||||
private JPanel myFiltersListPanel;
|
||||
private JBCheckBox myEnableHrefAutodetectJBCheckBox;
|
||||
private JBCheckBox myAddEditPointAtTheEndOfTemplateJBCheckBox;
|
||||
private JBTextField myBemElementSeparatorTextField;
|
||||
private JBTextField myBemModifierSeparatorTextField;
|
||||
private JBTextField myBemShortElementPrefixTextField;
|
||||
private JPanel myBemPanel;
|
||||
|
||||
private Map<String, JBCheckBox> myFilterCheckboxes = ContainerUtil.newHashMap();
|
||||
|
||||
@@ -53,23 +60,26 @@ public class XmlEmmetConfigurable implements SearchableConfigurable, Disposable,
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
boolean selected = myEnableEmmetJBCheckBox.isSelected();
|
||||
myEnablePreviewJBCheckBox.setEnabled(selected);
|
||||
myAddEditPointAtTheEndOfTemplateJBCheckBox.setEnabled(selected);
|
||||
myFiltersListPanel.setEnabled(selected);
|
||||
myEnableHrefAutodetectJBCheckBox.setEnabled(selected);
|
||||
myAddEditPointAtTheEndOfTemplateJBCheckBox.setEnabled(selected);
|
||||
UIUtil.setEnabled(myBemPanel, selected, true);
|
||||
for (JBCheckBox checkBox : myFilterCheckboxes.values()) {
|
||||
checkBox.setEnabled(selected);
|
||||
}
|
||||
}
|
||||
});
|
||||
myFiltersListPanel.setBorder(IdeBorderFactory.createTitledBorder(XmlBundle.message("emmet.filters.enabled.by.default")));
|
||||
myBemPanel.setBorder(IdeBorderFactory.createTitledBorder(XmlBundle.message("emmet.bem.title")));
|
||||
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);
|
||||
final GridBagConstraints constraints = new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
|
||||
JBUI.emptyInsets(), 0, 0);
|
||||
myFiltersListPanel.setLayout(layoutManager);
|
||||
for (int i = 0; i < filters.size(); i++) {
|
||||
ZenCodingFilter filter = filters.get(i);
|
||||
@@ -100,7 +110,10 @@ public class XmlEmmetConfigurable implements SearchableConfigurable, Disposable,
|
||||
emmetOptions.isPreviewEnabled() != myEnablePreviewJBCheckBox.isSelected() ||
|
||||
emmetOptions.isHrefAutoDetectEnabled() != myEnableHrefAutodetectJBCheckBox.isSelected() ||
|
||||
emmetOptions.isAddEditPointAtTheEndOfTemplate() != myAddEditPointAtTheEndOfTemplateJBCheckBox.isSelected() ||
|
||||
!emmetOptions.getFiltersEnabledByDefault().equals(enabledFilters());
|
||||
!emmetOptions.getFiltersEnabledByDefault().equals(enabledFilters()) ||
|
||||
!emmetOptions.getBemElementSeparator().equals(myBemElementSeparatorTextField.getText()) ||
|
||||
!emmetOptions.getBemModifierSeparator().equals(myBemModifierSeparatorTextField.getText()) ||
|
||||
!emmetOptions.getBemShortElementPrefix().equals(myBemShortElementPrefixTextField.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,9 +124,11 @@ public class XmlEmmetConfigurable implements SearchableConfigurable, Disposable,
|
||||
emmetOptions.setHrefAutoDetectEnabled(myEnableHrefAutodetectJBCheckBox.isSelected());
|
||||
emmetOptions.setAddEditPointAtTheEndOfTemplate(myAddEditPointAtTheEndOfTemplateJBCheckBox.isSelected());
|
||||
emmetOptions.setFiltersEnabledByDefault(enabledFilters());
|
||||
emmetOptions.setBemElementSeparator(myBemElementSeparatorTextField.getText());
|
||||
emmetOptions.setBemModifierSeparator(myBemModifierSeparatorTextField.getText());
|
||||
emmetOptions.setBemShortElementPrefix(myBemShortElementPrefixTextField.getText());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
EmmetOptions emmetOptions = EmmetOptions.getInstance();
|
||||
@@ -124,6 +139,10 @@ public class XmlEmmetConfigurable implements SearchableConfigurable, Disposable,
|
||||
myEnableHrefAutodetectJBCheckBox.setSelected(emmetOptions.isHrefAutoDetectEnabled());
|
||||
myAddEditPointAtTheEndOfTemplateJBCheckBox.setEnabled(emmetOptions.isEmmetEnabled());
|
||||
myAddEditPointAtTheEndOfTemplateJBCheckBox.setSelected(emmetOptions.isAddEditPointAtTheEndOfTemplate());
|
||||
|
||||
myBemElementSeparatorTextField.setText(emmetOptions.getBemElementSeparator());
|
||||
myBemModifierSeparatorTextField.setText(emmetOptions.getBemModifierSeparator());
|
||||
myBemShortElementPrefixTextField.setText(emmetOptions.getBemShortElementPrefix());
|
||||
|
||||
Set<String> enabledByDefault = emmetOptions.getFiltersEnabledByDefault();
|
||||
for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
|
||||
|
||||
@@ -15,77 +15,32 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.template.emmet.filters;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.intellij.application.options.emmet.EmmetOptions;
|
||||
import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
|
||||
import com.intellij.lang.xml.XMLLanguage;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.collect.Iterables.*;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Lists.newLinkedList;
|
||||
|
||||
/**
|
||||
* Bem filter for emmet support.
|
||||
* See the original source code here: https://github.com/emmetio/emmet/blob/master/javascript/filters/bem.js
|
||||
* And documentation here: http://docs.emmet.io/filters/bem/
|
||||
*/
|
||||
public class BemEmmetFilter extends ZenCodingFilter {
|
||||
public static final String SUFFIX = "bem";
|
||||
|
||||
private static final String SUFFIX = "bem";
|
||||
private static final Key<BemState> BEM_STATE = Key.create("BEM_STATE");
|
||||
|
||||
private static final String ELEMENT_SEPARATOR = "__";
|
||||
private static final String MODIFIER_SEPARATOR = "_";
|
||||
private static final String SHORT_ELEMENT_PREFIX = "-";
|
||||
|
||||
private static final Joiner ELEMENTS_JOINER = Joiner.on(ELEMENT_SEPARATOR).skipNulls();
|
||||
private static final Splitter ELEMENTS_SPLITTER = Splitter.on(ELEMENT_SEPARATOR);
|
||||
private static final Splitter MODIFIERS_SPLITTER = Splitter.on(MODIFIER_SEPARATOR).limit(2);
|
||||
private static final Splitter CLASS_NAME_SPLITTER = Splitter.on(' ').trimResults().omitEmptyStrings();
|
||||
private static final Joiner CLASS_NAME_JOINER = Joiner.on(' ');
|
||||
|
||||
private static final Function<String, String> CLASS_NAME_NORMALIZER = new Function<String, String>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String apply(@NotNull String input) {
|
||||
if (!input.startsWith(SHORT_ELEMENT_PREFIX)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
while (input.startsWith(SHORT_ELEMENT_PREFIX)) {
|
||||
input = input.substring(SHORT_ELEMENT_PREFIX.length());
|
||||
result.append(ELEMENT_SEPARATOR);
|
||||
}
|
||||
return result.append(input).toString();
|
||||
}
|
||||
};
|
||||
|
||||
private static final Predicate<String> BLOCK_NAME_PREDICATE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String className) {
|
||||
return Pattern.compile("^[A-z]-").matcher(className).matches();
|
||||
}
|
||||
};
|
||||
private static final Predicate<String> STARTS_WITH_LETTER = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable String input) {
|
||||
return input != null && input.length() > 0 && Character.isLetter(input.charAt(0));
|
||||
}
|
||||
};
|
||||
private static final Pattern BLOCK_NAME_PATTERN = Pattern.compile("^[A-z]-");
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -109,30 +64,37 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
public GenerationNode filterNode(@NotNull final GenerationNode node) {
|
||||
final Map<String, String> attributes = node.getTemplateToken().getAttributes();
|
||||
String classValue = attributes.get(HtmlUtil.CLASS_ATTRIBUTE_NAME);
|
||||
if (classValue != null) {
|
||||
Iterable<String> classNames = extractClasses(classValue);
|
||||
EmmetOptions emmetOptions = EmmetOptions.getInstance();
|
||||
if (classValue != null && emmetOptions != null) {
|
||||
String elementSeparator = emmetOptions.getBemElementSeparator();
|
||||
String modifierSeparator = emmetOptions.getBemModifierSeparator();
|
||||
String shortElementPrefix = emmetOptions.getBemShortElementPrefix();
|
||||
|
||||
List<String> classNames = ContainerUtil.map(HtmlUtil.splitClassNames(classValue), (s) -> {
|
||||
return normalizeClassName(s, elementSeparator, shortElementPrefix);
|
||||
});
|
||||
|
||||
BEM_STATE.set(node, new BemState(suggestBlockName(classNames), null, null));
|
||||
final Set<String> newClassNames = ImmutableSet.copyOf(concat(transform(classNames, new Function<String, Iterable<String>>() {
|
||||
@Override
|
||||
public Iterable<String> apply(String className) {
|
||||
return processClassName(className, node);
|
||||
}
|
||||
})));
|
||||
attributes.put(HtmlUtil.CLASS_ATTRIBUTE_NAME, CLASS_NAME_JOINER.join(newClassNames));
|
||||
Set<String> newClassNames = ContainerUtil.newLinkedHashSet();
|
||||
for (String className : classNames) {
|
||||
ContainerUtil.addAll(newClassNames, processClassName(className, node, elementSeparator, modifierSeparator));
|
||||
}
|
||||
attributes.put(HtmlUtil.CLASS_ATTRIBUTE_NAME, StringUtil.join(newClassNames, " "));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private static Iterable<String> processClassName(String className, @NotNull GenerationNode node) {
|
||||
className = fillWithBemElements(className, node);
|
||||
className = fillWithBemModifiers(className, node);
|
||||
private static Iterable<String> processClassName(@NotNull String className, @NotNull GenerationNode node,
|
||||
@NotNull String elementSeparator, @NotNull String modifierSeparator) {
|
||||
className = fillWithBemElements(className, node, elementSeparator);
|
||||
className = fillWithBemModifiers(className, node, modifierSeparator);
|
||||
|
||||
BemState nodeBemState = BEM_STATE.get(node);
|
||||
BemState bemState = extractBemStateFromClassName(className);
|
||||
List<String> result = newLinkedList();
|
||||
BemState bemState = extractBemStateFromClassName(className, elementSeparator, modifierSeparator);
|
||||
List<String> result = ContainerUtil.newArrayList();
|
||||
if (!bemState.isEmpty()) {
|
||||
String nodeBlockValue = nodeBemState != null ? nodeBemState.getBlock() : null;
|
||||
|
||||
|
||||
String block = bemState.getBlock();
|
||||
if (StringUtil.isEmpty(block)) {
|
||||
block = StringUtil.notNullize(nodeBlockValue);
|
||||
@@ -141,18 +103,18 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
String prefix = block;
|
||||
String element = bemState.getElement();
|
||||
if (StringUtil.isNotEmpty(element)) {
|
||||
prefix += ELEMENT_SEPARATOR + element;
|
||||
prefix += elementSeparator + element;
|
||||
}
|
||||
result.add(prefix);
|
||||
String modifier = bemState.getModifier();
|
||||
if (StringUtil.isNotEmpty(modifier)) {
|
||||
result.add(prefix + MODIFIER_SEPARATOR + modifier);
|
||||
result.add(prefix + modifierSeparator + modifier);
|
||||
}
|
||||
|
||||
|
||||
BemState newNodeBemState = bemState.copy();
|
||||
if (StringUtil.isNotEmpty(nodeBlockValue) && StringUtil.isEmpty(modifier)) {
|
||||
// save old value
|
||||
newNodeBemState.setBlock(nodeBlockValue);
|
||||
newNodeBemState.setBlock(nodeBlockValue);
|
||||
}
|
||||
BEM_STATE.set(node, newNodeBemState);
|
||||
}
|
||||
@@ -163,56 +125,54 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static BemState extractBemStateFromClassName(@NotNull String className) {
|
||||
private static BemState extractBemStateFromClassName(@NotNull String className, String elementSeparator, String modifierSeparator) {
|
||||
final BemState result = new BemState();
|
||||
if (className.contains(ELEMENT_SEPARATOR)) {
|
||||
final Iterator<String> elementsIterator = ELEMENTS_SPLITTER.split(className).iterator();
|
||||
result.setBlock(elementsIterator.next());
|
||||
int indexOfElementSeparator = className.indexOf(elementSeparator);
|
||||
if (indexOfElementSeparator >= 0) {
|
||||
result.setBlock(className.substring(0, indexOfElementSeparator));
|
||||
result.setElement(className.substring(indexOfElementSeparator + elementSeparator.length()));
|
||||
|
||||
final Collection<String> elementParts = newLinkedList();
|
||||
while (elementsIterator.hasNext()) {
|
||||
final String elementPart = elementsIterator.next();
|
||||
if (!elementsIterator.hasNext()) {
|
||||
final List<String> elementModifiers = newArrayList(MODIFIERS_SPLITTER.split(elementPart));
|
||||
elementParts.add(getFirst(elementModifiers, null));
|
||||
if (elementModifiers.size() > 1) {
|
||||
result.setModifier(getLast(elementModifiers, ""));
|
||||
}
|
||||
}
|
||||
else {
|
||||
elementParts.add(elementPart);
|
||||
}
|
||||
int lastIndexOfElementSeparator = className.lastIndexOf(elementSeparator);
|
||||
assert lastIndexOfElementSeparator >= 0;
|
||||
int indexOfModifierSeparator = className.indexOf(modifierSeparator, lastIndexOfElementSeparator + elementSeparator.length());
|
||||
if (indexOfModifierSeparator >= 0) {
|
||||
result.setModifier(className.substring(indexOfModifierSeparator + modifierSeparator.length()));
|
||||
result.setElement(className.substring(indexOfElementSeparator + elementSeparator.length(), indexOfModifierSeparator));
|
||||
}
|
||||
result.setElement(ELEMENTS_JOINER.join(elementParts));
|
||||
}
|
||||
else if (className.contains(MODIFIER_SEPARATOR)) {
|
||||
final Iterable<String> blockModifiers = MODIFIERS_SPLITTER.split(className);
|
||||
result.setBlock(getFirst(blockModifiers, ""));
|
||||
result.setModifier(getLast(blockModifiers, ""));
|
||||
else {
|
||||
int indexOfModifierSeparator = className.indexOf(modifierSeparator);
|
||||
if (indexOfModifierSeparator >= 0) {
|
||||
result.setBlock(className.substring(0, indexOfModifierSeparator));
|
||||
result.setModifier(className.substring(indexOfModifierSeparator + modifierSeparator.length()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String fillWithBemElements(@NotNull String className, @NotNull GenerationNode node) {
|
||||
return transformClassNameToBemFormat(className, ELEMENT_SEPARATOR, node);
|
||||
private static String fillWithBemElements(@NotNull String className, @NotNull GenerationNode node, @NotNull String separator) {
|
||||
return transformClassNameToBemFormat(className, separator, node, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String fillWithBemModifiers(@NotNull String className, @NotNull GenerationNode node) {
|
||||
return transformClassNameToBemFormat(className, MODIFIER_SEPARATOR, node);
|
||||
private static String fillWithBemModifiers(@NotNull String className, @NotNull GenerationNode node, @NotNull String separator) {
|
||||
return transformClassNameToBemFormat(className, separator, node, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adduction className to BEM format according to tags structure.
|
||||
* Adjusting className to BEM format according to tags structure.
|
||||
*
|
||||
* @param className
|
||||
* @param separator handling separator
|
||||
* @param node current node
|
||||
* @param separator handling separator
|
||||
* @param node current node
|
||||
* @param isModifierSeparator whether we're trying to handle modifier
|
||||
* @return class name in BEM format
|
||||
*/
|
||||
@NotNull
|
||||
private static String transformClassNameToBemFormat(@NotNull String className, @NotNull String separator, @NotNull GenerationNode node) {
|
||||
private static String transformClassNameToBemFormat(@NotNull String className, @NotNull String separator,
|
||||
@NotNull GenerationNode node, boolean isModifierSeparator) {
|
||||
Pair<String, Integer> cleanStringAndDepth = getCleanStringAndDepth(className, separator);
|
||||
Integer depth = cleanStringAndDepth.second;
|
||||
if (depth > 0) {
|
||||
@@ -227,7 +187,7 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
String prefix = bemState.getBlock();
|
||||
if (!StringUtil.isEmpty(prefix)) {
|
||||
String element = bemState.getElement();
|
||||
if (MODIFIER_SEPARATOR.equals(separator) && !StringUtil.isEmpty(element)) {
|
||||
if (isModifierSeparator && !StringUtil.isEmpty(element)) {
|
||||
prefix = prefix + separator + element;
|
||||
}
|
||||
return prefix + separator + cleanStringAndDepth.first;
|
||||
@@ -247,24 +207,13 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
@NotNull
|
||||
private static Pair<String, Integer> getCleanStringAndDepth(@NotNull String name, @NotNull String separator) {
|
||||
int result = 0;
|
||||
while (name.startsWith(separator)) {
|
||||
while (!separator.isEmpty() && name.startsWith(separator)) {
|
||||
result++;
|
||||
name = name.substring(separator.length());
|
||||
}
|
||||
return Pair.create(name, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all normalized class names from class attribute value
|
||||
*
|
||||
* @param classAttributeValue
|
||||
* @return collection of normalized class names
|
||||
*/
|
||||
@NotNull
|
||||
private static Iterable<String> extractClasses(String classAttributeValue) {
|
||||
return transform(CLASS_NAME_SPLITTER.split(classAttributeValue), CLASS_NAME_NORMALIZER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest block name by class names.
|
||||
* Returns first class started with pattern [a-z]-
|
||||
@@ -275,7 +224,27 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
*/
|
||||
@NotNull
|
||||
private static String suggestBlockName(Iterable<String> classNames) {
|
||||
return find(classNames, BLOCK_NAME_PREDICATE, find(classNames, STARTS_WITH_LETTER, ""));
|
||||
String result = ContainerUtil.find(classNames, className -> BLOCK_NAME_PATTERN.matcher(className).matches());
|
||||
if (result == null) {
|
||||
result = ContainerUtil.find(classNames, s -> s != null && !s.isEmpty() && Character.isLetter(s.charAt(0)));
|
||||
}
|
||||
return StringUtil.notNullize(result);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String normalizeClassName(@NotNull String className,
|
||||
@NotNull String elementSeparator,
|
||||
@NotNull String shortElementPrefix) {
|
||||
if (shortElementPrefix.isEmpty() || !className.startsWith(shortElementPrefix)) {
|
||||
return className;
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
while (className.startsWith(shortElementPrefix)) {
|
||||
className = className.substring(shortElementPrefix.length());
|
||||
result.append(elementSeparator);
|
||||
}
|
||||
return result.append(className).toString();
|
||||
}
|
||||
|
||||
private static class BemState {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -694,4 +694,9 @@ public class HtmlUtil {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static Iterable<String> splitClassNames(@NotNull String classAttributeValue) {
|
||||
// comma is useduse as separator because class name cannot contain comma but it can be part of JSF classes attributes
|
||||
return StringUtil.tokenize(classAttributeValue, " \t,");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user