下面列出了com.intellij.psi.util.PsiTreeUtil#prevVisibleLeaf ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
void runInvoke(@NotNull Project project, @NotNull PsiLocalOpen parentElement) {
// parentElement is the scope: Module.Module «( ... )»
RmlTypes types = RmlTypes.INSTANCE;
PsiElement grandParentElement = parentElement.getParent();
// Extract the module path (and remove path nodes)
String modulePath = "";
PsiElement sibling = PsiTreeUtil.prevVisibleLeaf(parentElement);
while (sibling != null && (sibling.getNode().getElementType() == types.UIDENT || sibling.getNode().getElementType() == types.DOT)) {
ASTNode currentNode = sibling.getNode();
if (!modulePath.isEmpty() || currentNode.getElementType() != types.DOT) {
modulePath = sibling.getText() + modulePath;
}
sibling = PsiTreeUtil.prevVisibleLeaf(sibling);
grandParentElement.getNode().removeChild(currentNode);
}
String text = parentElement.getText();
PsiElement newOpen = ORCodeFactory.createExpression(project, "{ open " + modulePath + "; " + text.substring(1, text.length() - 1) + "; }");
if (newOpen != null) {
grandParentElement.getNode().replaceChild(parentElement.getNode(), newOpen.getNode());
}
}
@Nullable
private String getTypeDocumentation(PsiElement element, GraphQLTypeDefinitionRegistryServiceImpl typeRegistryService, GraphQLSchema schema, GraphQLTypeNameDefinition parent) {
graphql.schema.GraphQLType schemaType = schema.getType(((GraphQLNamedElement) element).getName());
if (schemaType != null) {
final StringBuilder html = new StringBuilder().append(DEFINITION_START);
PsiElement keyword = PsiTreeUtil.prevVisibleLeaf(parent);
if (keyword != null) {
html.append(keyword.getText()).append(" ");
}
html.append(element.getText());
html.append(DEFINITION_END);
final String description = typeRegistryService.getTypeDescription(schemaType);
if (description != null) {
html.append(CONTENT_START);
html.append(GraphQLDocumentationMarkdownRenderer.getDescriptionAsHTML(description));
html.append(CONTENT_END);
}
return html.toString();
}
return null;
}
private PsiElement findPreviousLeaf(PsiElement start, IElementType typeToFind, TokenSet skipping) {
PsiElement result = PsiTreeUtil.prevVisibleLeaf(start);
while (result != null) {
if (result instanceof PsiWhiteSpace || result instanceof PsiComment) {
result = PsiTreeUtil.prevVisibleLeaf(result);
continue;
}
if (result.getNode().getElementType() == typeToFind) {
return result;
}
if (!skipping.contains(result.getNode().getElementType())) {
// not allowed
return null;
}
result = PsiTreeUtil.prevVisibleLeaf(result);
}
return null;
}
@NotNull
protected String extractPathName(@NotNull PsiElement element, @NotNull ORTypes types) {
String path = "";
PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(element);
if (prevLeaf != null && prevLeaf.getNode().getElementType() == types.DOT) {
// Extract the qualified name of current element
PsiElement prevSibling = prevLeaf.getPrevSibling();
if (prevSibling instanceof PsiNamedElement) {
String name = ((PsiNamedElement) prevSibling).getName();
path = name == null ? "" : name;
prevSibling = prevSibling.getPrevSibling();
}
while (prevSibling != null && prevSibling.getNode().getElementType() == types.DOT) {
prevSibling = prevSibling.getPrevSibling();
if (prevSibling instanceof PsiNamedElement) {
path = ((PsiNamedElement) prevSibling).getName() + "." + path;
prevSibling = prevSibling.getPrevSibling();
} else {
break;
}
}
}
return path;
}
private void completeTopLevelKeywords() {
CompletionProvider<CompletionParameters> provider = new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull final CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
final LogicalPosition completionPos = parameters.getEditor().offsetToLogicalPosition(parameters.getOffset());
final PsiElement prevVisibleLeaf = PsiTreeUtil.prevVisibleLeaf(parameters.getPosition());
if (prevVisibleLeaf != null) {
// NOTE: "type Foo <completion>" would grammatically allow a new definition to follow immediately
// but this completion at that position is likely to be unexpected and would interfere with "implements" on types
// so we expect top level keywords to be the first visible element on the line to complete
if (completionPos.line == parameters.getEditor().offsetToLogicalPosition(prevVisibleLeaf.getTextOffset()).line) {
return;
}
}
for (String keyword : TOP_LEVEL_KEYWORDS) {
// TODO filter schema if already declared
LookupElementBuilder element = LookupElementBuilder.create(keyword).withBoldness(true);
if (keyword.equals("{")) {
element = element.withInsertHandler((ctx, item) -> {
EditorModificationUtil.insertStringAtCaret(ctx.getEditor(), "}");
PsiDocumentManager.getInstance(ctx.getProject()).commitDocument(ctx.getEditor().getDocument());
ctx.getEditor().getCaretModel().moveCaretRelatively(-1, 0, false, false, false);
});
} else {
element = element.withInsertHandler(AddSpaceInsertHandler.INSTANCE_WITH_AUTO_POPUP);
}
result.addElement(element);
}
}
};
extend(CompletionType.BASIC, TOP_LEVEL_KEYWORD_PATTERN, provider);
}
private JSGraphQLEndpointNamedTypePsiElement getUnknownNamedType(PsiElement element) {
if (element instanceof PsiWhiteSpace || element.getNode().getElementType() == JSGraphQLEndpointTokenTypes.RPAREN) {
// lean left in case there's a quick-fix possibility before the cursor
element = PsiTreeUtil.prevVisibleLeaf(element);
}
if (element != null && element.getParent() instanceof JSGraphQLEndpointNamedTypePsiElement) {
PsiReference reference = element.getParent().getReference();
if (reference != null && reference.resolve() == null) {
return (JSGraphQLEndpointNamedTypePsiElement) element.getParent();
}
}
return null;
}
private boolean isFoldableBlock(ASTNode node, IElementType keyword) {
if (node.getElementType() == LOGICAL_BLOCK_ELEMENT) {
final PsiElement prev = PsiTreeUtil.prevVisibleLeaf(node.getPsi());
return prev != null
&& prev.getNode().getElementType() == keyword;
}
return false;
}
@Nullable
static IElementType getPrevNodeType(@NotNull PsiElement element) {
PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(element);
return prevLeaf == null ? null : prevLeaf.getNode().getElementType();
}
public JSGraphQLEndpointCompletionContributor() {
CompletionProvider<CompletionParameters> provider = new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull final CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
final PsiFile file = parameters.getOriginalFile();
if (!(file instanceof JSGraphQLEndpointFile)) {
return;
}
final boolean autoImport = parameters.isExtendedCompletion() || parameters.getCompletionType() == CompletionType.SMART;
final PsiElement completionElement = Optional.ofNullable(parameters.getOriginalPosition()).orElse(parameters.getPosition());
if (completionElement != null) {
final PsiElement parent = completionElement.getParent();
final PsiElement leafBeforeCompletion = PsiTreeUtil.prevVisibleLeaf(completionElement);
// 1. complete on interface name after IMPLEMENTS token
if (completeImplementableInterface(result, autoImport, completionElement, leafBeforeCompletion)) {
return;
}
// 2. import file
if (completeImportFile(result, file, parent)) {
return;
}
// 3.A. top level completions, e.g. keywords and definition annotations
if (completeKeywordsAndDefinitionAnnotations(result, autoImport, completionElement, leafBeforeCompletion, parent)) {
return;
}
// 3.B. implements when type definition surrounds completion element (e.g. when it has a FieldDefinitionSet)
if (completeImplementsInsideTypeDefinition(result, completionElement, parent)) {
return;
}
// 4. completions inside FieldDefinitionSet
final JSGraphQLEndpointFieldDefinitionSet fieldDefinitionSet = PsiTreeUtil.getParentOfType(completionElement, JSGraphQLEndpointFieldDefinitionSet.class);
if (fieldDefinitionSet != null) {
// 4.A. field/argument type completion
if (completeFieldOrArgumentType(result, autoImport, completionElement)) {
return;
}
// 4.B. annotations
if (completeAnnotations(result, autoImport, file, completionElement)) {
return;
}
// 4.C. annotation arguments
if (completeAnnotationArguments(result, file, completionElement, leafBeforeCompletion)) {
return;
}
// 4.D. override for interface fields
if (completeOverrideFields(fieldDefinitionSet, completionElement, result)) {
return;
}
}
// 5. completions inside SchemaDefinition
if (completeInsideSchemaDefinition(result, completionElement, leafBeforeCompletion)) {
return;
}
}
}
};
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), provider);
extend(CompletionType.SMART, PlatformPatterns.psiElement(), provider);
}
public static void completeKeywordQualified(@NotNull final PsiElement position, @NotNull final CompletionResultSet result) {
final PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(position);
if (prevLeaf != null && prevLeaf.getText().equals("import")) {
result.addElement(LookupElementUtil.fromString("qualified "));
}
}