/*
* Copyright (c) 2015-2015 Vladimir Schneider <vladimir.schneider@gmail.com>
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.vladsch.idea.multimarkdown.language;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.ui.JBColor;
import com.intellij.util.ProcessingContext;
import com.vladsch.idea.multimarkdown.MultiMarkdownIcons;
import com.vladsch.idea.multimarkdown.MultiMarkdownLanguage;
import com.vladsch.idea.multimarkdown.MultiMarkdownPlugin;
import com.vladsch.idea.multimarkdown.psi.*;
import com.vladsch.idea.multimarkdown.psi.impl.MultiMarkdownPsiImplUtil;
import com.vladsch.idea.multimarkdown.psi.impl.MultiMarkdownReferenceWikiLinkRef;
import com.vladsch.idea.multimarkdown.spellchecking.SuggestionList;
import com.vladsch.idea.multimarkdown.util.*;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.List;
import static com.vladsch.idea.multimarkdown.psi.MultiMarkdownTypes.*;
public class MultiMarkdownCompletionContributor extends CompletionContributor {
private static final Logger logger = Logger.getLogger(MultiMarkdownCompletionContributor.class);
public static final String DUMMY_IDENTIFIER = "\u001F";
@Override
public void beforeCompletion(@NotNull CompletionInitializationContext context) {
context.setDummyIdentifier(DUMMY_IDENTIFIER);
}
public MultiMarkdownCompletionContributor() {
extend(CompletionType.BASIC,
PlatformPatterns.psiElement(PsiElement.class).withLanguage(MultiMarkdownLanguage.INSTANCE),
new CompletionProvider<CompletionParameters>() {
public void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet resultSet) {
PsiElement elementPos = parameters.getPosition();
int offset = parameters.getOffset();
//logger.info("Completion for " + element + " at pos " + String.valueOf(offset));
PsiElement element = elementPos;
while (element instanceof LeafPsiElement) {
element = element.getParent();
}
IElementType elementType = element.getNode().getElementType();
if (elementType == WIKI_LINK_TEXT) {
PsiElement parent = element.getParent();
while (parent != null && !(parent instanceof MultiMarkdownWikiLink) && !(parent instanceof MultiMarkdownFile)) {
parent = parent.getParent();
}
if (parent != null && parent instanceof MultiMarkdownWikiLink) {
SuggestionList suggestionList = ElementNameSuggestionProvider.getLinkTextSuggestions(parent, false);
for (String suggestion : suggestionList.asList()) {
resultSet.addElement(LookupElementBuilder.create(suggestion)
.withCaseSensitivity(true)
);
}
}
} else if (elementType == WIKI_LINK_REF) {
Document document = parameters.getEditor().getDocument();
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
if (virtualFile != null) {
Project fileProject = parameters.getEditor().getProject();
if (fileProject != null) {
ProjectFileRef containingFile = new ProjectFileRef(virtualFile, fileProject);
GitHubLinkResolver resolver = new GitHubLinkResolver(containingFile);
String linkRefText = MultiMarkdownPsiImplUtil.getLinkRefText(element);
int uriLinks = LinkResolver.ANY;
LinkRef linkRef;
String fullPath = "";
linkRef = new WikiLinkRef(containingFile, fullPath, null, null);
String gitHubRepoPath = resolver.getProjectResolver().vcsRepoBasePath(linkRef.getContainingFile());
if (gitHubRepoPath == null) gitHubRepoPath = resolver.getProjectBasePath();
List<PathInfo> matchedFiles = resolver.multiResolve(linkRef, uriLinks | LinkResolver.LOOSE_MATCH, null);
for (PathInfo pathInfo : matchedFiles) {
String linkRefAddress = uriLinks != LinkResolver.ANY ? pathInfo.getFilePath() : resolver.linkAddress(linkRef, pathInfo, !pathInfo.isWikiPageExt(), null, null);
if (!linkRefAddress.equals("#") && !linkRefAddress.isEmpty()) {
String linkRefFileName = linkRefAddress;
Icon icon;
FileRef fileRef;
if (pathInfo instanceof FileRef) {
fileRef = (FileRef) pathInfo;
} else {
assert pathInfo instanceof LinkRef && pathInfo.isURI();
fileRef = ((LinkRef) pathInfo).getTargetRef();
}
if (fileRef != null) {
linkRefFileName = PathInfo.relativePath(gitHubRepoPath, fileRef.getFilePath(), false);
if (fileRef.isWikiPage()) icon = MultiMarkdownIcons.WIKI;
else if (fileRef.isMarkdownExt()) icon = MultiMarkdownIcons.FILE;
else {
Project project = resolver.getProject();
PsiFile psiFile = project == null ? null : fileRef.psiFile(project);
icon = psiFile == null ? null : psiFile.getIcon(0);
}
} else {
// must be a github link
icon = MultiMarkdownIcons.GITHUB;
}
LookupElementBuilder lookupElementBuilder = LookupElementBuilder.create(linkRefAddress).withCaseSensitivity(true);
if (icon != null) lookupElementBuilder = lookupElementBuilder.withIcon(icon);
if (!linkRefAddress.equals(linkRefFileName)) lookupElementBuilder = lookupElementBuilder.withTypeText(linkRefFileName, false);
if (linkRef instanceof WikiLinkRef && linkRefAddress.contains("/")) {
// TODO: get the color from color settings
lookupElementBuilder = lookupElementBuilder.withItemTextForeground(JBColor.RED);
}
resultSet.addElement(lookupElementBuilder);
}
}
}
}
} else if (elementType == WIKI_LINK_REF_ANCHOR) {
MultiMarkdownWikiLinkRef pageRef = (MultiMarkdownWikiLinkRef) MultiMarkdownPsiImplUtil.findChildByType(element.getParent(), MultiMarkdownTypes.WIKI_LINK_REF);
MultiMarkdownReferenceWikiLinkRef pageRefRef = pageRef == null ? null : (MultiMarkdownReferenceWikiLinkRef) pageRef.getReference();
if (pageRefRef != null && !pageRefRef.isResolveRefMissing()) {
MultiMarkdownFile markdownFile = (MultiMarkdownFile) pageRefRef.resolve();
if (markdownFile != null) {
// TODO: 2015-10-25 add list of anchors when anchor parsing is implemented
}
}
}
}
}
);
}
}