--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * 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 com.intellij.execution.filters;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.List;
+
+public abstract class AbstractFileHyperlinkFilter implements Filter {
+ private static final Logger LOG = Logger.getInstance(AbstractFileHyperlinkFilter.class);
+
+ private final Project myProject;
+ private final ProjectFileIndex myFileIndex;
+ private final String myBaseDir;
+
+ public AbstractFileHyperlinkFilter(@NotNull Project project, @Nullable String baseDir) {
+ myProject = project;
+ myFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
+ myBaseDir = baseDir;
+ }
+
+ @Nullable
+ @Override
+ public final Result applyFilter(String line, int entireLength) {
+ List<FileHyperlinkRawData> links;
+ try {
+ links = parse(line);
+ }
+ catch (RuntimeException e) {
+ LOG.error("Failed to process '" + line + "'", e);
+ return null;
+ }
+ List<Filter.ResultItem> items = ContainerUtil.newArrayList();
+ for (FileHyperlinkRawData link : links) {
+ VirtualFile file = findFile(link.getFilePath());
+ if (file != null) {
+ OpenFileHyperlinkInfo info = new OpenFileHyperlinkInfo(myProject,
+ file,
+ link.getDocumentLine(),
+ link.getDocumentColumn());
+ boolean grayedHyperLink = isGrayedHyperlink(file);
+ items.add(new Filter.ResultItem(link.getHyperlinkStartInd(), link.getHyperlinkEndInd(), info, grayedHyperLink));
+ }
+ }
+ return items.isEmpty() ? null : new Result(items);
+ }
+
+ private boolean isGrayedHyperlink(@NotNull VirtualFile file) {
+ return !myFileIndex.isInContent(file) || myFileIndex.isInLibrary(file);
+ }
+
+ @NotNull
+ public abstract List<FileHyperlinkRawData> parse(@NotNull String line);
+
+ @Nullable
+ public VirtualFile findFile(@NotNull String filePath) {
+ File file = findIoFile(filePath);
+ if (file != null) {
+ return LocalFileSystem.getInstance().findFileByIoFile(file);
+ }
+ return null;
+ }
+
+ @Nullable
+ private File findIoFile(@NotNull String filePath) {
+ File file = new File(filePath);
+ if (file.isFile() && file.isAbsolute()) {
+ return file;
+ }
+ if (myBaseDir != null) {
+ file = new File(myBaseDir, filePath);
+ if (file.isFile()) {
+ return file;
+ }
+ }
+ return null;
+ }
+}
import org.jetbrains.annotations.NotNull;
+/**
+ * @deprecated use {@link FileHyperlinkRawData} instead
+ */
public class FileHyperlinkParsedData {
private final String myFilePath;
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * 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 com.intellij.execution.filters;
+
+import org.jetbrains.annotations.NotNull;
+
+public class FileHyperlinkRawData {
+
+ private final String myFilePath;
+ private final int myDocumentLine;
+ private final int myDocumentColumn;
+ private final int myHyperlinkStartInd;
+ private final int myHyperlinkEndInd;
+
+ public FileHyperlinkRawData(@NotNull String filePath,
+ int documentLine,
+ int documentColumn,
+ int hyperlinkStartInd,
+ int hyperlinkEndInd) {
+ myFilePath = filePath;
+ myDocumentLine = documentLine;
+ myDocumentColumn = documentColumn;
+ myHyperlinkStartInd = hyperlinkStartInd;
+ myHyperlinkEndInd = hyperlinkEndInd;
+ }
+
+ @NotNull
+ public String getFilePath() {
+ return myFilePath;
+ }
+
+ public int getDocumentLine() {
+ return myDocumentLine;
+ }
+
+ public int getDocumentColumn() {
+ return myDocumentColumn;
+ }
+
+ public int getHyperlinkStartInd() {
+ return myHyperlinkStartInd;
+ }
+
+ public int getHyperlinkEndInd() {
+ return myHyperlinkEndInd;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FileHyperlinkRawData data = (FileHyperlinkRawData)o;
+
+ return myDocumentLine == data.myDocumentLine &&
+ myDocumentColumn == data.myDocumentColumn &&
+ myHyperlinkStartInd == data.myHyperlinkStartInd &&
+ myHyperlinkEndInd == data.myHyperlinkEndInd &&
+ myFilePath.equals(data.myFilePath);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = myFilePath.hashCode();
+ result = 31 * result + myDocumentLine;
+ result = 31 * result + myDocumentColumn;
+ result = 31 * result + myHyperlinkStartInd;
+ result = 31 * result + myHyperlinkEndInd;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "filePath=" + myFilePath +
+ ", line=" + myDocumentLine +
+ ", column=" + myDocumentColumn +
+ ", hyperlinkStartOffset=" + myHyperlinkStartInd +
+ ", hyperlinkEndOffset=" + myHyperlinkEndInd;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * 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 com.intellij.execution.filters;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public interface FileHyperlinkRawDataFinder {
+ @NotNull
+ List<FileHyperlinkRawData> find(@NotNull String line);
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * 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 com.intellij.execution.filters;
+
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class PatternBasedFileHyperlinkFilter extends AbstractFileHyperlinkFilter implements DumbAware {
+
+ private final PatternBasedFileHyperlinkRawDataFinder myFinder;
+
+ public PatternBasedFileHyperlinkFilter(@NotNull Project project,
+ @Nullable String baseDir,
+ @NotNull PatternBasedFileHyperlinkRawDataFinder finder) {
+ super(project, baseDir);
+ myFinder = finder;
+ }
+
+ @NotNull
+ @Override
+ public List<FileHyperlinkRawData> parse(@NotNull String line) {
+ return myFinder.find(line);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * 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 com.intellij.execution.filters;
+
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+
+public class PatternBasedFileHyperlinkRawDataFinder implements FileHyperlinkRawDataFinder {
+ private static final int UNKNOWN = -2;
+
+ private final PatternHyperlinkFormat[] myLinkFormats;
+
+ public PatternBasedFileHyperlinkRawDataFinder(@NotNull PatternHyperlinkFormat[] linkFormats) {
+ myLinkFormats = linkFormats;
+ }
+
+ @NotNull
+ @Override
+ public List<FileHyperlinkRawData> find(@NotNull String line) {
+ Pair<Matcher, PatternHyperlinkFormat> pair = findMatcher(line);
+ if (pair == null) {
+ return Collections.emptyList();
+ }
+ Matcher matcher = pair.first;
+ PatternHyperlinkFormat format = pair.second;
+ PatternHyperlinkPart[] linkParts = format.getLinkParts();
+ int groupCount = matcher.groupCount();
+ if (groupCount > linkParts.length) {
+ return Collections.emptyList();
+ }
+ String path = null;
+ int lineNumber = -1, columnNumber = -1;
+ int hyperlinkStartInd = -1, hyperlinkEndInd = -1;
+ boolean hyperlinkFreezed = false;
+ for (int i = 1; i <= groupCount; i++) {
+ String value = matcher.group(i);
+ PatternHyperlinkPart part = linkParts[i - 1];
+ if (part == PatternHyperlinkPart.HYPERLINK) {
+ hyperlinkStartInd = matcher.start(i);
+ hyperlinkEndInd = matcher.end(i);
+ hyperlinkFreezed = true;
+ }
+ else if (part == PatternHyperlinkPart.PATH) {
+ path = value;
+ if (!hyperlinkFreezed) {
+ hyperlinkStartInd = matcher.start(i);
+ hyperlinkEndInd = matcher.end(i);
+ }
+ }
+ else if (part == PatternHyperlinkPart.LINE) {
+ value = StringUtil.trimStart(value, ":");
+ lineNumber = StringUtil.parseInt(value, UNKNOWN);
+ hyperlinkEndInd = tryExtendHyperlinkEnd(hyperlinkFreezed, hyperlinkEndInd, matcher.start(i), matcher.end(i));
+ }
+ else if (part == PatternHyperlinkPart.COLUMN) {
+ value = StringUtil.trimStart(value, ":");
+ columnNumber = StringUtil.parseInt(value, UNKNOWN);
+ hyperlinkEndInd = tryExtendHyperlinkEnd(hyperlinkFreezed, hyperlinkEndInd, matcher.start(i), matcher.end(i));
+ }
+ }
+ if (path == null || lineNumber == UNKNOWN || columnNumber == UNKNOWN || hyperlinkStartInd == -1) {
+ return Collections.emptyList();
+ }
+ if (!format.isZeroBasedLine()) {
+ lineNumber--;
+ }
+ if (!format.isZeroBasedColumn()) {
+ columnNumber--;
+ }
+ FileHyperlinkRawData data = new FileHyperlinkRawData(path, lineNumber, columnNumber,
+ hyperlinkStartInd, hyperlinkEndInd);
+ return Collections.singletonList(data);
+ }
+
+ private static int tryExtendHyperlinkEnd(boolean hyperlinkFreezed, int hyperlinkEndInd,
+ int groupStartInd, int groupEndInd) {
+ if (!hyperlinkFreezed && (hyperlinkEndInd == groupStartInd || hyperlinkEndInd + 1 == groupStartInd)) {
+ return groupEndInd;
+ }
+ return hyperlinkEndInd;
+ }
+
+ @Nullable
+ private Pair<Matcher, PatternHyperlinkFormat> findMatcher(@NotNull String line) {
+ for (PatternHyperlinkFormat linkFormat : myLinkFormats) {
+ Matcher matcher = linkFormat.getPattern().matcher(line);
+ if (matcher.matches()) {
+ return Pair.create(matcher, linkFormat);
+ }
+ }
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * 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 com.intellij.execution.filters;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+public class PatternHyperlinkFormat {
+ private final Pattern myPattern;
+ private final boolean myZeroBasedLine;
+ private final boolean myZeroBasedColumn;
+ private final PatternHyperlinkPart[] myLinkParts;
+
+ public PatternHyperlinkFormat(@NotNull Pattern pattern,
+ boolean zeroBasedLine,
+ boolean zeroBasedColumn,
+ @NotNull PatternHyperlinkPart... linkParts) {
+ myPattern = pattern;
+ myZeroBasedLine = zeroBasedLine;
+ myZeroBasedColumn = zeroBasedColumn;
+ myLinkParts = linkParts;
+ }
+
+ @NotNull
+ public Pattern getPattern() {
+ return myPattern;
+ }
+
+ public boolean isZeroBasedLine() {
+ return myZeroBasedLine;
+ }
+
+ public boolean isZeroBasedColumn() {
+ return myZeroBasedColumn;
+ }
+
+ @NotNull
+ public PatternHyperlinkPart[] getLinkParts() {
+ return myLinkParts;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * 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 com.intellij.execution.filters;
+
+public enum PatternHyperlinkPart {
+ HYPERLINK, PATH, LINE, COLUMN
+}