blob: c925cd2c25b01c7f5e8759913b6176348e987496 [file] [log] [blame]
/*
* Copyright 2000-2009 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.codeInsight.completion.simple;
import com.intellij.codeInsight.TailType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
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.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.java.IJavaElementType;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NonNls;
/**
* @author peter
*/
public abstract class RParenthTailType extends TailType {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.simple.RParenthSimpleTailType");
private static TextRange getRangeToCheckParensBalance(PsiFile file, final Document document, int startOffset){
PsiElement element = file.findElementAt(startOffset);
element = PsiTreeUtil.getParentOfType(element, PsiStatement.class, false);
if (element != null) {
final PsiElement parent = element.getParent();
if (parent instanceof PsiLoopStatement) {
element = parent;
}
}
return element == null ? new TextRange(0, document.getTextLength()) : element.getTextRange();
}
protected abstract boolean isSpaceWithinParentheses(CommonCodeStyleSettings styleSettings, Editor editor, final int tailOffset);
@Override
public int processTail(final Editor editor, int tailOffset) {
return addRParenth(editor, tailOffset, isSpaceWithinParentheses(getLocalCodeStyleSettings(editor, tailOffset), editor, tailOffset));
}
public static int addRParenth(Editor editor, int offset, boolean spaceWithinParens) {
int existingRParenthOffset = getExistingRParenthOffset(editor, offset);
if (existingRParenthOffset < 0){
if (spaceWithinParens){
offset = insertChar(editor, offset, ' ');
}
editor.getDocument().insertString(offset, ")");
return moveCaret(editor, offset, 1);
}
if (spaceWithinParens && offset == existingRParenthOffset) {
existingRParenthOffset = insertChar(editor, offset, ' ');
}
return moveCaret(editor, existingRParenthOffset, 1);
}
@NonNls
public String toString() {
return "RParenth";
}
private static int getExistingRParenthOffset(final Editor editor, final int tailOffset) {
final Document document = editor.getDocument();
if (tailOffset >= document.getTextLength()) return -1;
final CharSequence charsSequence = document.getCharsSequence();
EditorHighlighter highlighter = ((EditorEx) editor).getHighlighter();
int existingRParenthOffset = -1;
for(HighlighterIterator iterator = highlighter.createIterator(tailOffset); !iterator.atEnd(); iterator.advance()){
final IElementType tokenType = iterator.getTokenType();
if ((!(tokenType instanceof IJavaElementType) || !ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(tokenType)) &&
tokenType != TokenType.WHITE_SPACE) {
final int start = iterator.getStart();
if (iterator.getEnd() == start + 1 && ')' == charsSequence.charAt(start)) {
existingRParenthOffset = start;
}
break;
}
}
if (existingRParenthOffset >= 0){
final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(editor.getProject());
psiDocumentManager.commitDocument(document);
TextRange range = getRangeToCheckParensBalance(psiDocumentManager.getPsiFile(document), document, editor.getCaretModel().getOffset());
int balance = calcParensBalance(document, highlighter, range.getStartOffset(), range.getEndOffset());
if (balance > 0){
return -1;
}
}
return existingRParenthOffset;
}
private static int calcParensBalance(Document document, EditorHighlighter highlighter, int rangeStart, int rangeEnd){
LOG.assertTrue(0 <= rangeStart);
LOG.assertTrue(rangeStart <= rangeEnd);
LOG.assertTrue(rangeEnd <= document.getTextLength());
HighlighterIterator iterator = highlighter.createIterator(rangeStart);
int balance = 0;
while(!iterator.atEnd() && iterator.getStart() < rangeEnd){
IElementType tokenType = iterator.getTokenType();
if (tokenType == JavaTokenType.LPARENTH){
balance++;
}
else if (tokenType == JavaTokenType.RPARENTH){
balance--;
}
iterator.advance();
}
return balance;
}
}