Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.osgi.service.debug.DebugOptions;
Expand Down Expand Up @@ -720,6 +721,12 @@ private boolean openUnifiedDiff(UnifiedDiffSource source, CompareEditorInput inp
closeIfOpenedHere(wpage, openedHere);
return false;
}
// A side that is not a workspace file, the version shown for a deleted file
// for example, is only worth overlaying when its content really loaded.
if (!(source.editorInput() instanceof IFileEditorInput) && !hasContent(textEditor)) {
closeIfOpenedHere(wpage, openedHere);
return false;
}
Action openTwoWayCompare = createOpenTwoWayCompareAction(input, page, editor, activate, textEditor);
IStatus status = UnifiedDiff.create(textEditor, source.diffSource(), source.mode())
.additionalActions(Arrays.asList(openTwoWayCompare))
Expand All @@ -744,6 +751,11 @@ private boolean openUnifiedDiff(UnifiedDiffSource source, CompareEditorInput inp
return false;
}

private static boolean hasContent(ITextEditor editor) {
IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput());
return document != null && document.getLength() > 0;
}

private static void closeIfOpenedHere(IWorkbenchPage page, IEditorPart editor) {
if (editor != null) {
// Nothing here writes to the document, so there is nothing to save.
Expand Down Expand Up @@ -897,17 +909,31 @@ private static UnifiedDiffCandidate unifiedDiffCandidateOf(CompareEditorInput in
// plain left-vs-right overlay.
ITypedElement left = compareInput.getLeft();
ITypedElement right = compareInput.getRight();
// Only the side shown in the editor has to be a workspace file; an editor
// opened on anything else, a revision for example, comes up empty. The other
// side merely supplies the diff source and may be missing entirely, as for a
// newly added file.
if (documentKeyOf(left) instanceof IFileEditorInput leftEditorInput) {
IEditorInput leftEditorInput = documentKeyOf(left);
IEditorInput rightEditorInput = documentKeyOf(right);
// The side shown in the editor is preferably a workspace file; an editor opened
// on anything else, a revision for example, comes up empty. The other side
// merely supplies the diff source and may be missing entirely, as for a newly
// added file.
if (leftEditorInput instanceof IFileEditorInput) {
return new UnifiedDiffCandidate(compareInput, leftEditorInput, left, UnifiedDiffMode.REVERT_MODE, right);
}
if (documentKeyOf(right) instanceof IFileEditorInput rightEditorInput) {
if (rightEditorInput instanceof IFileEditorInput) {
return new UnifiedDiffCandidate(compareInput, rightEditorInput, right,
UnifiedDiffMode.OVERLAY_READ_ONLY_MODE, left);
}
// A deleted file leaves no workspace file to overlay. The version that still
// exists is then shown read-only, with its whole content marked as removed.
// Two sides that both exist are left to the classic compare editor, because
// neither of them is the state on disk.
if (rightEditorInput != null && isAbsent(left)) {
return new UnifiedDiffCandidate(compareInput, rightEditorInput, right,
UnifiedDiffMode.OVERLAY_READ_ONLY_MODE, left);
}
if (leftEditorInput != null && isAbsent(right)) {
return new UnifiedDiffCandidate(compareInput, leftEditorInput, left,
UnifiedDiffMode.OVERLAY_READ_ONLY_MODE, right);
}
return null;
}

Expand Down Expand Up @@ -953,6 +979,21 @@ private static record UnifiedDiffCandidate(ICompareInput compareInput, IEditorIn
ITypedElement element, UnifiedDiffMode mode, ITypedElement diffSource) {
}

/**
* Returns whether the given side does not exist, as the workspace file of a
* deleted resource or the previous version of an added file. Answered from the
* element alone, so that picking a candidate stays free of content reads.
*/
private static boolean isAbsent(ITypedElement element) {
// null, or an element that only names the file
if (!(element instanceof IStreamContentAccessor)) {
return true;
}
IResource resource = element instanceof IResourceProvider provider ? provider.getResource()
: Adapters.adapt(element, IResource.class);
return resource != null && !resource.exists();
}

private static IEditorInput documentKeyOf(ITypedElement element) {
if (element == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public HideAllDiffsRunnable(ITextViewer tv, IAnnotationModel model) {

public HideAllDiffsRunnable(ITextEditor textEditor) {
this.tv = textEditor.getAdapter(ITextViewer.class);
this.model = textEditor.getDocumentProvider().getAnnotationModel(textEditor.getEditorInput());
this.model = UnifiedDiffManager.annotationModelOf(textEditor);
}

public String getLabel() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.codemining.ICodeMining;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.AnnotationModel;
import org.eclipse.jface.text.source.AnnotationModelEvent;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.jface.text.source.IAnnotationModelListener;
import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.ISourceViewerExtension5;
import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
Expand Down Expand Up @@ -130,20 +132,49 @@ public static List<UnifiedDiff> get(ITextViewer viewer) {
return diffsByViewer.get(viewer);
}

/**
* Returns the annotation model the diffs of the given editor live in, or
* <code>null</code> when it has none. The document provider of an editor on
* something other than a workspace file, a revision for example, supplies no
* model, so the one installed on the viewer is used.
*/
public static IAnnotationModel annotationModelOf(ITextEditor editor) {
IAnnotationModel model = editor.getDocumentProvider().getAnnotationModel(editor.getEditorInput());
if (model != null) {
return model;
}
return editor.getAdapter(ITextViewer.class) instanceof ISourceViewer sourceViewer
? sourceViewer.getAnnotationModel()
: null;
}

/**
* Installs an annotation model on the viewer of an editor whose document
* provider has none, so that the diffs have somewhere to be shown.
*/
private static IAnnotationModel installAnnotationModel(ITextViewer viewer, IDocument document) {
if (document == null || !(viewer instanceof ISourceViewer sourceViewer)) {
return null;
}
sourceViewer.setDocument(document, new AnnotationModel());
return sourceViewer.getAnnotationModel();
}

public static IStatus open(ITextEditor editor, String source, UnifiedDiffMode mode, List<Action> additionalActions,
TokenComparatorFactory tokenComparatorFactory,
IgnoreWhitespaceContributorFactory ignoreWhitespaceContributorFactory, boolean ignoreWhiteSpace) {
ITextViewer viewer = editor.getAdapter(ITextViewer.class);
if (viewer instanceof ProjectionViewer pv) {
pv.doOperation(ProjectionViewer.EXPAND_ALL);
}
IAnnotationModel model = editor.getDocumentProvider().getAnnotationModel(editor.getEditorInput());
IDocument leftDocument = editor.getDocumentProvider().getDocument(editor.getEditorInput());
IAnnotationModel editorModel = annotationModelOf(editor);
IAnnotationModel model = editorModel != null ? editorModel : installAnnotationModel(viewer, leftDocument);
if (model == null) {
return Status.CANCEL_STATUS;
}
clearAll(viewer, model);

IDocument leftDocument = editor.getDocumentProvider().getDocument(editor.getEditorInput());
IDocument rightDocument = new Document(source);

List<UnifiedDiff> unifiedDiffs;
Expand Down
Loading
Loading