mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
refactoring, extract zen-coding filter EP
This commit is contained in:
+3
-2
@@ -61,7 +61,7 @@ public class CustomTemplateCallback {
|
||||
fixInitialState();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
public PsiElement getContext() {
|
||||
return getContext(myFile, myStartOffset > 0 ? myStartOffset - 1 : myStartOffset);
|
||||
}
|
||||
@@ -231,7 +231,8 @@ public class CustomTemplateCallback {
|
||||
myEditor.getDocument().deleteString(caretAt - key.length(), caretAt);
|
||||
}
|
||||
|
||||
public static PsiElement getContext(PsiFile file, int offset) {
|
||||
@NotNull
|
||||
public static PsiElement getContext(@NotNull PsiFile file, int offset) {
|
||||
PsiElement element = null;
|
||||
if (!InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) {
|
||||
element = InjectedLanguageUtil.findInjectedElementNoCommit(file, offset);
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
<extensionPoint name="xml.implicitNamespaceDescriptorProvider"
|
||||
interface="com.intellij.javaee.ImplicitNamespaceDescriptorProvider"/>
|
||||
|
||||
<extensionPoint name="xml.zenCodingFilter" interface="com.intellij.codeInsight.template.zencoding.ZenCodingFilter"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
+31
-80
@@ -17,22 +17,18 @@ package com.intellij.codeInsight.template.zencoding;
|
||||
|
||||
import com.intellij.codeInsight.template.CustomTemplateCallback;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.psi.xml.XmlToken;
|
||||
import com.intellij.psi.xml.XmlTokenType;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
@@ -43,7 +39,6 @@ import java.util.*;
|
||||
class XmlZenCodingInterpreter {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.zencoding.XmlZenCodingInterpreter");
|
||||
private static final String ATTRS = "ATTRS";
|
||||
private static final String NUMBER_IN_ITERATION_PLACE_HOLDER = "$";
|
||||
|
||||
private final List<Token> myTokens;
|
||||
|
||||
@@ -269,8 +264,11 @@ class XmlZenCodingInterpreter {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Map<String, String> buildPredefinedValues(List<Pair<String, String>> attribute2value, int numberInIteration) {
|
||||
String attributes = buildAttributesString(attribute2value, numberInIteration);
|
||||
private static Map<String, String> buildPredefinedValues(List<Pair<String, String>> attribute2value,
|
||||
int numberInIteration,
|
||||
CustomTemplateCallback callback) {
|
||||
String attributes = buildAttributesString(attribute2value, numberInIteration, callback);
|
||||
assert attributes != null;
|
||||
attributes = attributes.length() > 0 ? ' ' + attributes : null;
|
||||
Map<String, String> predefinedValues = null;
|
||||
if (attributes != null) {
|
||||
@@ -280,28 +278,19 @@ class XmlZenCodingInterpreter {
|
||||
return predefinedValues;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String buildAttributesString(List<Pair<String, String>> attribute2value, int numberInIteration) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Iterator<Pair<String, String>> it = attribute2value.iterator(); it.hasNext();) {
|
||||
Pair<String, String> pair = it.next();
|
||||
String name = pair.first;
|
||||
String value = getValue(pair, numberInIteration);
|
||||
result.append(getAttributeString(name, value));
|
||||
if (it.hasNext()) {
|
||||
result.append(' ');
|
||||
@Nullable
|
||||
private static String buildAttributesString(List<Pair<String, String>> attribute2value,
|
||||
int numberInIteration,
|
||||
CustomTemplateCallback callback) {
|
||||
PsiElement context = callback.getContext();
|
||||
for (ZenCodingFilter filter : ZenCodingFilter.EP_NAME.getExtensions()) {
|
||||
if (filter.isMyContext(context)) {
|
||||
return filter.buildAttributesString(attribute2value, numberInIteration);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
return new ZenCodingFilterImpl().buildAttributesString(attribute2value, numberInIteration);
|
||||
}
|
||||
|
||||
private static String getAttributeString(String name, String value) {
|
||||
return name + "=\"" + value + '"';
|
||||
}
|
||||
|
||||
private static String getValue(Pair<String, String> pair, int numberInIteration) {
|
||||
return pair.second.replace(NUMBER_IN_ITERATION_PLACE_HOLDER, Integer.toString(numberInIteration + 1));
|
||||
}
|
||||
|
||||
private static void invokeTemplate(TemplateToken token,
|
||||
final CustomTemplateCallback callback,
|
||||
@@ -315,13 +304,15 @@ class XmlZenCodingInterpreter {
|
||||
for (Iterator<Pair<String, String>> iterator = attr2value.iterator(); iterator.hasNext();) {
|
||||
Pair<String, String> pair = iterator.next();
|
||||
if (tag.getAttribute(pair.first) != null) {
|
||||
tag.setAttribute(pair.first, getValue(pair, numberInIteration));
|
||||
tag.setAttribute(pair.first, ZenCodingUtil.getValue(pair, numberInIteration));
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
modifiedTemplate.setString(filter(tag, callback));
|
||||
String s = filter(tag, callback);
|
||||
assert s != null;
|
||||
modifiedTemplate.setString(s);
|
||||
removeVariablesWhichHasNoSegment(modifiedTemplate);
|
||||
Map<String, String> predefinedValues = buildPredefinedValues(attr2value, numberInIteration);
|
||||
Map<String, String> predefinedValues = buildPredefinedValues(attr2value, numberInIteration, callback);
|
||||
callback.expandTemplate(modifiedTemplate, predefinedValues);
|
||||
return;
|
||||
}
|
||||
@@ -330,60 +321,20 @@ class XmlZenCodingInterpreter {
|
||||
}
|
||||
else {
|
||||
// for CSS
|
||||
Map<String, String> predefinedValues = buildPredefinedValues(attr2value, numberInIteration);
|
||||
Map<String, String> predefinedValues = buildPredefinedValues(attr2value, numberInIteration, callback);
|
||||
callback.expandTemplate(token.getKey(), predefinedValues);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String filter(XmlTag tag, CustomTemplateCallback callback) {
|
||||
if (XmlZenCodingTemplate.isTrueXml(callback)) {
|
||||
closeUnclosingTags(tag);
|
||||
}
|
||||
return tag.getContainingFile().getText();
|
||||
}
|
||||
|
||||
private static boolean isTagClosed(@NotNull XmlTag tag) {
|
||||
ASTNode node = tag.getNode();
|
||||
assert node != null;
|
||||
final ASTNode emptyTagEnd = XmlChildRole.EMPTY_TAG_END_FINDER.findChild(node);
|
||||
final ASTNode endTagEnd = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(node);
|
||||
return emptyTagEnd != null || endTagEnd != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"ConstantConditions"})
|
||||
private static void closeUnclosingTags(@NotNull XmlTag root) {
|
||||
final List<SmartPsiElementPointer<XmlTag>> tagToClose = new ArrayList<SmartPsiElementPointer<XmlTag>>();
|
||||
Project project = root.getProject();
|
||||
final SmartPointerManager pointerManager = SmartPointerManager.getInstance(project);
|
||||
root.accept(new XmlRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitXmlTag(final XmlTag tag) {
|
||||
if (!isTagClosed(tag)) {
|
||||
tagToClose.add(pointerManager.createLazyPointer(tag));
|
||||
}
|
||||
}
|
||||
});
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
||||
for (final SmartPsiElementPointer<XmlTag> pointer : tagToClose) {
|
||||
final XmlTag tag = pointer.getElement();
|
||||
if (tag != null) {
|
||||
final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild(tag.getNode());
|
||||
if (child != null) {
|
||||
final int offset = child.getTextRange().getStartOffset();
|
||||
VirtualFile file = tag.getContainingFile().getVirtualFile();
|
||||
if (file != null) {
|
||||
final Document document = FileDocumentManager.getInstance().getDocument(file);
|
||||
documentManager.doPostponedOperationsAndUnblockDocument(document);
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
document.replaceString(offset, tag.getTextRange().getEndOffset(), "/>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
PsiElement context = callback.getContext();
|
||||
for (ZenCodingFilter filter : ZenCodingFilter.EP_NAME.getExtensions()) {
|
||||
if (filter.isMyContext(context)) {
|
||||
return filter.toString(tag, context);
|
||||
}
|
||||
}
|
||||
documentManager.commitAllDocuments();
|
||||
return new ZenCodingFilterImpl().toString(tag, context);
|
||||
}
|
||||
|
||||
private static void fail() {
|
||||
|
||||
@@ -160,7 +160,10 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate {
|
||||
}
|
||||
|
||||
public static boolean isTrueXml(CustomTemplateCallback callback) {
|
||||
FileType type = callback.getFileType();
|
||||
return isTrueXml(callback.getFileType());
|
||||
}
|
||||
|
||||
public static boolean isTrueXml(FileType type) {
|
||||
return type == StdFileTypes.XHTML || type == StdFileTypes.JSPX || type == StdFileTypes.XML;
|
||||
}
|
||||
|
||||
@@ -265,11 +268,23 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate {
|
||||
if (PsiTreeUtil.getParentOfType(element, XmlComment.class) != null) {
|
||||
return false;
|
||||
}
|
||||
if (!findApplicableFilter(element)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean findApplicableFilter(@NotNull PsiElement context) {
|
||||
for (ZenCodingFilter filter : ZenCodingFilter.EP_NAME.getExtensions()) {
|
||||
if (filter.isMyContext(context)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return new ZenCodingFilterImpl().isMyContext(context);
|
||||
}
|
||||
|
||||
public static boolean startZenCoding(Editor editor, PsiFile file, String abbreviation) {
|
||||
int caretAt = editor.getCaretModel().getOffset();
|
||||
XmlZenCodingTemplate template = CustomLiveTemplate.EP_NAME.findExtension(XmlZenCodingTemplate.class);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.template.zencoding;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public interface ZenCodingFilter {
|
||||
ExtensionPointName<ZenCodingFilter> EP_NAME = new ExtensionPointName<ZenCodingFilter>("com.intellij.xml.zenCodingFilter");
|
||||
|
||||
@NotNull
|
||||
String toString(@NotNull XmlTag tag, @NotNull PsiElement context);
|
||||
|
||||
@NotNull
|
||||
String buildAttributesString(@NotNull List<Pair<String, String>> attribute2value, int numberInIteration);
|
||||
|
||||
boolean isMyContext(@NotNull PsiElement context);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.template.zencoding;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.xml.XmlChildRole;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class ZenCodingFilterImpl implements ZenCodingFilter {
|
||||
@NotNull
|
||||
public String toString(@NotNull XmlTag tag, @NotNull PsiElement context) {
|
||||
FileType fileType = context.getContainingFile().getFileType();
|
||||
if (XmlZenCodingTemplate.isTrueXml(fileType)) {
|
||||
closeUnclosingTags(tag);
|
||||
}
|
||||
return tag.getContainingFile().getText();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String buildAttributesString(@NotNull List<Pair<String, String>> attribute2value, int numberInIteration) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Iterator<Pair<String, String>> it = attribute2value.iterator(); it.hasNext();) {
|
||||
Pair<String, String> pair = it.next();
|
||||
String name = pair.first;
|
||||
String value = ZenCodingUtil.getValue(pair, numberInIteration);
|
||||
result.append(getAttributeString(name, value));
|
||||
if (it.hasNext()) {
|
||||
result.append(' ');
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public boolean isMyContext(@NotNull PsiElement context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getAttributeString(String name, String value) {
|
||||
return name + "=\"" + value + '"';
|
||||
}
|
||||
|
||||
@SuppressWarnings({"ConstantConditions"})
|
||||
private static void closeUnclosingTags(@NotNull XmlTag root) {
|
||||
final List<SmartPsiElementPointer<XmlTag>> tagToClose = new ArrayList<SmartPsiElementPointer<XmlTag>>();
|
||||
Project project = root.getProject();
|
||||
final SmartPointerManager pointerManager = SmartPointerManager.getInstance(project);
|
||||
root.accept(new XmlRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitXmlTag(final XmlTag tag) {
|
||||
if (!isTagClosed(tag)) {
|
||||
tagToClose.add(pointerManager.createLazyPointer(tag));
|
||||
}
|
||||
}
|
||||
});
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
||||
for (final SmartPsiElementPointer<XmlTag> pointer : tagToClose) {
|
||||
final XmlTag tag = pointer.getElement();
|
||||
if (tag != null) {
|
||||
final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild(tag.getNode());
|
||||
if (child != null) {
|
||||
final int offset = child.getTextRange().getStartOffset();
|
||||
VirtualFile file = tag.getContainingFile().getVirtualFile();
|
||||
if (file != null) {
|
||||
final Document document = FileDocumentManager.getInstance().getDocument(file);
|
||||
documentManager.doPostponedOperationsAndUnblockDocument(document);
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
document.replaceString(offset, tag.getTextRange().getEndOffset(), "/>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
documentManager.commitAllDocuments();
|
||||
}
|
||||
|
||||
private static boolean isTagClosed(@NotNull XmlTag tag) {
|
||||
ASTNode node = tag.getNode();
|
||||
assert node != null;
|
||||
final ASTNode emptyTagEnd = XmlChildRole.EMPTY_TAG_END_FINDER.findChild(node);
|
||||
final ASTNode endTagEnd = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(node);
|
||||
return emptyTagEnd != null || endTagEnd != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.codeInsight.template.zencoding;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class ZenCodingUtil {
|
||||
static final String NUMBER_IN_ITERATION_PLACE_HOLDER = "$";
|
||||
|
||||
public static String getValue(Pair<String, String> pair, int numberInIteration) {
|
||||
return pair.second.replace(NUMBER_IN_ITERATION_PLACE_HOLDER, Integer.toString(numberInIteration + 1));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user