From 63190ae549e9ac9275917021d7acadaf7e95cfb4 Mon Sep 17 00:00:00 2001 From: Sougandh S Date: Mon, 6 Apr 2026 13:55:40 +0530 Subject: [PATCH] Improve Copy operations of Variables & Expressions View Improves copy behavior in Variables and Expressions views for more predictable results. Previously, copying would include the entire row (Name, Value, Type), leading to incorrect clipboard content. Introduces dedicated actions: Copy Variable/Expression for copying only the name/text, and Copy Row for full row content when columns are shown. Fixes : https://github.com/eclipse-platform/eclipse.platform/issues/2596 --- debug/org.eclipse.debug.ui/plugin.properties | 6 +- debug/org.eclipse.debug.ui/plugin.xml | 33 +++++++++-- ...pressionRowToClipboardActionDelegate.java} | 47 ++++++++++++++- ...pyExpressionToClipboardActionDelegate.java | 50 ++++++++++++++++ ...yVariableRowToClipboardActionDelegate.java | 45 +++++++++++++++ ...CopyVariableToClipboardActionDelegate.java | 57 +++++++++++++++++++ 6 files changed, 228 insertions(+), 10 deletions(-) rename debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/{CopyExpressionsToClipboardActionDelegate.java => CopyExpressionRowToClipboardActionDelegate.java} (59%) create mode 100644 debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionToClipboardActionDelegate.java create mode 100644 debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableRowToClipboardActionDelegate.java create mode 100644 debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableToClipboardActionDelegate.java diff --git a/debug/org.eclipse.debug.ui/plugin.properties b/debug/org.eclipse.debug.ui/plugin.properties index 605192017de..da2864a3640 100644 --- a/debug/org.eclipse.debug.ui/plugin.properties +++ b/debug/org.eclipse.debug.ui/plugin.properties @@ -52,8 +52,10 @@ BreakpointActionSet.label=Breakpoints CollapseAll.label=Collapse All CollapseAll.tooltip= Collapse All CopyToClipboardAction.label=&Copy Stack -CopyVariablesToClipboardAction.label=Copy &Variables -CopyExpressionsToClipboardAction.label=Copy &Expressions +CopyVariableRowToClipboardAction.label=Copy Row +CopyVariableToClipboardAction.label=Copy Variable +CopyExpressionRowToClipboardAction.label=Copy Row +CopyExpressionToClipboardAction.label=Copy Expression CopyRegistersToClipboardAction.label=Copy &Registers DebugActionSet.label=Debug DebugToolbarActionSet.label=Debug Toolbar diff --git a/debug/org.eclipse.debug.ui/plugin.xml b/debug/org.eclipse.debug.ui/plugin.xml index 70d4d67b5a6..52c830538b7 100644 --- a/debug/org.eclipse.debug.ui/plugin.xml +++ b/debug/org.eclipse.debug.ui/plugin.xml @@ -1569,13 +1569,22 @@ id="org.eclipse.debug.ui.variablesView.popupMenu"> + + + id="org.eclipse.debug.ui.debugview.popupMenu.copyVariableToClipboard"> + + + + + id="org.eclipse.debug.ui.debugview.popupMenu.copyExpressionToClipboard"> diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionsToClipboardActionDelegate.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionRowToClipboardActionDelegate.java similarity index 59% rename from debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionsToClipboardActionDelegate.java rename to debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionRowToClipboardActionDelegate.java index f9915d57fbe..ba49b4f9a06 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionsToClipboardActionDelegate.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionRowToClipboardActionDelegate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2025 Bachmann electronic GmbH and others. + * Copyright (c) 2017, 2026 Bachmann electronic GmbH and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -14,11 +14,18 @@ *******************************************************************************/ package org.eclipse.debug.internal.ui.actions.expressions; +import java.util.Iterator; + +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugElement; import org.eclipse.debug.internal.core.WatchExpression; import org.eclipse.debug.internal.ui.DebugUIMessages; import org.eclipse.debug.internal.ui.viewers.model.VirtualCopyToClipboardActionDelegate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.jface.viewers.IStructuredSelection; -public class CopyExpressionsToClipboardActionDelegate extends VirtualCopyToClipboardActionDelegate { +public class CopyExpressionRowToClipboardActionDelegate extends VirtualCopyToClipboardActionDelegate { private static final String QUOTE = "\""; //$NON-NLS-1$ @Override @@ -57,4 +64,40 @@ protected String exludeLabels(Object itemData, String label) { } return label; } + + @Override + protected boolean getEnableStateForSelection(IStructuredSelection selection) { + if (selection.size() == 0) { + return false; + } + + if (getViewer() instanceof TreeModelViewer treeViewer) { + if (!treeViewer.isShowColumns()) { + return false; + } + } + + Object object = DebugUITools.getDebugContext(); + IDebugElement context = null; + if (object == null) { + return false; + } + if (object instanceof IDebugElement debugElement) { + context = debugElement; + } else if (object instanceof ILaunch launch) { + context = launch.getDebugTarget(); + } + if (context != null && context.getLaunch().isTerminated()) { + return false; + } + + Iterator itr = selection.iterator(); + while (itr.hasNext()) { + Object element = itr.next(); + if (!isEnabledFor(element)) { + return false; + } + } + return true; + } } diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionToClipboardActionDelegate.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionToClipboardActionDelegate.java new file mode 100644 index 00000000000..f96ab404e33 --- /dev/null +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyExpressionToClipboardActionDelegate.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2026 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.debug.internal.ui.actions.expressions; + +import java.util.Iterator; + +import org.eclipse.debug.core.model.IExpression; +import org.eclipse.debug.internal.ui.viewers.model.VirtualCopyToClipboardActionDelegate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem; +import org.eclipse.jface.viewers.IStructuredSelection; + +public class CopyExpressionToClipboardActionDelegate extends VirtualCopyToClipboardActionDelegate { + + @Override + protected void append(VirtualItem item, StringBuilder buffer, int indent) { + if (item.getData() instanceof IExpression expression) { + if (!buffer.isEmpty()) { + buffer.append(System.lineSeparator()); + } + String expString = expression.getExpressionText(); + buffer.append(expString); + } + } + + @Override + protected boolean getEnableStateForSelection(IStructuredSelection selection) { + if (selection.size() == 0) { + return false; + } + Iterator itr = selection.iterator(); + while (itr.hasNext()) { + Object element = itr.next(); + if (!isEnabledFor(element)) { + return false; + } + } + return true; + } +} diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableRowToClipboardActionDelegate.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableRowToClipboardActionDelegate.java new file mode 100644 index 00000000000..b7073ee24de --- /dev/null +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableRowToClipboardActionDelegate.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2026 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.debug.internal.ui.actions.expressions; + +import java.util.Iterator; + +import org.eclipse.debug.internal.ui.viewers.model.VirtualCopyToClipboardActionDelegate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; +import org.eclipse.jface.viewers.IStructuredSelection; + +public class CopyVariableRowToClipboardActionDelegate extends VirtualCopyToClipboardActionDelegate { + + @Override + protected boolean getEnableStateForSelection(IStructuredSelection selection) { + if (selection.size() == 0) { + return false; + } + + if (getViewer() instanceof TreeModelViewer treeViewer) { + if (!treeViewer.isShowColumns()) { + return false; + } + } + + Iterator itr = selection.iterator(); + while (itr.hasNext()) { + Object element = itr.next(); + if (!isEnabledFor(element)) { + return false; + } + } + return true; + } +} diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableToClipboardActionDelegate.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableToClipboardActionDelegate.java new file mode 100644 index 00000000000..300c1a4e3f6 --- /dev/null +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/CopyVariableToClipboardActionDelegate.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2026 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.debug.internal.ui.actions.expressions; + +import java.util.Iterator; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.debug.internal.ui.viewers.model.VirtualCopyToClipboardActionDelegate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem; +import org.eclipse.jface.viewers.IStructuredSelection; + +public class CopyVariableToClipboardActionDelegate extends VirtualCopyToClipboardActionDelegate { + + @Override + protected void append(VirtualItem item, StringBuilder buffer, int indent) { + if (item.getData() instanceof IVariable variable) { + try { + if (!buffer.isEmpty()) { + buffer.append(System.lineSeparator()); + } + String variableName = variable.getName(); + buffer.append(variableName); + } catch (DebugException e) { + DebugPlugin.log(e); + } + + } + } + + @Override + protected boolean getEnableStateForSelection(IStructuredSelection selection) { + if (selection.size() == 0) { + return false; + } + Iterator itr = selection.iterator(); + while (itr.hasNext()) { + Object element = itr.next(); + if (!isEnabledFor(element)) { + return false; + } + } + return true; + } +}