Skip to content

Compare/Replace selection or editor with clipboard #1862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
@@ -0,0 +1,190 @@
/*******************************************************************************
* Copyright (c) 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.compare.internal;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.IStreamContentAccessor;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.ITextEditor;

public class ClipboardCompare extends BaseCompareAction implements IObjectActionDelegate {

private String clipboard = "Clipboard"; //$NON-NLS-1$
private String compareFailed = "Comparision Failed"; //$NON-NLS-1$

private IWorkbenchPart activePart;

@Override
protected void run(ISelection selection) {
IFile[] files = Utilities.getFiles(selection);
Shell parentShell = CompareUIPlugin.getShell();
for (IFile file : files) {
try {
processComparison(file, parentShell);
} catch (Exception e) {
MessageDialog.openError(parentShell, compareFailed, e.getMessage());
}
}
}
@Override
protected boolean isEnabled(ISelection selection) {
return Utilities.getFiles(selection).length == 1 && getClipboard() != null;
}

/**
* Process comparison with selection or entire editor contents with contents in
* clipboard
*
* @param file Editor file
* @param parentShell The shell containing this window's controls
* @throws IOException, CoreException
*/
private void processComparison(IFile file, Shell parentShell) throws IOException, CoreException {
String cb = getClipboard().toString();
String fileName = file.getName();
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IEditorPart editor = page.getActiveEditor();
if (activePart instanceof IViewPart) {
String fileContents = new String(file.getContents().readAllBytes(), file.getCharset());
showComparison(fileContents, fileName, cb, parentShell);
return;
}
final String selectionContents;
if (editor instanceof ITextEditor txtEditor) {
ISelection selection = txtEditor.getSelectionProvider().getSelection();
if (selection instanceof ITextSelection textSelection) {
selectionContents = textSelection.getText();
if (selectionContents.isEmpty()) {
String fileContents = new String(file.getContents().readAllBytes(), file.getCharset());
showComparison(fileContents, fileName, cb, parentShell);
} else {
showComparison(selectionContents, fileName, cb, parentShell);
}
return;
}
}
if (editor instanceof CompareEditor existingCompare) { // if selection is from compare editor itself
ISelection selection = existingCompare.getSite().getSelectionProvider().getSelection();
if (selection instanceof ITextSelection textSelection) {
String selectedText = textSelection.getText();
String fileContents = new String(file.getContents().readAllBytes(), file.getCharset());
showComparison(fileContents, fileName, selectedText, parentShell);
}
}
}

/**
* Shows comparison result
*
* @param source Either selection from current editor or entire
* editor if no selection
* @param fileName Editor file name
* @param clipboardContents Contents in clipboard
* @param parentShell The shell containing this window's controls
*/
private void showComparison(String source, String fileName, String clipboardContents, Shell parentShell) {
class ClipboardTypedElement implements ITypedElement, IStreamContentAccessor {
private final String name;
private final String content;

public ClipboardTypedElement(String name, String content) {
this.name = name;
this.content = content;
}

@Override
public String getName() {
return name;
}

@Override
public Image getImage() {
return null;
}

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

@Override
public InputStream getContents() throws CoreException {
return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
}

}
if (source == null) {
MessageDialog.openInformation(parentShell, compareFailed, "Failed to process selected file"); //$NON-NLS-1$
return;
}
CompareConfiguration config = new CompareConfiguration();
config.setLeftLabel(fileName);
config.setRightLabel(clipboard);
config.setLeftEditable(true);
config.setRightEditable(true);
CompareEditorInput compareInput = new CompareEditorInput(config) {
@Override
protected Object prepareInput(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
return new DiffNode(new ClipboardTypedElement(fileName, source),
new ClipboardTypedElement(clipboard, clipboardContents));

}
};
CompareUI.openCompareEditor(compareInput);
}

/**
* Returns Clipboard Object or null if there is nothing in clipboard
*
* @returns Clipboard Object or null
*/
private Object getClipboard() {
Clipboard clip = new Clipboard(Display.getDefault());
return clip.getContents(TextTransfer.getInstance());
}

