[diff] IDEA-77540 Go To Source from vcs diff

Go To Source uses the getOpenFileDescriptor() returned by DiffContent,
but it is null for BinaryContent & SimpleContent,
both used from different places of the VCS history.

* Implement it for BinaryContent:
  - get the file by path if exists
  - supply the Project to the constructor, deprecate other constructors.

* SimpleContent is too general thing and is used everywhere,
  so for certain VCS operations create a separate extension -
  OpenFileCapableSimpleContent which behaves the same way: searches
  the virtual file by path.

KNOWN LIMITATION:
current implementation navigates to the same offset,
no conversion is made if the file is different from the current
version.
This commit is contained in:
Kirill Likhodedov
2014-01-13 17:02:29 +04:00
parent 3eb73154bf
commit 5f44d7781f
5 changed files with 85 additions and 17 deletions
@@ -20,6 +20,8 @@ import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.UIBasedFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -34,9 +36,10 @@ import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
/**
* Represents bytes as content. May has text representaion.
* A {@link DiffContent} represented as a byte array. It still contain a text though.
*/
public class BinaryContent extends DiffContent {
@NotNull private final Project myProject;
@NotNull
private final FileType myFileType;
private final byte[] myBytes;
@@ -45,11 +48,12 @@ public class BinaryContent extends DiffContent {
private String myFilePath;
/**
* @param charset use to convert bytes to String. null means bytes can't be converted to text.
* Has no sense if fileType.isBinary()
* @param charset use to convert bytes to String. null means bytes can't be converted to text. Has no sense if fileType.isBinary()
* @param fileType type of content
*/
public BinaryContent(byte[] bytes, Charset charset, @NotNull FileType fileType) {
public BinaryContent(@NotNull Project project, byte[] bytes, @Nullable Charset charset, @NotNull FileType fileType,
@Nullable String filePath) {
myProject = project;
myFileType = fileType;
myBytes = bytes;
if (fileType.isBinary()) {
@@ -58,11 +62,21 @@ public class BinaryContent extends DiffContent {
else {
myCharset = charset;
}
myFilePath = filePath;
}
/**
* @deprecated to remove in IDEA 14. Use {@link #BinaryContent(Project, byte[], Charset, FileType, String)}.
*/
public BinaryContent(byte[] bytes, Charset charset, @NotNull FileType fileType) {
this(bytes, charset, fileType, null);
}
/**
* @deprecated to remove in IDEA 14. Use {@link #BinaryContent(Project, byte[], Charset, FileType, String)}.
*/
public BinaryContent(byte[] bytes, Charset charset, @NotNull FileType fileType, String filePath) {
this(bytes, charset, fileType);
myFilePath = filePath;
this(ProjectManager.getInstance().getDefaultProject(), bytes, charset, fileType, filePath);
}
@Override
@@ -95,19 +109,22 @@ public class BinaryContent extends DiffContent {
return myDocument;
}
/**
* @return null
*/
@Override
public OpenFileDescriptor getOpenFileDescriptor(int offset) {
return null;
VirtualFile file = findVirtualFile();
return file == null ? null : new OpenFileDescriptor(myProject, file, offset);
}
@Nullable
private VirtualFile findVirtualFile() {
return LocalFileSystem.getInstance().findFileByIoFile(new File(myFilePath));
}
@Override
@Nullable
public VirtualFile getFile() {
if (myFileType instanceof UIBasedFileType) {
final VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(myFilePath));
final VirtualFile file = findVirtualFile();
if (file != null) {
final LightVirtualFile lightFile = new LightVirtualFile(file, new String(myBytes), 1);
lightFile.setOriginalFile(file);
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2014 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.diff;
import com.intellij.openapi.diff.SimpleContent;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A {@link SimpleContent} which content is retrieved from a file which exists or existed in the project.
*/
public class FileAwareSimpleContent extends SimpleContent {
@NotNull private final Project myProject;
@NotNull private final FilePath myFilePath;
public FileAwareSimpleContent(@NotNull Project project, @NotNull FilePath filePath, @NotNull String text, @Nullable FileType type) {
super(text, type);
myProject = project;
myFilePath = filePath;
}
@Override
public OpenFileDescriptor getOpenFileDescriptor(int offset) {
VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(myFilePath.getIOFile());
return file == null ? null : new OpenFileDescriptor(myProject, file, offset);
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.vcs.actions;
import com.intellij.diff.FileAwareSimpleContent;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diff.*;
import com.intellij.openapi.editor.Document;
@@ -86,7 +87,7 @@ public abstract class DiffActionExecutor {
if (content == null) {
throw new VcsException("Failed to load content");
}
return new SimpleContent(content, mySelectedFile.getFileType());
return new FileAwareSimpleContent(myProject, fileRevision.getFile(), content, mySelectedFile.getFileType());
}
return null;
}
@@ -16,6 +16,7 @@
package com.intellij.openapi.vcs.changes.actions;
import com.intellij.CommonBundle;
import com.intellij.diff.FileAwareSimpleContent;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.DiffContent;
@@ -150,8 +151,9 @@ public class ChangeDiffRequestPresentable implements DiffRequestPresentable {
final VirtualFile vFile = current.getVirtualFile();
return vFile != null ? new FileContent(myProject, vFile) : new SimpleContent("");
}
FilePath filePath = revision.getFile();
if (revision instanceof BinaryContentRevision) {
final String name = revision.getFile().getName();
final String name = filePath.getName();
try {
return FileContent.createFromTempFile(myProject, name, name, ((BinaryContentRevision)revision).getBinaryContent());
}
@@ -188,8 +190,8 @@ public class ChangeDiffRequestPresentable implements DiffRequestPresentable {
}
SimpleContent content = revisionContent == null
? new SimpleContent("")
: new SimpleContent(revisionContent, revision.getFile().getFileType());
VirtualFile vFile = revision.getFile().getVirtualFile();
: new FileAwareSimpleContent(myProject, filePath, revisionContent, filePath.getFileType());
VirtualFile vFile = filePath.getVirtualFile();
if (vFile != null) {
content.setCharset(vFile.getCharset());
content.setBOM(vFile.getBOM());
@@ -186,9 +186,9 @@ public class VcsHistoryUtil {
return CharsetToolkit.bytesToString(bytes, e.getDefaultCharset());
}
private static DiffContent createContent(Project project, byte[] content1, VcsFileRevision revision, Document doc, Charset charset, FileType fileType, String filePath) {
private static DiffContent createContent(@NotNull Project project, byte[] content1, VcsFileRevision revision, Document doc, Charset charset, FileType fileType, String filePath) {
if (isCurrent(revision) && (doc != null)) { return new DocumentContent(project, doc); }
return new BinaryContent(content1, charset, fileType, filePath);
return new BinaryContent(project, content1, charset, fileType, filePath);
}
private static boolean isCurrent(VcsFileRevision revision) {