Skip to content

Commit

Permalink
allow comparing two commits in a raw diff
Browse files Browse the repository at this point in the history
The history view is missing a way to compare two commits without having
to iterate through the changed files. This change adds a "Show Diff"
context menu entry when two commits are selected and opens an editor
with the corresponding git diff.
  • Loading branch information
nittka committed Jan 31, 2020
1 parent df4a5a1 commit 3a15bd9
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 3 deletions.
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -9,6 +9,10 @@ If you select specialized import wizards, you need to select the maven wizard bu

This plugin adds an Import Maven Project entry to the context menu (for the repository and the Working Tree).

## Show Diff for two commits

The "Compare with each other" feature is nice but sometimes you want to see the diff without having to navigate through every single file, e.g. when reviewing version updates in many pom files.

## open extern

We found the openextern plugin very useful.
Expand Down
11 changes: 9 additions & 2 deletions de.nittka.tooling.egit/META-INF/MANIFEST.MF
Expand Up @@ -8,5 +8,12 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.core.commands,
org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.egit.ui;bundle-version="5.6.0"
Export-Package: de.nittka.tooling.egit.mavenimport
org.eclipse.egit.ui;bundle-version="5.6.0",
org.eclipse.egit.core,
org.eclipse.jface.text,
org.eclipse.ui.ide,
org.eclipse.ui.editors,
org.eclipse.core.resources,
org.eclipse.jgit
Export-Package: de.nittka.tooling.egit.diff,
de.nittka.tooling.egit.mavenimport
43 changes: 42 additions & 1 deletion de.nittka.tooling.egit/plugin.xml
Expand Up @@ -9,6 +9,12 @@
name="Import Maven Project"
>
</command>
<command
categoryId="org.eclipse.egit.ui.commandCategory"
id="de.nittka.tooling.egit.ShowRawCommitDiff"
name="Show Diff"
>
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
Expand Down Expand Up @@ -39,6 +45,22 @@
</and>
</activeWhen>
</handler>
<handler
commandId="de.nittka.tooling.egit.ShowRawCommitDiff">
<class
class="de.nittka.tooling.egit.diff.DiffCommand">
</class>
<activeWhen>
<and>
<count
value="2">
</count>
<iterate>
<instanceof value="org.eclipse.egit.core.internal.IRepositoryCommit" />
</iterate>
</and>
</activeWhen>
</handler>
</extension>
<extension
point="org.eclipse.ui.menus">
Expand All @@ -51,5 +73,24 @@
<visibleWhen checkEnabled="true" />
</command>
</menuContribution>
<menuContribution
locationURI="popup:org.eclipse.egit.ui.historyPageContributions?after=history.group">
<command
commandId="de.nittka.tooling.egit.ShowRawCommitDiff"
label="Show Diff"
style="push">
<visibleWhen checkEnabled="true" />
</command>
</menuContribution>

</extension>
<extension
point="org.eclipse.ui.editors">
<editor
class="de.nittka.tooling.egit.diff.DiffEditor"
default="false"
id="de.nittka.tooling.egit.diffeditor"
name="DiffEditor">
</editor>
</extension>
</plugin>
</plugin>
@@ -0,0 +1,52 @@

package de.nittka.tooling.egit.diff;

import java.util.List;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.egit.core.internal.IRepositoryCommit;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.statushandlers.StatusManager;

public class DiffCommand extends AbstractHandler {

@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
ISelection selection = HandlerUtil.getCurrentSelectionChecked(event);
if (selection instanceof IStructuredSelection) {
List<?> list = ((IStructuredSelection) selection).toList();
if(list.size()==2) {
Object c1 = list.get(0);
Object c2 = list.get(1);
if(c1 instanceof IRepositoryCommit && c2 instanceof IRepositoryCommit) {
showDiff((IRepositoryCommit)c1,(IRepositoryCommit) c2);
}
}
}
return null;
}

