| /* |
| * 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; |
| |
| import com.intellij.codeInsight.AutoPopupController; |
| import com.intellij.codeInsight.CharTailType; |
| import com.intellij.codeInsight.TailType; |
| import com.intellij.codeInsight.TailTypes; |
| import com.intellij.codeInsight.lookup.Lookup; |
| import com.intellij.codeInsight.lookup.LookupElement; |
| import com.intellij.codeInsight.lookup.LookupItem; |
| import com.intellij.openapi.editor.Document; |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.psi.PsiDocumentManager; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.codeStyle.CommonCodeStyleSettings; |
| import org.jetbrains.annotations.NotNull; |
| |
| public class DefaultInsertHandler extends TemplateInsertHandler implements Cloneable { |
| |
| public static final DefaultInsertHandler NO_TAIL_HANDLER = new DefaultInsertHandler(){ |
| @Override |
| protected TailType getTailType(char completionChar, LookupItem item) { |
| return TailType.NONE; |
| } |
| }; |
| |
| @Override |
| public void handleInsert(final InsertionContext context, LookupElement item) { |
| super.handleInsert(context, item); |
| |
| handleInsertInner(context, (LookupItem)item, context.getCompletionChar()); |
| } |
| |
| private void handleInsertInner(InsertionContext context, LookupItem item, final char completionChar) { |
| final Project project = context.getProject(); |
| final Editor editor = context.getEditor(); |
| final Document document = editor.getDocument(); |
| PsiDocumentManager.getInstance(project).commitDocument(document); |
| |
| TailType tailType = getTailType(completionChar, item); |
| |
| InsertHandlerState state = new InsertHandlerState(context.getSelectionEndOffset(), context.getSelectionEndOffset()); |
| |
| if (completionChar == Lookup.REPLACE_SELECT_CHAR) { |
| removeEndOfIdentifier(context); |
| } |
| else if(context.getOffsetMap().getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET) != context.getSelectionEndOffset()) { |
| JavaCompletionUtil.resetParensInfo(context.getOffsetMap()); |
| } |
| |
| handleParentheses(false, false, tailType, context, state); |
| |
| context.setTailOffset(state.tailOffset); |
| state.caretOffset = processTail(tailType, state.caretOffset, state.tailOffset, editor); |
| editor.getSelectionModel().removeSelection(); |
| |
| if (tailType == TailType.DOT || context.getCompletionChar() == '.') { |
| AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, null); |
| } |
| |
| } |
| |
| private static void handleParentheses(final boolean hasParams, final boolean needParenth, TailType tailType, InsertionContext context, InsertHandlerState myState){ |
| final Document document = context.getEditor().getDocument(); |
| boolean insertRightParenth = context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR; |
| |
| if (needParenth){ |
| if (context.getOffsetMap().getOffset(JavaCompletionUtil.LPAREN_OFFSET) >= 0 && context.getOffsetMap().getOffset(JavaCompletionUtil.ARG_LIST_END_OFFSET) >= 0){ |
| myState.tailOffset = context.getOffsetMap().getOffset(JavaCompletionUtil.ARG_LIST_END_OFFSET); |
| if (context.getOffsetMap().getOffset(JavaCompletionUtil.RPAREN_OFFSET) < 0 && insertRightParenth){ |
| document.insertString(myState.tailOffset, ")"); |
| myState.tailOffset += 1; |
| } |
| if (hasParams){ |
| myState.caretOffset = context.getOffsetMap().getOffset(JavaCompletionUtil.LPAREN_OFFSET) + 1; |
| } |
| else{ |
| myState.caretOffset = context.getOffsetMap().getOffset(JavaCompletionUtil.ARG_LIST_END_OFFSET); |
| } |
| } |
| else{ |
| final CommonCodeStyleSettings styleSettings = context.getCodeStyleSettings(); |
| myState.tailOffset = context.getSelectionEndOffset(); |
| myState.caretOffset = context.getSelectionEndOffset(); |
| |
| if(styleSettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES){ |
| document.insertString(myState.tailOffset++, " "); |
| myState.caretOffset ++; |
| } |
| if (insertRightParenth) { |
| final CharSequence charsSequence = document.getCharsSequence(); |
| if (charsSequence.length() <= myState.tailOffset || charsSequence.charAt(myState.tailOffset) != '(') { |
| document.insertString(myState.tailOffset, "("); |
| } |
| |
| document.insertString(myState.tailOffset + 1, ")"); |
| if (hasParams){ |
| myState.tailOffset += 2; |
| myState.caretOffset++; |
| } |
| else{ |
| if (tailType != TailTypes.CALL_RPARENTH) { |
| myState.tailOffset += 2; |
| myState.caretOffset += 2; |
| } |
| else { |
| myState.tailOffset++; |
| myState.caretOffset++; |
| } |
| } |
| } |
| else{ |
| document.insertString(myState.tailOffset++, "("); |
| myState.caretOffset ++; |
| } |
| |
| if(hasParams && styleSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES){ |
| document.insertString(myState.caretOffset++, " "); |
| myState.tailOffset++; |
| } |
| } |
| } |
| } |
| |
| public static void removeEndOfIdentifier(InsertionContext context){ |
| final Document document = context.getEditor().getDocument(); |
| JavaCompletionUtil.initOffsets(context.getFile(), context.getOffsetMap()); |
| document.deleteString(context.getSelectionEndOffset(), context.getOffsetMap().getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET)); |
| if(context.getOffsetMap().getOffset(JavaCompletionUtil.LPAREN_OFFSET) > 0){ |
| document.deleteString(context.getOffsetMap().getOffset(JavaCompletionUtil.LPAREN_OFFSET), |
| context.getOffsetMap().getOffset(JavaCompletionUtil.ARG_LIST_END_OFFSET)); |
| JavaCompletionUtil.resetParensInfo(context.getOffsetMap()); |
| } |
| } |
| |
| protected TailType getTailType(final char completionChar, LookupItem item){ |
| switch(completionChar){ |
| case '.': return new CharTailType('.', false); |
| case ',': return TailType.COMMA; |
| case ';': return TailType.SEMICOLON; |
| case '=': return TailType.EQ; |
| case ' ': return TailType.SPACE; |
| case ':': return TailType.CASE_COLON; //? |
| case '<': |
| case '>': |
| case '\"': |
| } |
| final TailType attr = item.getTailType(); |
| return attr == TailType.UNKNOWN ? TailType.NONE : attr; |
| } |
| |
| private static int processTail(TailType tailType, int caretOffset, int tailOffset, Editor editor) { |
| editor.getCaretModel().moveToOffset(caretOffset); |
| tailType.processTail(editor, tailOffset); |
| return editor.getCaretModel().getOffset(); |
| } |
| |
| @Override |
| protected void populateInsertMap(@NotNull final PsiFile file, @NotNull final OffsetMap offsetMap) { |
| JavaCompletionUtil.initOffsets(file, offsetMap); |
| } |
| |
| public static class InsertHandlerState{ |
| int tailOffset; |
| int caretOffset; |
| |
| public InsertHandlerState(int caretOffset, int tailOffset){ |
| this.caretOffset = caretOffset; |
| this.tailOffset = tailOffset; |
| } |
| } |
| } |