| /* |
| * Copyright 2000-2014 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.emmet.generators; |
| |
| import com.intellij.codeInsight.template.CustomTemplateCallback; |
| import com.intellij.codeInsight.template.emmet.EmmetParser; |
| import com.intellij.codeInsight.template.emmet.XmlEmmetParser; |
| import com.intellij.codeInsight.template.emmet.ZenCodingTemplate; |
| import com.intellij.codeInsight.template.emmet.tokens.TemplateToken; |
| 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.util.text.StringUtil; |
| import com.intellij.psi.PsiElement; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| |
| /** |
| * @author Eugene.Kudelevsky |
| */ |
| public abstract class ZenCodingGenerator { |
| private static final ExtensionPointName<ZenCodingGenerator> EP_NAME = new ExtensionPointName<ZenCodingGenerator>("com.intellij.xml.zenCodingGenerator"); |
| |
| public abstract TemplateImpl generateTemplate(@NotNull TemplateToken token, boolean hasChildren, @NotNull PsiElement context); |
| |
| @Nullable |
| public TemplateImpl createTemplateByKey(@NotNull String key) { |
| return null; |
| } |
| |
| public abstract boolean isMyContext(@NotNull PsiElement context, boolean wrapping); |
| |
| @Nullable |
| public String getSuffix() { |
| return null; |
| } |
| |
| public abstract boolean isAppliedByDefault(@NotNull PsiElement context); |
| |
| public abstract boolean isEnabled(); |
| |
| public static List<ZenCodingGenerator> getInstances() { |
| List<ZenCodingGenerator> generators = new ArrayList<ZenCodingGenerator>(); |
| Collections.addAll(generators, XmlZenCodingGeneratorImpl.INSTANCE); |
| Collections.addAll(generators, EP_NAME.getExtensions()); |
| return generators; |
| } |
| |
| @Nullable |
| public String computeTemplateKey(@NotNull CustomTemplateCallback callback) { |
| Editor editor = callback.getEditor(); |
| int currentOffset = editor.getCaretModel().getOffset(); |
| int startOffset = editor.getDocument().getLineStartOffset(editor.getCaretModel().getLogicalPosition().line); |
| String key = computeKey(editor.getDocument().getCharsSequence().subSequence(startOffset, currentOffset)); |
| return !StringUtil.isEmpty(key) && ZenCodingTemplate.checkTemplateKey(key, callback, this) ? key : null; |
| } |
| |
| @Nullable |
| protected String computeKey(@NotNull CharSequence text) { |
| int currentOffset = text.length(); |
| int groupCount = 0; |
| int bracketCount = 0; |
| int textCount = 0; |
| |
| while (currentOffset > 0) { |
| currentOffset--; |
| char c = text.charAt(currentOffset); |
| |
| if (c == ']') { |
| bracketCount++; |
| } |
| else if (c == '[') { |
| if (bracketCount == 0) { |
| currentOffset++; |
| break; |
| } |
| bracketCount--; |
| } |
| else if (c == '}') { |
| textCount++; |
| } |
| else if (c == '{') { |
| if (textCount == 0) { |
| currentOffset++; |
| break; |
| } |
| textCount--; |
| } |
| else if (c == ')') { |
| groupCount++; |
| } |
| else if (c == '(') { |
| if (groupCount == 0) { |
| currentOffset++; |
| break; |
| } |
| groupCount--; |
| } |
| else { |
| if (bracketCount > 0 || textCount > 0) { |
| // respect all characters inside attribute sets or text nodes |
| continue; |
| } |
| if (!isAllowedChar(c)) { |
| currentOffset++; |
| break; |
| } |
| } |
| } |
| return groupCount == 0 && textCount == 0 && bracketCount == 0 && currentOffset >= 0 && currentOffset < text.length() |
| ? text.subSequence(currentOffset, text.length()).toString().replaceFirst("^[*+>^]+", "") |
| : null; |
| } |
| |
| private static boolean isAllowedChar(char c) { |
| return (Character.isDigit(c) || Character.isLetter(c) || StringUtil.containsChar("/>+^[](){}#.*:$-_!@|%", c)); |
| } |
| |
| @NotNull |
| public EmmetParser createParser(List<ZenCodingToken> tokens, |
| CustomTemplateCallback callback, |
| ZenCodingGenerator generator, |
| boolean surroundWithTemplate) { |
| return new XmlEmmetParser(tokens, callback, generator, surroundWithTemplate); |
| } |
| |
| @Nullable |
| public UnnamedConfigurable createConfigurable() { |
| return null; |
| } |
| |
| public boolean hasCompletionItem() { |
| return false; |
| } |
| } |