package com.dmarcotte.handlebars.editor.actions; import com.dmarcotte.handlebars.psi.HbPsiFile; import com.dmarcotte.handlebars.psi.HbPsiUtil; import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; /** * Handler for custom plugin actions when {@code Enter} is typed by the user */ public class HbEnterHandler extends EnterHandlerDelegateAdapter { public Result preprocessEnter(@NotNull final PsiFile file, @NotNull final Editor editor, @NotNull final Ref<Integer> caretOffset, @NotNull final Ref<Integer> caretAdvance, @NotNull final DataContext dataContext, final EditorActionHandler originalHandler) { /** * if we are between open and close tags, we ensure the caret ends up in the "logical" place on Enter. * i.e. "{{#foo}}<caret>{{/foo}}" becomes the following on Enter: * * {{#foo}} * <caret> * {{/foo}} * * (Note: <caret> may be indented depending on formatter settings.) */ if (file instanceof HbPsiFile && isBetweenHbTags(editor, file, caretOffset.get())) { originalHandler.execute(editor, dataContext); return Result.Default; } return Result.Continue; } /** * Checks to see if {@code Enter} has been typed while the caret is between an open and close tag pair. * * @return true if between open and close tags, false otherwise */ private static boolean isBetweenHbTags(Editor editor, PsiFile file, int offset) { if (offset == 0) return false; CharSequence chars = editor.getDocument().getCharsSequence(); if (chars.charAt(offset - 1) != '}') return false; EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter(); HighlighterIterator iterator = highlighter.createIterator(offset - 1); PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); final PsiElement openerElement = file.findElementAt(iterator.getStart()); PsiElement openTag = HbPsiUtil.findParentOpenTagElement(openerElement); if (openTag == null) { return false; } iterator.advance(); if (iterator.atEnd()) { // no more tokens, so certainly no close tag return false; } final PsiElement closerElement = file.findElementAt(iterator.getStart()); PsiElement closeTag = HbPsiUtil.findParentCloseTagElement(closerElement); // if we got this far, we're between open and close tags iff this is a close tag return closeTag != null; } }