diff --git a/org.eclipse.buildship.kotlindsl.provider/META-INF/MANIFEST.MF b/org.eclipse.buildship.kotlindsl.provider/META-INF/MANIFEST.MF
index a6a5b760c..8e7e640b6 100644
--- a/org.eclipse.buildship.kotlindsl.provider/META-INF/MANIFEST.MF
+++ b/org.eclipse.buildship.kotlindsl.provider/META-INF/MANIFEST.MF
@@ -12,6 +12,7 @@ Require-Bundle: org.eclipse.core.contenttype,
org.eclipse.tm4e.registry,
org.eclipse.jdt.launching,
org.eclipse.swt,
- org.eclipse.ui.genericeditor
+ org.eclipse.ui.genericeditor,
+ org.eclipse.compare
Export-Package: org.eclipse.buildship.kotlindsl.provider
diff --git a/org.eclipse.buildship.kotlindsl.provider/plugin.xml b/org.eclipse.buildship.kotlindsl.provider/plugin.xml
index 25ab6e2e2..0fd24f1ad 100644
--- a/org.eclipse.buildship.kotlindsl.provider/plugin.xml
+++ b/org.eclipse.buildship.kotlindsl.provider/plugin.xml
@@ -42,5 +42,19 @@
label="Kotlin DSL language server">
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.buildship.ui/META-INF/MANIFEST.MF b/org.eclipse.buildship.ui/META-INF/MANIFEST.MF
index 8bb2997aa..ba325abeb 100644
--- a/org.eclipse.buildship.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.buildship.ui/META-INF/MANIFEST.MF
@@ -23,6 +23,7 @@ Require-Bundle: org.eclipse.buildship.core,
com.ibm.icu,
com.google.guava;bundle-version="33.0.0",
org.gradle.toolingapi;bundle-version="[8.6.0,8.7.0)",
- org.eclipse.ui.workbench.texteditor
+ org.eclipse.ui.workbench.texteditor,
+ org.eclipse.compare
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/org.eclipse.buildship.ui/plugin.xml b/org.eclipse.buildship.ui/plugin.xml
index 4719cd31e..701a1df62 100644
--- a/org.eclipse.buildship.ui/plugin.xml
+++ b/org.eclipse.buildship.ui/plugin.xml
@@ -675,4 +675,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleMergeViewer.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleMergeViewer.java
new file mode 100644
index 000000000..0913672cf
--- /dev/null
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleMergeViewer.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Gradle Inc. and others
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ******************************************************************************/
+package org.eclipse.buildship.ui.internal.compare;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.jface.text.TextViewer;
+import org.eclipse.jface.text.rules.FastPartitioner;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.widgets.Composite;
+
+import org.eclipse.buildship.ui.internal.editor.GradleEditorConstants;
+import org.eclipse.buildship.ui.internal.editor.GradlePartitionScanner;
+import org.eclipse.buildship.ui.internal.editor.GradleTextViewerConfiguration;
+import org.eclipse.buildship.ui.internal.i18n.UiMessages;
+
+public final class GradleMergeViewer extends TextMergeViewer {
+
+ public GradleMergeViewer(Composite parent, CompareConfiguration configuration) {
+ super(parent, configuration);
+ }
+
+ @Override
+ public String getTitle() {
+ return UiMessages.Title_Gradle_Build_Script_Compare;
+ }
+
+ @Override
+ protected void configureTextViewer(TextViewer textViewer) {
+ if (textViewer instanceof ISourceViewer) {
+ ((ISourceViewer) textViewer).configure(new GradleTextViewerConfiguration());
+ }
+ }
+
+ @Override
+ protected IDocumentPartitioner getDocumentPartitioner() {
+ return new FastPartitioner(new GradlePartitionScanner(), GradleEditorConstants.PARTITIONS);
+ }
+
+ @Override
+ protected String getDocumentPartitioning() {
+ return GradleEditorConstants.PARTITIONING;
+ }
+
+}
diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleMergeViewerCreator.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleMergeViewerCreator.java
new file mode 100644
index 000000000..641cb9b41
--- /dev/null
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleMergeViewerCreator.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Gradle Inc. and others
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ******************************************************************************/
+package org.eclipse.buildship.ui.internal.compare;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.IViewerCreator;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Composite;
+
+public final class GradleMergeViewerCreator implements IViewerCreator {
+
+ @Override
+ public Viewer createViewer(Composite parent, CompareConfiguration config) {
+ return new GradleMergeViewer(parent, config);
+ }
+
+}
diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleViewer.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleViewer.java
new file mode 100644
index 000000000..7101e4c7a
--- /dev/null
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleViewer.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Gradle Inc. and others
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ******************************************************************************/
+package org.eclipse.buildship.ui.internal.compare;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.compare.IEncodedStreamContentAccessor;
+import org.eclipse.compare.IStreamContentAccessor;
+import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+import org.eclipse.buildship.ui.internal.UiPlugin;
+import org.eclipse.buildship.ui.internal.editor.GradleDocumentSetupParticipant;
+import org.eclipse.buildship.ui.internal.editor.GradleTextViewerConfiguration;
+
+public final class GradleViewer extends Viewer {
+
+ private final SourceViewer sourceViewer;
+
+ private Object input;
+
+ public GradleViewer(Composite parent) {
+ this.sourceViewer = new SourceViewer(parent, null, SWT.H_SCROLL | SWT.V_SCROLL);
+ this.sourceViewer.setEditable(false);
+ this.sourceViewer.configure(new GradleTextViewerConfiguration());
+
+ // use the same font as the TextMergeViewer
+ this.sourceViewer.getTextWidget().setFont(JFaceResources.getFont(TextMergeViewer.class.getName()));
+ }
+
+ @Override
+ public Control getControl() {
+ return this.sourceViewer.getControl();
+ }
+
+ @Override
+ public Object getInput() {
+ return this.input;
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return StructuredSelection.EMPTY;
+ }
+
+ @Override
+ public void refresh() {
+ // empty implementation
+ }
+
+ @Override
+ public void setInput(Object input) {
+ this.input = input;
+
+ if (!(input instanceof IStreamContentAccessor && input instanceof IEncodedStreamContentAccessor)) {
+ return;
+ }
+
+ IEncodedStreamContentAccessor contentAccessor = (IEncodedStreamContentAccessor) input;
+ try (InputStream contents = contentAccessor.getContents()) {
+ if (contents == null) {
+ return;
+ }
+
+ String charset = contentAccessor.getCharset();
+ if (charset == null) {
+ charset = ResourcesPlugin.getEncoding();
+ }
+
+ Document document = new Document(new String(contents.readAllBytes(), charset));
+ new GradleDocumentSetupParticipant().setup(document);
+ this.sourceViewer.setDocument(document);
+ } catch (CoreException | IOException e) {
+ UiPlugin.logger().error("Failed to set up input document.", e);
+ }
+ }
+
+ @Override
+ public void setSelection(ISelection selection, boolean reveal) {
+ // empty implementation
+ }
+
+}
diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleViewerCreator.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleViewerCreator.java
new file mode 100644
index 000000000..d98af217d
--- /dev/null
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/compare/GradleViewerCreator.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Gradle Inc. and others
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ******************************************************************************/
+package org.eclipse.buildship.ui.internal.compare;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.IViewerCreator;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Composite;
+
+public final class GradleViewerCreator implements IViewerCreator {
+
+ @Override
+ public Viewer createViewer(Composite parent, CompareConfiguration config) {
+ return new GradleViewer(parent);
+ }
+
+}
diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/editor/GradleEditor.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/editor/GradleEditor.java
index 0a06ea4ae..ef98b31c2 100644
--- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/editor/GradleEditor.java
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/editor/GradleEditor.java
@@ -10,8 +10,11 @@
package org.eclipse.buildship.ui.internal.editor;
import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.editors.text.ForwardingDocumentProvider;
import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.editors.text.TextFileDocumentProvider;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
+import org.eclipse.ui.texteditor.IDocumentProvider;
/**
* Editor definition for Gradle build scripts.
@@ -19,10 +22,18 @@
* @author Christophe Moine
*/
public final class GradleEditor extends TextEditor {
+
+ private static final IDocumentProvider DOCUMENT_PROVIDER = new ForwardingDocumentProvider(GradleEditorConstants.PARTITIONING, new GradleDocumentSetupParticipant(),
+ new TextFileDocumentProvider());
+
@Override
protected void initializeEditor() {
super.initializeEditor();
setSourceViewerConfiguration(new GradleTextViewerConfiguration());
+
+ // This ensures that the document is set up correctly when it is opened from the History
+ // View.
+ setDocumentProvider(DOCUMENT_PROVIDER);
}
@Override
diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/i18n/UiMessages.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/i18n/UiMessages.java
index 3fc0fcab4..3b042be2f 100644
--- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/i18n/UiMessages.java
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/i18n/UiMessages.java
@@ -19,6 +19,7 @@ public final class UiMessages extends NLS {
private static final String BUNDLE_NAME = "org.eclipse.buildship.ui.internal.i18n.UiMessages"; //$NON-NLS-1$
public static String Title_Select_0;
+ public static String Title_Gradle_Build_Script_Compare;
public static String Button_Label_Browse;
diff --git a/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/i18n/UiMessages.properties b/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/i18n/UiMessages.properties
index a66c102fb..7acac4166 100644
--- a/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/i18n/UiMessages.properties
+++ b/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/i18n/UiMessages.properties
@@ -8,6 +8,7 @@
# SPDX-License-Identifier: EPL-2.0
#-------------------------------------------------------------------------------
Title_Select_0=Select {0}
+Title_Gradle_Build_Script_Compare=Gradle Build Script Compare
Button_Label_Browse=Browse...