@Override
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
this.activePart = targetPart;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*******************************************************************************
* Copyright (c) 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.compare.internal;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.ITextEditor;

public class ClipboardReplace extends BaseCompareAction {

@Override
protected void run(ISelection selection) {
IFile[] files = Utilities.getFiles(selection);
for (IFile file : files) {
try {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IEditorPart editor = page.getActiveEditor();
IEditorInput input = editor.getEditorInput();
if (input instanceof IFileEditorInput ed) {
IFile file2 = ed.getFile();
String fileName2 = file2.getName();
if (!file.getName().equals(fileName2)) {
ByteArrayInputStream source = new ByteArrayInputStream(
getClipboard().toString().getBytes(StandardCharsets.UTF_8));
file.setContents(source, IResource.FORCE, null);
return;
}
}
if (editor instanceof ITextEditor txtEditor) {
ISelection selection2 = txtEditor.getSelectionProvider().getSelection();
if (selection2 instanceof ITextSelection textSelection) {
int offset = textSelection.getOffset();
int len = textSelection.getLength();
if (len > 0) {
IDocument doc = ((ITextEditor) editor).getDocumentProvider()
.getDocument(editor.getEditorInput());
doc.replace(offset, len, getClipboard().toString());
return;
}
ByteArrayInputStream source = new ByteArrayInputStream(
getClipboard().toString().getBytes(StandardCharsets.UTF_8));
file.setContents(source, IResource.FORCE, null);
}
}

} catch (Exception e) {
Shell parentShell = CompareUIPlugin.getShell();
MessageDialog.openError(parentShell, "Replace Failed", e.getMessage()); //$NON-NLS-1$
}
}
}
@Override
protected boolean isEnabled(ISelection selection) {
return Utilities.getFiles(selection).length == 1 && getClipboard() != null;
}

/**
* Returns Clipboard Object or null if there is nothing in clipboard
*
* @returns Clipboard Object or null
*/
private Object getClipboard() {
Clipboard clip = new Clipboard(Display.getDefault());
return clip.getContents(TextTransfer.getInstance());
}

}
8 changes: 7 additions & 1 deletion team/bundles/org.eclipse.compare/plugin.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2000, 2016 IBM Corporation and others.
# Copyright (c) 2000, 2025 IBM Corporation and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -98,6 +98,12 @@ CompareWithOtherResource.tooltip= Open the 'Compare With' Dialog
CompareWithHistoryAction.label= &Local History...
CompareWithHistoryAction.tooltip= Compare the Selected Resource with Local History

CompareWithClipboardAction.label= Clipboard
CompareWithClipboardAction.tooltip= Compare the selection or entire contents in editor with contents in clipboard

ReplaceWithClipboardAction.label= Clipboard
ReplaceWithClipboardAction.tooltip= Replace the selection or entire contents in editor with contents in clipboard

ReplaceWithMenu.label= Rep&lace With

ReplaceFromHistoryAction.label= &Local History...
Expand Down
16 changes: 16 additions & 0 deletions team/bundles/org.eclipse.compare/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,14 @@
enablesFor="1"
id="replaceWithPreviousFromHistory">
</action>
<action
label="%ReplaceWithClipboardAction.label"
tooltip="%ReplaceWithClipboardAction.tooltip"
class="org.eclipse.compare.internal.ClipboardReplace"
menubarPath="replaceWithMenu/replaceWithGroup"
enablesFor="1"
id="replaceWithClipboard">
</action>
</objectContribution>
<objectContribution
objectClass="org.eclipse.core.resources.IFile"
Expand All @@ -309,6 +317,14 @@
name="compareWithGroup">
</separator>
</menu>
<action
label="%CompareWithClipboardAction.label"
tooltip="%CompareWithClipboardAction.tooltip"
class="org.eclipse.compare.internal.ClipboardCompare"
menubarPath="compareWithMenu/compareWithGroup"
enablesFor="1"
id="compareWithClipboard">
</action>
<action
label="%CompareWithHistoryAction.label"
tooltip="%CompareWithHistoryAction.tooltip"
Expand Down
Loading