Skip to content

Commit 73d7e06

Browse files
committed
Add support to Compare/Replace selection or editor with clipboard
Allows users to compare or replace either the selected text or the entire editor content against the clipboard content
1 parent 2e1acee commit 73d7e06

File tree

4 files changed

+307
-1
lines changed

4 files changed

+307
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.compare.internal;
15+
16+
import java.io.ByteArrayInputStream;
17+
import java.io.IOException;
18+
import java.io.InputStream;
19+
import java.lang.reflect.InvocationTargetException;
20+
import java.nio.charset.StandardCharsets;
21+
22+
import org.eclipse.compare.CompareConfiguration;
23+
import org.eclipse.compare.CompareEditorInput;
24+
import org.eclipse.compare.CompareUI;
25+
import org.eclipse.compare.IStreamContentAccessor;
26+
import org.eclipse.compare.ITypedElement;
27+
import org.eclipse.compare.structuremergeviewer.DiffNode;
28+
import org.eclipse.core.resources.IFile;
29+
import org.eclipse.core.runtime.CoreException;
30+
import org.eclipse.core.runtime.IProgressMonitor;
31+
import org.eclipse.jface.action.IAction;
32+
import org.eclipse.jface.dialogs.MessageDialog;
33+
import org.eclipse.jface.text.ITextSelection;
34+
import org.eclipse.jface.viewers.ISelection;
35+
import org.eclipse.swt.dnd.Clipboard;
36+
import org.eclipse.swt.dnd.TextTransfer;
37+
import org.eclipse.swt.graphics.Image;
38+
import org.eclipse.swt.widgets.Display;
39+
import org.eclipse.swt.widgets.Shell;
40+
import org.eclipse.ui.IEditorPart;
41+
import org.eclipse.ui.IObjectActionDelegate;
42+
import org.eclipse.ui.IViewPart;
43+
import org.eclipse.ui.IWorkbenchPage;
44+
import org.eclipse.ui.IWorkbenchPart;
45+
import org.eclipse.ui.PlatformUI;
46+
import org.eclipse.ui.texteditor.ITextEditor;
47+
48+
public class ClipboardCompare extends BaseCompareAction implements IObjectActionDelegate {
49+
50+
private String clipboard = "Clipboard"; //$NON-NLS-1$
51+
private String compareFailed = "Comparision Failed"; //$NON-NLS-1$
52+
53+
private IWorkbenchPart activePart;
54+
55+
@Override
56+
protected void run(ISelection selection) {
57+
IFile[] files = Utilities.getFiles(selection);
58+
Shell parentShell = CompareUIPlugin.getShell();
59+
for (IFile file : files) {
60+
try {
61+
processComparison(file, parentShell);
62+
} catch (Exception e) {
63+
MessageDialog.openError(parentShell, compareFailed, e.getMessage());
64+
}
65+
}
66+
}
67+
@Override
68+
protected boolean isEnabled(ISelection selection) {
69+
return Utilities.getFiles(selection).length == 1 && getClipboard() != null;
70+
}
71+
72+
/**
73+
* Process comparison with selection or entire editor contents with contents in
74+
* clipboard
75+
*
76+
* @param file Editor file
77+
* @param parentShell The shell containing this window's controls
78+
* @throws IOException, CoreException
79+
*/
80+
private void processComparison(IFile file, Shell parentShell) throws IOException, CoreException {
81+
String cb = getClipboard().toString();
82+
String fileName = file.getName();
83+
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
84+
IEditorPart editor = page.getActiveEditor();
85+
if (activePart instanceof IViewPart) {
86+
String fileContents = new String(file.getContents().readAllBytes(), file.getCharset());
87+
showComparison(fileContents, fileName, cb, parentShell);
88+
return;
89+
}
90+
final String selectionContents;
91+
if (editor instanceof ITextEditor txtEditor) {
92+
ISelection selection = txtEditor.getSelectionProvider().getSelection();
93+
if (selection instanceof ITextSelection textSelection) {
94+
selectionContents = textSelection.getText();
95+
if (selectionContents.isEmpty()) {
96+
String fileContents = new String(file.getContents().readAllBytes(), file.getCharset());
97+
showComparison(fileContents, fileName, cb, parentShell);
98+
} else {
99+
showComparison(selectionContents, fileName, cb, parentShell);
100+
}
101+
return;
102+
}
103+
}
104+
if (editor instanceof CompareEditor existingCompare) { // if selection is from compare editor itself
105+
ISelection selection = existingCompare.getSite().getSelectionProvider().getSelection();
106+
if (selection instanceof ITextSelection textSelection) {
107+
String selectedText = textSelection.getText();
108+
String fileContents = new String(file.getContents().readAllBytes(), file.getCharset());
109+
showComparison(fileContents, fileName, selectedText, parentShell);
110+
}
111+
}
112+
}
113+
114+
/**
115+
* Shows comparison result
116+
*
117+
* @param source Either selection from current editor or entire
118+
* editor if no selection
119+
* @param fileName Editor file name
120+
* @param clipboardContents Contents in clipboard
121+
* @param parentShell The shell containing this window's controls
122+
*/
123+
private void showComparison(String source, String fileName, String clipboardContents, Shell parentShell) {
124+
class ClipboardTypedElement implements ITypedElement, IStreamContentAccessor {
125+
private final String name;
126+
private final String content;
127+
128+
public ClipboardTypedElement(String name, String content) {
129+
this.name = name;
130+
this.content = content;
131+
}
132+
133+
@Override
134+
public String getName() {
135+
return name;
136+
}
137+
138+
@Override
139+
public Image getImage() {
140+
return null;
141+
}
142+
143+
@Override
144+
public String getType() {
145+
return null;
146+
}
147+
148+
@Override
149+
public InputStream getContents() throws CoreException {
150+
return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
151+
}
152+
153+
}
154+
if (source == null) {
155+
MessageDialog.openInformation(parentShell, compareFailed, "Failed to process selected file"); //$NON-NLS-1$
156+
return;
157+
}
158+
CompareConfiguration config = new CompareConfiguration();
159+
config.setLeftLabel(fileName);
160+
config.setRightLabel(clipboard);
161+
config.setLeftEditable(true);
162+
config.setRightEditable(true);
163+
CompareEditorInput compareInput = new CompareEditorInput(config) {
164+
@Override
165+
protected Object prepareInput(IProgressMonitor monitor)
166+
throws InvocationTargetException, InterruptedException {
167+
return new DiffNode(new ClipboardTypedElement(fileName, source),
168+
new ClipboardTypedElement(clipboard, clipboardContents));
169+
170+
}
171+
};
172+
CompareUI.openCompareEditor(compareInput);
173+
}
174+
175+
/**
176+
* Returns Clipboard Object or null if there is nothing in clipboard
177+
*
178+
* @returns Clipboard Object or null
179+
*/
180+
private Object getClipboard() {
181+
Clipboard clip = new Clipboard(Display.getDefault());
182+
return clip.getContents(TextTransfer.getInstance());
183+
}
184+
185+
@Override
186+
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
187+
this.activePart = targetPart;
188+
}
189+
190+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.compare.internal;
15+
16+
import java.io.ByteArrayInputStream;
17+
import java.nio.charset.StandardCharsets;
18+
19+
import org.eclipse.core.resources.IFile;
20+
import org.eclipse.core.resources.IResource;
21+
import org.eclipse.jface.dialogs.MessageDialog;
22+
import org.eclipse.jface.text.IDocument;
23+
import org.eclipse.jface.text.ITextSelection;
24+
import org.eclipse.jface.viewers.ISelection;
25+
import org.eclipse.swt.dnd.Clipboard;
26+
import org.eclipse.swt.dnd.TextTransfer;
27+
import org.eclipse.swt.widgets.Display;
28+
import org.eclipse.swt.widgets.Shell;
29+
import org.eclipse.ui.IEditorInput;
30+
import org.eclipse.ui.IEditorPart;
31+
import org.eclipse.ui.IFileEditorInput;
32+
import org.eclipse.ui.IWorkbenchPage;
33+
import org.eclipse.ui.PlatformUI;
34+
import org.eclipse.ui.texteditor.ITextEditor;
35+
36+
public class ClipboardReplace extends BaseCompareAction {
37+
38+
@Override
39+
protected void run(ISelection selection) {
40+
IFile[] files = Utilities.getFiles(selection);
41+
for (IFile file : files) {
42+
try {
43+
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
44+
IEditorPart editor = page.getActiveEditor();
45+
IEditorInput input = editor.getEditorInput();
46+
if (input instanceof IFileEditorInput ed) {
47+
IFile file2 = ed.getFile();
48+
String fileName2 = file2.getName();
49+
if (!file.getName().equals(fileName2)) {
50+
ByteArrayInputStream source = new ByteArrayInputStream(
51+
getClipboard().toString().getBytes(StandardCharsets.UTF_8));
52+
file.setContents(source, IResource.FORCE, null);
53+
return;
54+
}
55+
}
56+
if (editor instanceof ITextEditor txtEditor) {
57+
ISelection selection2 = txtEditor.getSelectionProvider().getSelection();
58+
if (selection2 instanceof ITextSelection textSelection) {
59+
int offset = textSelection.getOffset();
60+
int len = textSelection.getLength();
61+
if (len > 0) {
62+
IDocument doc = ((ITextEditor) editor).getDocumentProvider()
63+
.getDocument(editor.getEditorInput());
64+
doc.replace(offset, len, getClipboard().toString());
65+
return;
66+
}
67+
ByteArrayInputStream source = new ByteArrayInputStream(
68+
getClipboard().toString().getBytes(StandardCharsets.UTF_8));
69+
file.setContents(source, IResource.FORCE, null);
70+
}
71+
}
72+
73+
} catch (Exception e) {
74+
Shell parentShell = CompareUIPlugin.getShell();
75+
MessageDialog.openError(parentShell, "Replace Failed", e.getMessage()); //$NON-NLS-1$
76+
}
77+
}
78+
}
79+
@Override
80+
protected boolean isEnabled(ISelection selection) {
81+
return Utilities.getFiles(selection).length == 1 && getClipboard() != null;
82+
}
83+
84+
/**
85+
* Returns Clipboard Object or null if there is nothing in clipboard
86+
*
87+
* @returns Clipboard Object or null
88+
*/
89+
private Object getClipboard() {
90+
Clipboard clip = new Clipboard(Display.getDefault());
91+
return clip.getContents(TextTransfer.getInstance());
92+
}
93+
94+
}

