/*
* 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.daemon.RelatedItemLineMarkerInfo;
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
import com.intellij.ide.util.PsiElementListCellRenderer;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
import com.intellij.util.NullableFunction;
import com.vladsch.idea.multimarkdown.MultiMarkdownBundle;
import com.vladsch.idea.multimarkdown.MultiMarkdownIcons;
import com.vladsch.idea.multimarkdown.psi.MultiMarkdownFile;
import com.vladsch.idea.multimarkdown.psi.MultiMarkdownWikiLinkRef;
import com.vladsch.idea.multimarkdown.psi.impl.MultiMarkdownReference;
import com.vladsch.idea.multimarkdown.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collection;
public class MultiMarkdownLineMarkerProvider extends RelatedItemLineMarkerProvider {
@Override
protected void collectNavigationMarkers(@NotNull final PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) {
if (element instanceof MultiMarkdownWikiLinkRef) {
PsiReference psiReference = element.getReference();
// incompleteCode in our case means looseMatch criteria, otherwise precise match as per repo rules
final ResolveResult[] results = psiReference != null ? ((MultiMarkdownReference) psiReference).multiResolve(false) : null;
if (results != null && results.length > 0) {
final PsiFile containingFile = element.getContainingFile();
final GitHubLinkResolver resolver = new GitHubLinkResolver(containingFile);
NullableFunction<PsiElement, String> namer = new NullableFunction<PsiElement, String>() {
@Nullable
@Override
public String fun(PsiElement element) {
return resolver.linkAddress(new FileRef((PsiFile) element), null, null, null);
}
};
final Project project = element.getProject();
final String basePath = project.getBasePath() == null ? "/" : StringUtilKt.suffixWith(project.getBasePath(), '/');
if (results.length > 0) {
final ArrayList<PsiFile> linkTargets = new ArrayList<PsiFile>();
Icon icon = null;
for (ResolveResult resolveResult : results) {
if (resolveResult.getElement() instanceof PsiFile && !((results.length == 1 || results.length != 2) && resolveResult.getElement() == containingFile)) {
PsiFile file = (PsiFile) resolveResult.getElement();
if (icon == null) icon = file.getIcon(0);
linkTargets.add(file);
}
}
if (linkTargets.size() > 0) {
if (linkTargets.size() > 1) icon = MultiMarkdownIcons.MULTI_WIKI;
PsiElementListCellRenderer cellRenderer = new PsiElementListCellRenderer<PsiElement>() {
@Override
public String getElementText(PsiElement fileElement) {
if (fileElement instanceof PsiFile) {
FileRef fileRef = new FileRef((PsiFile) fileElement);
if (fileRef.isUnderWikiDir() && results.length > 1) {
// need subdirectory and extension, there is more than one match
return PathInfo.relativePath(StringUtilKt.suffixWith(fileRef.getWikiDir(), '/'), fileRef.getFilePath(), false);
} else {
return new GitHubLinkResolver(containingFile).linkAddress(fileRef, null, null, null);
}
}
return "<unknown>";
}
protected Icon getIcon(PsiElement element) {
boolean firstItem = element == linkTargets.get(0);
boolean isWikiPage = element instanceof MultiMarkdownFile && ((MultiMarkdownFile) element).isWikiPage();
return firstItem || !(element instanceof MultiMarkdownFile) ? element.getIcon(0) : (isWikiPage ? MultiMarkdownIcons.HIDDEN_WIKI : MultiMarkdownIcons.HIDDEN_FILE);
}
@Nullable
@Override
protected String getContainerText(PsiElement element, String name) {
if (element instanceof PsiFile) {
FileRef fileRef = new FileRef((PsiFile) element);
String repoDir;
if (fileRef.isUnderWikiDir()) {
repoDir = fileRef.getWikiDir();
} else {
repoDir = fileRef.getPath();
}
return PathInfo.relativePath(basePath, repoDir, false);
}
return null;
}
@Override
protected int getIconFlags() {
return Iconable.ICON_FLAG_READ_STATUS;
}
};
if (icon == null) icon = MultiMarkdownIcons.FILE;
NavigationGutterIconBuilder<PsiElement> builder =
NavigationGutterIconBuilder.create(icon)
.setCellRenderer(cellRenderer)
.setTargets(linkTargets)
.setNamer(namer)
.setTooltipText(MultiMarkdownBundle.message("linemarker.navigate-to"));
result.add(builder.createLineMarkerInfo(element));
}
}
}
}
}
}