private void showDiff(IRepositoryCommit c1, IRepositoryCommit c2) {
DiffEditorInput editorInuput = new DiffEditorInput(c1, c2);
IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
try {
IDE.openEditor(page, editorInuput, "de.nittka.tooling.egit.diffeditor");
} catch (PartInitException e) {
IStatus status = new Status(IStatus.ERROR, "de.nittka.tooling.egit", "Error opening diff view", e);
StatusManager.getManager().handle(status, StatusManager.SHOW);
}
}
}
@@ -0,0 +1,97 @@
package de.nittka.tooling.egit.diff;

import java.io.IOException;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.egit.ui.internal.commit.DiffDocument;
import org.eclipse.egit.ui.internal.commit.DiffRegionFormatter;
import org.eclipse.egit.ui.internal.commit.DiffViewer;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
import org.eclipse.egit.ui.internal.history.FileDiff;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.AnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.AbstractDocumentProvider;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.IDocumentProvider;

public class DiffEditor extends AbstractTextEditor {

private AbstractDocumentProvider dp;

@Override
public void createPartControl(Composite parent) {
setSourceViewerConfiguration(new DiffViewer.Configuration(EditorsUI.getPreferenceStore()));
super.createPartControl(parent);
}

@Override
protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
DiffViewer diffViewer = new DiffViewer(parent, ruler, styles);
return diffViewer;
}

@Override
public IDocumentProvider getDocumentProvider() {
if (dp == null) {
dp = new AbstractDocumentProvider() {

@Override
protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
return null;
}

@Override
protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document,
boolean overwrite) throws CoreException {
}

@Override
protected IDocument createDocument(Object element) throws CoreException {
if (element instanceof DiffEditorInput) {
DiffEditorInput input = (DiffEditorInput) element;
Repository repo = input.c1.getRepository();
RepositoryCommit repoCommit = new RepositoryCommit(repo, input.c1.getRevCommit());
FileDiff[] diffs = repoCommit.getDiffs(input.c2.getRevCommit());
if (diffs.length == 0) {
return new DiffDocument("Kein Unterschiede gefunden!");
}
final DiffDocument document = new DiffDocument();
try (DiffRegionFormatter formatter = new DiffRegionFormatter(document, document.getLength(),
1000000)) {
for (FileDiff diff : diffs) {
try {
formatter.write(diff);
} catch (IOException ignore) {
// Ignored
}
}
document.connect(formatter);
}
return document;
}
return new DiffDocument();
}

@Override
public IDocument getDocument(Object element) {
IDocument result = super.getDocument(element);
return result;
}

@Override
protected IAnnotationModel createAnnotationModel(Object element) throws CoreException {
return new AnnotationModel();
}
};
}
return dp;
}
}
@@ -0,0 +1,60 @@
package de.nittka.tooling.egit.diff;

import org.eclipse.egit.core.internal.IRepositoryCommit;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPersistableElement;

public class DiffEditorInput implements IEditorInput, IPersistableElement {

IRepositoryCommit c1;
IRepositoryCommit c2;

public DiffEditorInput(IRepositoryCommit c1, IRepositoryCommit c2) {
this.c1=c1;
this.c2=c2;
}

@Override
public <T> T getAdapter(Class<T> adapter) {
return null;
}

@Override
public boolean exists() {
return true;
}

@Override
public ImageDescriptor getImageDescriptor() {
return UIIcons.CHANGESET;
}

@Override
public String getName() {
return "Diff "+c2.getRevCommit().abbreviate(6).name()+"->"+c1.getRevCommit().abbreviate(6).name();
}

@Override
public IPersistableElement getPersistable() {
return this;
}

@Override
public String getToolTipText() {
return null;
}

@Override
public void saveState(IMemento memento) {
}

@Override
public String getFactoryId() {
return "";
}

}

0 comments on commit 3a15bd9

Please sign in to comment.