/*
* 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;
import static com.intellij.patterns.StandardPatterns.psiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import consulo.csharp.lang.psi.CSharpEventDeclaration;
import consulo.csharp.lang.psi.CSharpSoftTokens;
import consulo.csharp.lang.psi.CSharpXXXAccessorOwner;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import consulo.annotations.RequiredReadAction;
import consulo.annotations.RequiredWriteAction;
import consulo.codeInsight.completion.CompletionProvider;
import consulo.dotnet.psi.DotNetModifier;
import consulo.dotnet.psi.DotNetXXXAccessor;
/**
* @author VISTALL
* @since 24.12.14
*/
public class CSharpAccessorCompletionContributor extends CompletionContributor
{
public CSharpAccessorCompletionContributor()
{
extend(CompletionType.BASIC, psiElement().andNot(psiElement().inside(DotNetXXXAccessor.class)), new CompletionProvider()
{
@RequiredReadAction
@Override
public void addCompletions(@NotNull CompletionParameters completionParameters, ProcessingContext processingContext, @NotNull CompletionResultSet resultSet)
{
PsiElement position = completionParameters.getPosition();
final CSharpXXXAccessorOwner accessorOwner = PsiTreeUtil.getParentOfType(position, CSharpXXXAccessorOwner.class);
if(accessorOwner == null)
{
return;
}
PsiElement leftBrace = accessorOwner.getLeftBrace();
if(leftBrace == null)
{
return;
}
int textOffset = position.getTextOffset();
PsiElement rightBrace = accessorOwner.getRightBrace();
int rightTextRange = rightBrace == null ? -1 : rightBrace.getTextOffset();
if((rightTextRange == -1 || textOffset < rightTextRange) && textOffset > leftBrace.getTextOffset())
{
if(accessorOwner.hasModifier(DotNetModifier.ABSTRACT))
{
buildAccessorKeywordsCompletion(resultSet, accessorOwner, null);
}
else
{
buildAccessorKeywordsCompletion(resultSet, accessorOwner, new InsertHandler<LookupElement>()
{
@Override
@RequiredWriteAction
public void handleInsert(InsertionContext context, LookupElement item)
{
if(context.getCompletionChar() == '{')
{
context.setAddCompletionChar(false);
Editor editor = context.getEditor();
CaretModel caretModel = editor.getCaretModel();
int offset = caretModel.getOffset();
context.getDocument().insertString(offset, "{\n}");
caretModel.moveToOffset(offset + 1);
PsiElement elementAt = context.getFile().findElementAt(offset - 1);
context.commitDocument();
DotNetXXXAccessor accessor = PsiTreeUtil.getParentOfType(elementAt, DotNetXXXAccessor.class);
if(accessor != null)
{
CodeStyleManager.getInstance(context.getProject()).reformat(accessor);
}
EditorWriteActionHandler actionHandler = (EditorWriteActionHandler) EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_ENTER);
actionHandler.executeWriteAction(editor, DataManager.getInstance().getDataContext(editor.getContentComponent()));
}
}
});
}
}
}
});
}
private void buildAccessorKeywordsCompletion(CompletionResultSet resultSet, final CSharpXXXAccessorOwner accessorOwner, @Nullable InsertHandler<LookupElement> insertHandler)
{
TokenSet tokenSet = accessorOwner instanceof CSharpEventDeclaration ? TokenSet.create(CSharpSoftTokens.ADD_KEYWORD, CSharpSoftTokens.REMOVE_KEYWORD) : TokenSet.create(CSharpSoftTokens
.GET_KEYWORD, CSharpSoftTokens.SET_KEYWORD);
for(IElementType elementType : tokenSet.getTypes())
{
if(!isCanShowAccessorKeyword(elementType, accessorOwner))
{
continue;
}
LookupElementBuilder builder = LookupElementBuilder.create(CSharpCompletionUtil.textOfKeyword(elementType));
builder = builder.bold();
if(insertHandler != null)
{
builder = builder.withInsertHandler(insertHandler);
}
builder.putUserData(CSharpCompletionUtil.KEYWORD_ELEMENT_TYPE, elementType);
resultSet.addElement(builder);
}
}
private static boolean isCanShowAccessorKeyword(IElementType elementType, CSharpXXXAccessorOwner accessorOwner)
{
DotNetXXXAccessor[] accessors = accessorOwner.getAccessors();
for(DotNetXXXAccessor accessor : accessors)
{
DotNetXXXAccessor.Kind accessorKind = accessor.getAccessorKind();
if(accessorKind == null)
{
continue;
}
IElementType expectedElementType;
switch(accessorKind)
{
case GET:
expectedElementType = CSharpSoftTokens.GET_KEYWORD;
break;
case SET:
expectedElementType = CSharpSoftTokens.SET_KEYWORD;
break;
case ADD:
expectedElementType = CSharpSoftTokens.ADD_KEYWORD;
break;
case REMOVE:
expectedElementType = CSharpSoftTokens.REMOVE_KEYWORD;
break;
default:
continue;
}
if(expectedElementType == elementType)
{
return false;
}
}
return true;
}
}