/*
* Copyright 2000-2013 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.coldFusion.UI.editorActions.typedHandlers;
import com.intellij.codeInsight.editorActions.TypedHandlerDelegate;
import com.intellij.coldFusion.UI.editorActions.matchers.CfmlBraceMatcher;
import com.intellij.coldFusion.UI.editorActions.utils.CfmlEditorUtil;
import com.intellij.coldFusion.model.CfmlLanguage;
import com.intellij.coldFusion.model.CfmlUtil;
import com.intellij.coldFusion.model.files.CfmlFile;
import com.intellij.coldFusion.model.lexer.CfmlTokenTypes;
import com.intellij.coldFusion.model.psi.CfmlTag;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SystemProperties;
import org.jetbrains.annotations.NotNull;
/**
* Created by Lera Nikolaenko
* Date: 13.10.2008
*/
public class CfmlTypedHandler extends TypedHandlerDelegate {
static final boolean ourEnableDoublePoundInsertion = SystemProperties.getBooleanProperty("idea.cfml.insert.pair.pound", true);
@Override
public Result checkAutoPopup(char charTyped, final Project project, final Editor editor, final PsiFile file) {
PsiFile cfmlFile = file.getViewProvider().getPsi(CfmlLanguage.INSTANCE);
if (isNotCfmlFile(cfmlFile, editor)) {
return Result.CONTINUE;
}
if (charTyped == '/') {
CfmlUtil.showCompletion(editor);
}
return Result.CONTINUE;
}
public Result beforeCharTyped(final char c, final Project project, final Editor editor, final PsiFile file, final FileType fileType) {
PsiFile cfmlFile = file.getViewProvider().getPsi(CfmlLanguage.INSTANCE);
if (isNotCfmlFile(cfmlFile, editor)) {
return Result.CONTINUE;
}
int offset = editor.getCaretModel().getOffset();
if (c == '{') {
CfmlBraceMatcher braceMatcher = new CfmlBraceMatcher();
HighlighterIterator iterator = ((EditorEx)editor).getHighlighter().createIterator(offset);
if (!braceMatcher.isLBraceToken(iterator, editor.getDocument().getCharsSequence(), fileType)) {
EditorModificationUtil.insertStringAtCaret(editor, "}", true, 0);
// return Result.STOP;
}
return Result.CONTINUE;
}
if (c == '#') {
if (ourEnableDoublePoundInsertion && CfmlEditorUtil.countSharpsBalance(editor) == 0) {
char charAtOffset = DocumentUtils.getCharAt(editor.getDocument(), offset);
if (charAtOffset == '#') {
EditorModificationUtil.moveCaretRelatively(editor, 1);
return Result.STOP;
}
EditorModificationUtil.insertStringAtCaret(editor, "#", true, 0);
}
}
else if (c == '>') {
if (((EditorEx)editor).getHighlighter().createIterator(editor.getCaretModel().getOffset()).getTokenType() == CfmlTokenTypes.COMMENT ||
((EditorEx)editor).getHighlighter().createIterator(editor.getCaretModel().getOffset()).getTokenType().getLanguage() !=
CfmlLanguage.INSTANCE) {
return Result.CONTINUE;
}
insertCloseTagIfNeeded(editor, cfmlFile, project);
return Result.STOP;
}
return Result.CONTINUE;
}
public static boolean insertCloseTagIfNeeded(Editor editor, PsiFile file, Project project) {
final Document document = editor.getDocument();
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
int offset = editor.getCaretModel().getOffset();
documentManager.commitDocument(document);
char charAtOffset = DocumentUtils.getCharAt(document, offset);
if (charAtOffset != '>') {
EditorModificationUtil.insertStringAtCaret(editor, ">", true, 0);
}
EditorModificationUtil.moveCaretRelatively(editor, 1);
++offset;
if (DocumentUtils.getCharAt(document, offset - 2) == '/') {
return false;
}
HighlighterIterator iterator = ((EditorEx)editor).getHighlighter().createIterator(offset - 2);
while (!iterator.atEnd() && !iterator.getTokenType().equals(CfmlTokenTypes.CF_TAG_NAME)) {
if (CfmlUtil.isControlToken(iterator.getTokenType())) {
return false;
}
iterator.retreat();
}
if (!iterator.atEnd()) {
iterator.retreat();
if (!iterator.atEnd() && iterator.getTokenType().equals(CfmlTokenTypes.LSLASH_ANGLEBRACKET)) {
return false;
}
iterator.advance();
}
if (iterator.atEnd()) {
return false;
}
String tagName = document.getCharsSequence().subSequence(iterator.getStart(), iterator.getEnd()).toString();
if (CfmlUtil.isSingleCfmlTag(tagName, project) || CfmlUtil.isUserDefined(tagName)) {
return false;
}
PsiElement tagElement = file.findElementAt(iterator.getStart());
while (tagElement != null && !(tagElement instanceof CfmlTag)) {
tagElement = tagElement.getParent();
}
if (tagElement == null) {
return false;
}
boolean doInsertion = false;
if (tagElement.getLastChild() instanceof PsiErrorElement) {
doInsertion = true;
}
else {
iterator = ((EditorEx)editor).getHighlighter().createIterator(0);
while (!iterator.atEnd() && iterator.getStart() < offset) {
if (iterator.getTokenType() == CfmlTokenTypes.CF_TAG_NAME) {
String currentTagName = document.getCharsSequence().subSequence(iterator.getStart(), iterator.getEnd()).toString();
if (tagName.equals(currentTagName)) {
PsiElement currentTagElement = file.findElementAt(iterator.getStart());
currentTagElement = PsiTreeUtil.getParentOfType(currentTagElement, CfmlTag.class);
if (currentTagElement.getLastChild() instanceof PsiErrorElement) {
doInsertion = true;
break;
}
}
}
iterator.advance();
}
}
String tagNameFromPsi = ((CfmlTag)tagElement).getTagName(); // tag name in lowercase
if (doInsertion && CfmlUtil.isEndTagRequired(tagNameFromPsi, project)) {
if (!Comparing.equal(tagNameFromPsi, tagName, false)) {
tagName = tagNameFromPsi; // use tagName because it has proper case
}
EditorModificationUtil.insertStringAtCaret(editor, "</" + tagName + ">", true, 0);
return true;
}
return false;
}
public Result charTyped(final char c, final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
if (isNotCfmlFile(file, editor)) {
return Result.CONTINUE;
}
return Result.CONTINUE;
}
static boolean isNotCfmlFile(final PsiFile file, final Editor editor) {
return !(file instanceof CfmlFile)
|| editor.getCaretModel().getOffset() == 0;
}
}