2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.codeInsight
.completion
.simple
;
18 import com
.intellij
.codeInsight
.TailType
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.editor
.Document
;
21 import com
.intellij
.openapi
.editor
.Editor
;
22 import com
.intellij
.openapi
.editor
.ex
.EditorEx
;
23 import com
.intellij
.openapi
.editor
.highlighter
.EditorHighlighter
;
24 import com
.intellij
.openapi
.editor
.highlighter
.HighlighterIterator
;
25 import com
.intellij
.openapi
.util
.TextRange
;
26 import com
.intellij
.psi
.*;
27 import com
.intellij
.psi
.codeStyle
.CodeStyleSettings
;
28 import com
.intellij
.psi
.codeStyle
.CodeStyleSettingsManager
;
29 import com
.intellij
.psi
.tree
.IElementType
;
30 import com
.intellij
.psi
.tree
.java
.IJavaElementType
;
31 import com
.intellij
.psi
.util
.PsiTreeUtil
;
32 import org
.jetbrains
.annotations
.NonNls
;
37 public abstract class RParenthTailType
extends TailType
{
38 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.completion.simple.RParenthSimpleTailType");
40 private static TextRange
getRangeToCheckParensBalance(PsiFile file
, final Document document
, int startOffset
){
41 PsiElement element
= file
.findElementAt(startOffset
);
42 element
= PsiTreeUtil
.getParentOfType(element
, PsiStatement
.class, false);
43 if (element
!= null) {
44 final PsiElement parent
= element
.getParent();
45 if (parent
instanceof PsiLoopStatement
) {
49 return element
== null ?
new TextRange(0, document
.getTextLength()) : element
.getTextRange();
52 protected abstract boolean isSpaceWithinParentheses(CodeStyleSettings styleSettings
, Editor editor
, final int tailOffset
);
54 public int processTail(final Editor editor
, int tailOffset
) {
55 CodeStyleSettings styleSettings
= CodeStyleSettingsManager
.getSettings(editor
.getProject());
56 int existingRParenthOffset
= getExistingRParenthOffset(editor
, tailOffset
);
58 boolean spaceWithinParens
= isSpaceWithinParentheses(styleSettings
, editor
, tailOffset
);
59 if (existingRParenthOffset
< 0){
60 if (spaceWithinParens
){
61 tailOffset
= insertChar(editor
, tailOffset
, ' ');
63 editor
.getDocument().insertString(tailOffset
, ")");
64 return moveCaret(editor
, tailOffset
, 1);
66 if (spaceWithinParens
&& tailOffset
== existingRParenthOffset
) {
67 existingRParenthOffset
= insertChar(editor
, tailOffset
, ' ');
69 return moveCaret(editor
, existingRParenthOffset
, 1);
73 public String
toString() {
77 private static int getExistingRParenthOffset(final Editor editor
, final int tailOffset
) {
78 final Document document
= editor
.getDocument();
79 if (tailOffset
>= document
.getTextLength()) return -1;
81 final CharSequence charsSequence
= document
.getCharsSequence();
82 EditorHighlighter highlighter
= ((EditorEx
) editor
).getHighlighter();
84 int existingRParenthOffset
= -1;
85 for(HighlighterIterator iterator
= highlighter
.createIterator(tailOffset
); !iterator
.atEnd(); iterator
.advance()){
86 final IElementType tokenType
= iterator
.getTokenType();
88 if ((!(tokenType
instanceof IJavaElementType
) || !JavaTokenType
.WHITE_SPACE_OR_COMMENT_BIT_SET
.contains(tokenType
)) &&
89 tokenType
!= TokenType
.WHITE_SPACE
) {
90 final int start
= iterator
.getStart();
91 if (iterator
.getEnd() == start
+ 1 && ')' == charsSequence
.charAt(start
)) {
92 existingRParenthOffset
= start
;
98 if (existingRParenthOffset
>= 0){
99 final PsiDocumentManager psiDocumentManager
= PsiDocumentManager
.getInstance(editor
.getProject());
100 psiDocumentManager
.commitDocument(document
);
101 TextRange range
= getRangeToCheckParensBalance(psiDocumentManager
.getPsiFile(document
), document
, editor
.getCaretModel().getOffset());
102 int balance
= calcParensBalance(document
, highlighter
, range
.getStartOffset(), range
.getEndOffset());
107 return existingRParenthOffset
;
110 private static int calcParensBalance(Document document
, EditorHighlighter highlighter
, int rangeStart
, int rangeEnd
){
111 LOG
.assertTrue(0 <= rangeStart
);
112 LOG
.assertTrue(rangeStart
<= rangeEnd
);
113 LOG
.assertTrue(rangeEnd
<= document
.getTextLength());
115 HighlighterIterator iterator
= highlighter
.createIterator(rangeStart
);
117 while(!iterator
.atEnd() && iterator
.getStart() < rangeEnd
){
118 IElementType tokenType
= iterator
.getTokenType();
119 if (tokenType
== JavaTokenType
.LPARENTH
){
122 else if (tokenType
== JavaTokenType
.RPARENTH
){