correct work of Zen Coding inside inline HTML tag (WI-1131)
authorEugene Kudelevsky <Eugene.Kudelevsky@jetbrains.com>
Fri, 19 Feb 2010 15:25:04 +0000 (18:25 +0300)
committerEugene Kudelevsky <Eugene.Kudelevsky@jetbrains.com>
Fri, 19 Feb 2010 15:25:04 +0000 (18:25 +0300)
platform/lang-impl/src/com/intellij/codeInsight/template/CustomLiveTemplate.java
platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java
xml/impl/src/com/intellij/codeInsight/template/XmlCustomLiveTemplate.java

index 74912fddebad7e51fff05469e680906d4231d124..959aa06fa19a3aca2e4b2cb7990e96e4618ad3d5 100644 (file)
@@ -26,7 +26,8 @@ import org.jetbrains.annotations.Nullable;
 public interface CustomLiveTemplate {
   ExtensionPointName<CustomLiveTemplate> EP_NAME = ExtensionPointName.create("com.intellij.customLiveTemplate");
 
-  boolean isApplicable(@NotNull String key, @NotNull CustomTemplateCallback callback);
+  @Nullable
+  String computeTemplateKey(@NotNull CustomTemplateCallback callback);
 
-  void execute(@NotNull String key, @NotNull CustomTemplateCallback callback, @Nullable TemplateInvokationListener listener);
+  void execute(String key, @NotNull CustomTemplateCallback callback, @Nullable TemplateInvokationListener listener);
 }
index 0f661293de45e9a25597d375e9832fc1c58f54ee..6bfda59e3a57c395fa7693f58d4ac631d46d615c 100644 (file)
@@ -220,47 +220,19 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo
     }
   }
 
-  private static String getCurrentLineBeforeCaret(@NotNull Editor editor) {
-    CaretModel caretModel = editor.getCaretModel();
-    int line = caretModel.getLogicalPosition().line;
-    int lineStart = editor.getDocument().getLineStartOffset(line);
-    int offset = caretModel.getOffset();
-    String s = editor.getDocument().getCharsSequence().subSequence(lineStart, offset).toString();
-    int index = 0;
-    while (index < s.length() && Character.isWhitespace(s.charAt(index))) {
-      index++;
-    }
-    return index < s.length() ? s.substring(index) : s;
-  }
-
-  @NotNull
-  private static String normalize(@NotNull String key) {
-    int lastWhitespaceIndex = -1;
-    for (int i = 0; i < key.length(); i++) {
-      if (Character.isWhitespace(key.charAt(i))) {
-        lastWhitespaceIndex = i;
-      }
-    }
-    if (lastWhitespaceIndex >= 0 && lastWhitespaceIndex < key.length() - 1) {
-      return key.substring(lastWhitespaceIndex + 1);
-    }
-    return key;
-  }
-
   public boolean startTemplate(final Editor editor, char shortcutChar, final PairProcessor<String, String> processor) {
     PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject);
     if (file == null) return false;
     TemplateSettings templateSettings = TemplateSettings.getInstance();
     if (shortcutChar == templateSettings.getDefaultShortcutChar()) {
       for (final CustomLiveTemplate customLiveTemplate : CustomLiveTemplate.EP_NAME.getExtensions()) {
-        final String currentLineBeforeCaret = normalize(getCurrentLineBeforeCaret(editor));
         final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file);
-        if (customLiveTemplate.isApplicable(currentLineBeforeCaret, callback)) {
-          int offset = editor.getCaretModel().getOffset();
-          final int startOffset = offset - currentLineBeforeCaret.length();
-          editor.getDocument().deleteString(startOffset, offset);
+        String key = customLiveTemplate.computeTemplateKey(callback);
+        if (key != null) {
+          int offset = callback.getEditor().getCaretModel().getOffset();
+          callback.getEditor().getDocument().deleteString(offset - key.length(), offset);
           callback.fixInitialEditorState();
-          customLiveTemplate.execute(currentLineBeforeCaret, callback, null);
+          customLiveTemplate.execute(key, callback, null);
           return true;
         }
       }
index fad2be78c8bf4e31c789d2d620f46687c09cc43d..446fe956c6d27a8c5d8303c425a304ede4764658 100644 (file)
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.ScrollType;
 import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
 import com.intellij.util.containers.HashMap;
 import com.intellij.util.containers.HashSet;
@@ -273,18 +274,54 @@ public class XmlCustomLiveTemplate implements CustomLiveTemplate {
     return state == MyState.OPERATION || state == MyState.AFTER_NUMBER;
   }
 
-  public boolean isApplicable(@NotNull String key, @NotNull CustomTemplateCallback callback) {
+  private static String computeKey(Editor editor, int startOffset) {
+    int offset = editor.getCaretModel().getOffset();
+    String s = editor.getDocument().getCharsSequence().subSequence(startOffset, offset).toString();
+    int index = 0;
+    while (index < s.length() && Character.isWhitespace(s.charAt(index))) {
+      index++;
+    }
+    String key = s.substring(index);
+    int lastWhitespaceIndex = -1;
+    for (int i = 0; i < key.length(); i++) {
+      if (Character.isWhitespace(key.charAt(i))) {
+        lastWhitespaceIndex = i;
+      }
+    }
+    if (lastWhitespaceIndex >= 0 && lastWhitespaceIndex < key.length() - 1) {
+      return key.substring(lastWhitespaceIndex + 1);
+    }
+    return key;
+  }
+
+  public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
     PsiFile file = callback.getFile();
     if (file.getLanguage() instanceof XMLLanguage) {
-      List<MyToken> tokens = parse(key, callback);
-      if (tokens != null) {
-        return check(tokens);
+      Editor editor = callback.getEditor();
+      PsiElement element = file.findElementAt(editor.getCaretModel().getOffset() - 1);
+      int line = editor.getCaretModel().getLogicalPosition().line;
+      int lineStart = editor.getDocument().getLineStartOffset(line);
+      int parentStart;
+      do {
+        parentStart = element != null ? element.getTextRange().getStartOffset() : 0;
+        int startOffset = parentStart > lineStart ? parentStart : lineStart;
+        String key = computeKey(editor, startOffset);
+        List<MyToken> tokens = parse(key, callback);
+        if (tokens != null) {
+          if (check(tokens)) {
+            return key;
+          }
+        }
+        if (element != null) {
+          element = element.getParent();
+        }
       }
+      while (element != null && parentStart > lineStart);
     }
-    return false;
+    return null;
   }
 
-  public void execute(@NotNull String key, @NotNull CustomTemplateCallback callback, @Nullable TemplateInvokationListener listener) {
+  public void execute(String key, @NotNull CustomTemplateCallback callback, @Nullable TemplateInvokationListener listener) {
     List<MyToken> tokens = parse(key, callback);
     assert tokens != null;
     MyInterpreter interpreter = new MyInterpreter(tokens, callback, MyState.WORD, listener);