package org.angularjs.editor; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.editorActions.TypedHandlerDelegate; import com.intellij.ide.highlighter.HtmlFileType; import com.intellij.lang.javascript.formatter.JSCodeStyleSettings; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorModificationUtil; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.psi.MultiplePsiFilesPerDocumentFileViewProvider; import com.intellij.psi.PsiFile; /** * @author Dennis.Ushakov */ public class AngularBracesInterpolationTypedHandler extends TypedHandlerDelegate { @Override public Result beforeCharTyped(char c, Project project, Editor editor, PsiFile file, FileType fileType) { if (file.getViewProvider() instanceof MultiplePsiFilesPerDocumentFileViewProvider || DumbService.isDumb(project)) return Result.CONTINUE; if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return Result.DEFAULT; // we should use AngularJSBracesUtil here if (file.getFileType() == HtmlFileType.INSTANCE) { final Document document = editor.getDocument(); if (c == '{') { if (!AngularJSBracesUtil.DEFAULT_START.equals(AngularJSBracesUtil.getInjectionStart(project)) || !AngularJSBracesUtil.DEFAULT_END.equals(AngularJSBracesUtil.getInjectionEnd(project))) return Result.CONTINUE; JSCodeStyleSettings jsSettings = JSCodeStyleSettings.getSettings(file); boolean addWhiteSpaceBetweenBraces = jsSettings.SPACES_WITHIN_INTERPOLATION_EXPRESSIONS; int offset = editor.getCaretModel().getOffset(); String chars = document.getText(); if (offset > 0 && (chars.charAt(offset - 1)) == '{') { if (offset < 2 || (chars.charAt(offset - 2)) != '{') { if (alreadyHasEnding(chars, offset)) { return Result.CONTINUE; } else { String interpolation = addWhiteSpaceBetweenBraces ? "{ }" : "{}"; if (offset == chars.length() || (offset < chars.length() && chars.charAt(offset) != '}')) { interpolation += "}"; } EditorModificationUtil.insertStringAtCaret(editor, interpolation, true, addWhiteSpaceBetweenBraces ? 2 : 1); return Result.STOP; } } } } if (c == '}') { if (!AngularJSBracesUtil.DEFAULT_END.equals(AngularJSBracesUtil.getInjectionEnd(project))) return Result.CONTINUE; final int offset = editor.getCaretModel().getOffset(); final char charAt; if (offset < document.getTextLength()) { charAt = document.getCharsSequence().charAt(offset); if (charAt == '}') { editor.getCaretModel().moveCaretRelatively(1, 0, false, false, true); return Result.STOP; } } else if (offset > 0) { charAt = document.getCharsSequence().charAt(offset - 1); if (charAt != '}') { EditorModificationUtil.insertStringAtCaret(editor, "}}", true, 2); return Result.STOP; } } } } return Result.CONTINUE; } private static boolean alreadyHasEnding(String chars, int offset) { int i = offset; while (i < chars.length() && (chars.charAt(i) != '{' && chars.charAt(i) != '}' && chars.charAt(i) != '\n')) { i++; } return i + 1 < chars.length() && chars.charAt(i) == '}' && chars.charAt(i + 1) == '}'; } }