/*
* Copyright 2013-2017 consulo.io
*
* 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 consulo.csharp.ide.completion.util;
import org.jetbrains.annotations.Nullable;
import consulo.annotations.RequiredDispatchThread;
import consulo.csharp.ide.parameterInfo.CSharpParameterInfoHandler;
import consulo.dotnet.psi.DotNetLikeMethodDeclaration;
import consulo.dotnet.psi.DotNetParameterList;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
/**
* @author peter
*/
public class CSharpParenthesesInsertHandler implements InsertHandler<LookupElement>
{
private DotNetLikeMethodDeclaration myLikeMethodDeclaration;
public CSharpParenthesesInsertHandler(DotNetLikeMethodDeclaration likeMethodDeclaration)
{
myLikeMethodDeclaration = likeMethodDeclaration;
}
@RequiredDispatchThread
private static boolean isToken(@Nullable final PsiElement element, final String text)
{
return element != null && text.equals(element.getText());
}
@RequiredDispatchThread
private boolean placeCaretInsideParentheses()
{
DotNetParameterList parameterList = myLikeMethodDeclaration.getParameterList();
return parameterList != null && parameterList.getParametersCount() > 0;
}
@RequiredDispatchThread
@Override
public void handleInsert(final InsertionContext context, final LookupElement item)
{
final Editor editor = context.getEditor();
final Document document = editor.getDocument();
context.commitDocument();
PsiElement element = findNextToken(context);
final char completionChar = context.getCompletionChar();
final boolean putCaretInside = completionChar == '(' || placeCaretInsideParentheses();
if(completionChar == '(')
{
context.setAddCompletionChar(false);
}
if(isToken(element, "("))
{
int lparenthOffset = element.getTextRange().getStartOffset();
if(completionChar == '(' || completionChar == '\t')
{
editor.getCaretModel().moveToOffset(lparenthOffset + 1);
}
else
{
editor.getCaretModel().moveToOffset(context.getTailOffset());
}
context.setTailOffset(lparenthOffset + 1);
PsiElement list = element.getParent();
PsiElement last = list.getLastChild();
if(isToken(last, ")"))
{
int rparenthOffset = last.getTextRange().getStartOffset();
context.setTailOffset(rparenthOffset + 1);
if(!putCaretInside)
{
for(int i = lparenthOffset + 1; i < rparenthOffset; i++)
{
if(!Character.isWhitespace(document.getCharsSequence().charAt(i)))
{
return;
}
}
editor.getCaretModel().moveToOffset(context.getTailOffset());
}
else
{
AutoPopupController.getInstance(context.getProject()).autoPopupParameterInfo(editor, CSharpParameterInfoHandler.item(myLikeMethodDeclaration));
editor.getCaretModel().moveToOffset(lparenthOffset + 1);
}
return;
}
}
else
{
document.insertString(context.getTailOffset(), "" + "(" + "");
editor.getCaretModel().moveToOffset(context.getTailOffset());
}
if(context.getCompletionChar() == '(')
{
//todo use BraceMatchingUtil.isPairedBracesAllowedBeforeTypeInFileType
int tail = context.getTailOffset();
if(tail < document.getTextLength() && StringUtil.isJavaIdentifierPart(document.getCharsSequence().charAt(tail)))
{
return;
}
}
document.insertString(context.getTailOffset(), ")");
if(!putCaretInside)
{
editor.getCaretModel().moveToOffset(context.getTailOffset());
}
else
{
AutoPopupController.getInstance(context.getProject()).autoPopupParameterInfo(editor, CSharpParameterInfoHandler.item(myLikeMethodDeclaration));
}
}
@Nullable
@RequiredDispatchThread
protected PsiElement findNextToken(final InsertionContext context)
{
final PsiFile file = context.getFile();
PsiElement element = file.findElementAt(context.getTailOffset());
if(element instanceof PsiWhiteSpace)
{
boolean allowParametersOnNextLine = false;
if(!allowParametersOnNextLine && element.getText().contains("\n"))
{
return null;
}
element = file.findElementAt(element.getTextRange().getEndOffset());
}
return element;
}
}