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);
}
}
}
- 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;
}
}
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;
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);