428e61646f6cdacd2f2657f3d3c04d9cb3d097a7
[idea/community.git] / platform / lang-impl / src / com / intellij / execution / filters / AbstractFileHyperlinkFilter.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.execution.filters;
17
18 import com.intellij.openapi.application.ReadAction;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.roots.ProjectFileIndex;
22 import com.intellij.openapi.util.io.FileUtil;
23 import com.intellij.openapi.vfs.VirtualFile;
24 import com.intellij.util.containers.ContainerUtil;
25 import org.jetbrains.annotations.NotNull;
26 import org.jetbrains.annotations.Nullable;
27 import org.jetbrains.io.LocalFileFinder;
28
29 import java.util.List;
30
31 public abstract class AbstractFileHyperlinkFilter implements Filter {
32   private static final Logger LOG = Logger.getInstance(AbstractFileHyperlinkFilter.class);
33
34   private final Project myProject;
35   private final ProjectFileIndex myFileIndex;
36   private final VirtualFile myBaseDir;
37
38   public AbstractFileHyperlinkFilter(@NotNull Project project, @Nullable String baseDir) {
39     myProject = project;
40     myFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
41     myBaseDir = findDir(baseDir);
42   }
43
44   @Nullable
45   private static VirtualFile findDir(@Nullable String baseDir) {
46     if (baseDir == null) {
47       return null;
48     }
49     return ReadAction.compute(() -> {
50       String path = FileUtil.toSystemIndependentName(baseDir);
51       VirtualFile dir = LocalFileFinder.findFile(path);
52       return dir != null && dir.isValid() && dir.isDirectory() ? dir : null;
53     });
54   }
55
56   @Nullable
57   @Override
58   public final Result applyFilter(String line, int entireLength) {
59     List<FileHyperlinkRawData> links;
60     try {
61       links = parse(line);
62     }
63     catch (RuntimeException e) {
64       LOG.error("Failed to parse '" + line + "' with " + getClass(), e);
65       return null;
66     }
67     List<Filter.ResultItem> items = ContainerUtil.newArrayList();
68     for (FileHyperlinkRawData link : links) {
69       VirtualFile file = findFile(FileUtil.toSystemIndependentName(link.getFilePath()));
70       if (file != null) {
71         OpenFileHyperlinkInfo info = new OpenFileHyperlinkInfo(myProject,
72                                                                file,
73                                                                link.getDocumentLine(),
74                                                                link.getDocumentColumn());
75         boolean grayedHyperLink = isGrayedHyperlink(file);
76         int offset = entireLength - line.length();
77         items.add(new Filter.ResultItem(offset + link.getHyperlinkStartInd(),
78                                         offset + link.getHyperlinkEndInd(),
79                                         info,
80                                         grayedHyperLink));
81       }
82     }
83     return items.isEmpty() ? null : new Result(items);
84   }
85
86   private boolean isGrayedHyperlink(@NotNull VirtualFile file) {
87     return !myFileIndex.isInContent(file) || myFileIndex.isInLibrary(file);
88   }
89
90   @NotNull
91   public abstract List<FileHyperlinkRawData> parse(@NotNull String line);
92
93   @Nullable
94   public VirtualFile findFile(@NotNull String filePath) {
95     VirtualFile file = LocalFileFinder.findFile(filePath);
96     if (file == null && myBaseDir != null) {
97       file = myBaseDir.findFileByRelativePath(filePath);
98     }
99     return file;
100   }
101 }