team/bundles/org.eclipse.compare/plugin.properties

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
###############################################################################
2-
# Copyright (c) 2000, 2016 IBM Corporation and others.
2+
# Copyright (c) 2000, 2025 IBM Corporation and others.
33
#
44
# This program and the accompanying materials
55
# are made available under the terms of the Eclipse Public License 2.0
@@ -98,6 +98,12 @@ CompareWithOtherResource.tooltip= Open the 'Compare With' Dialog
9898
CompareWithHistoryAction.label= &Local History...
9999
CompareWithHistoryAction.tooltip= Compare the Selected Resource with Local History
100100

101+
CompareWithClipboardAction.label= Clipboard
102+
CompareWithClipboardAction.tooltip= Compare the selection or entire contents in editor with contents in clipboard
103+
104+
ReplaceWithClipboardAction.label= Clipboard
105+
ReplaceWithClipboardAction.tooltip= Replace the selection or entire contents in editor with contents in clipboard
106+
101107
ReplaceWithMenu.label= Rep&lace With
102108

103109
ReplaceFromHistoryAction.label= &Local History...

team/bundles/org.eclipse.compare/plugin.xml

+16
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,14 @@
296296
enablesFor="1"
297297
id="replaceWithPreviousFromHistory">
298298
</action>
299+
<action
300+
label="%ReplaceWithClipboardAction.label"
301+
tooltip="%ReplaceWithClipboardAction.tooltip"
302+
class="org.eclipse.compare.internal.ClipboardReplace"
303+
menubarPath="replaceWithMenu/replaceWithGroup"
304+
enablesFor="1"
305+
id="replaceWithClipboard">
306+
</action>
299307
</objectContribution>
300308
<objectContribution
301309
objectClass="org.eclipse.core.resources.IFile"
@@ -309,6 +317,14 @@
309317
name="compareWithGroup">
310318
</separator>
311319
</menu>
320+
<action
321+
label="%CompareWithClipboardAction.label"
322+
tooltip="%CompareWithClipboardAction.tooltip"
323+
class="org.eclipse.compare.internal.ClipboardCompare"
324+
menubarPath="compareWithMenu/compareWithGroup"
325+
enablesFor="1"
326+
id="compareWithClipboard">
327+
</action>
312328
<action
313329
label="%CompareWithHistoryAction.label"
314330
tooltip="%CompareWithHistoryAction.tooltip"

0 commit comments

Comments
 (0)