file url provider: support when line number exceed lines count in a file
[fedora-idea.git] / platform / smRunner / src / com / intellij / execution / testframework / sm / FileUrlProvider.java
blobf559ede447d5ab2c1a09b58f510c25e397415244
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.execution.testframework.sm;
18 import com.intellij.execution.Location;
19 import com.intellij.execution.PsiLocation;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.editor.Document;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.util.io.FileUtil;
24 import com.intellij.openapi.vfs.VirtualFile;
25 import com.intellij.psi.*;
26 import com.intellij.testIntegration.TestLocationProvider;
27 import org.jetbrains.annotations.NonNls;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
31 import java.io.File;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.List;
36 /**
37 * @author Roman Chernyatchik
39 public class FileUrlProvider implements TestLocationProvider {
40 private static final Logger LOG = Logger.getInstance(FileUrlProvider.class.getName());
42 @NonNls private static final String FILE_PROTOCOL_ID = "file";
44 @NotNull
45 public List<Location> getLocation(@NotNull final String protocolId, @NotNull final String path,
46 final Project project) {
48 if (!FILE_PROTOCOL_ID.equals(protocolId)) {
49 return Collections.emptyList();
52 final String normalizedPath = path.replace(File.separatorChar, '/');
54 final int lineNoSeparatorIndex = normalizedPath.lastIndexOf(':');
56 final String filePath;
57 final int lineNumber;
58 // if line is specified
59 if (lineNoSeparatorIndex > 3) { // on Windows, paths start with /C: and that colon is not a line number separator
60 final String lineNumStr = normalizedPath.substring(lineNoSeparatorIndex + 1);
61 int lineNum = 0;
62 try {
63 lineNum = Integer.parseInt(lineNumStr);
64 } catch (NumberFormatException e) {
65 LOG.warn(protocolId + ": Malformed location path: " + path, e);
68 filePath = normalizedPath.substring(0, lineNoSeparatorIndex);
69 lineNumber = lineNum;
70 } else {
71 // unknown line
72 lineNumber = 1;
73 filePath = normalizedPath;
75 // Now we should search file with most suitable path
76 // here path may be absolute or relative
77 final String systemIndependentPath = FileUtil.toSystemIndependentName(filePath);
78 final List<VirtualFile> virtualFiles = TestsLocationProviderUtil.findSuitableFilesFor(systemIndependentPath, project);
79 if (virtualFiles.isEmpty()) {
80 return Collections.emptyList();
83 final List<Location> locations = new ArrayList<Location>(2);
84 for (VirtualFile file : virtualFiles) {
85 locations.add(createLocationFor(project, file, lineNumber));
87 return locations;
90 @Nullable
91 protected static Location createLocationFor(final Project project,
92 @NotNull final VirtualFile virtualFile, final int lineNum) {
93 assert lineNum > 0;
95 final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
96 if (psiFile == null) {
97 return null;
100 final Document doc = PsiDocumentManager.getInstance(project).getDocument(psiFile);
101 if (doc == null) {
102 return null;
105 final int lineCount = doc.getLineCount();
106 final int lineStartOffset;
107 if (lineNum <= lineCount) {
108 lineStartOffset = doc.getLineStartOffset(lineNum - 1);
109 } else {
110 // unknown line
111 lineStartOffset = 0;
114 PsiElement elementAtLine = psiFile.findElementAt(lineStartOffset);
115 if (elementAtLine != null) {
116 // skip whitespaces
117 while (elementAtLine instanceof PsiWhiteSpace) {
118 elementAtLine = elementAtLine.getNextSibling();
121 final PsiElement leafPsiElementAtLine = elementAtLine == null
122 ? null
123 : psiFile.findElementAt(elementAtLine.getTextOffset());
125 return PsiLocation.fromPsiElement(project, leafPsiElementAtLine != null ? leafPsiElementAtLine : psiFile);