From c8058885f0f89158debb4d6787cd5eae703916d6 Mon Sep 17 00:00:00 2001 From: sougandhs Date: Fri, 17 Oct 2025 18:06:30 +0530 Subject: [PATCH] Add Support for Expression Pinning This commit add a new option to pin an expression with current active context, making the expression always be evaluating with the pinned context --- .../META-INF/MANIFEST.MF | 2 +- .../debug/core/model/IWatchExpression.java | 29 +++- .../debug/internal/core/WatchExpression.java | 31 +++- debug/org.eclipse.debug.ui/plugin.properties | 6 +- debug/org.eclipse.debug.ui/plugin.xml | 13 ++ .../internal/ui/actions/ActionMessages.java | 2 + .../ui/actions/ActionMessages.properties | 5 +- .../expressions/PinWatchContextAction.java | 162 ++++++++++++++++++ .../elements/ExpressionLabelProvider.java | 20 ++- .../DefaultWatchExpressionModelProxy.java | 11 +- 10 files changed, 272 insertions(+), 9 deletions(-) create mode 100644 debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/PinWatchContextAction.java diff --git a/debug/org.eclipse.debug.core/META-INF/MANIFEST.MF b/debug/org.eclipse.debug.core/META-INF/MANIFEST.MF index 5367db66167..b1c4c50bff2 100644 --- a/debug/org.eclipse.debug.core/META-INF/MANIFEST.MF +++ b/debug/org.eclipse.debug.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.debug.core; singleton:=true -Bundle-Version: 3.23.200.qualifier +Bundle-Version: 3.24.0.qualifier Bundle-Activator: org.eclipse.debug.core.DebugPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IWatchExpression.java b/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IWatchExpression.java index 01388a582f2..02c5a401bd7 100644 --- a/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IWatchExpression.java +++ b/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IWatchExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -94,4 +94,31 @@ public interface IWatchExpression extends IErrorReportingExpression { */ void setEnabled(boolean enabled); + /** + * Sets a user preferred context for expression evaluation + * + * @param context + * @since 3.24 + */ + public default void setPinnedContext(IDebugElement context) { + } + + /** + * Returns the pinned context for the given expression + * + * @return returns pinned IDebugElement + * @since 3.24 + */ + public default IDebugElement getPinnedContext() { + return null; + } + + /** + * Removes attached custom context + * + * @since 3.24 + */ + public default void removePinnedContext() { + } + } diff --git a/debug/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java b/debug/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java index 554ca41ff94..5b59bc0b140 100644 --- a/debug/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java +++ b/debug/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 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 @@ -21,6 +21,7 @@ import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.model.IDebugElement; import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IValue; import org.eclipse.debug.core.model.IWatchExpression; import org.eclipse.debug.core.model.IWatchExpressionDelegate; @@ -39,6 +40,7 @@ public class WatchExpression implements IWatchExpression { protected IDebugElement fCurrentContext; private boolean fEnabled= true; private boolean fPending= false; + private IDebugElement fPinnedContext; /** * Creates a new watch expression with the given expression @@ -301,4 +303,31 @@ public String[] getErrorMessages() { return fResult.getErrorMessages(); } + /** + * @see org.eclipse.debug.core.model.IWatchExpression#setPinnedContext(IDebugElement) + */ + @Override + public void setPinnedContext(IDebugElement context) { + fPinnedContext = context; + } + + /** + * @see org.eclipse.debug.core.model.IWatchExpression#getPinnedContext() + */ + @Override + public IDebugElement getPinnedContext() { + if (fPinnedContext instanceof IStackFrame) { + return fPinnedContext; + } + return null; + } + + /** + * @see org.eclipse.debug.core.model.IWatchExpression#removePinnedContext() + */ + @Override + public void removePinnedContext() { + fPinnedContext = null; + } + } diff --git a/debug/org.eclipse.debug.ui/plugin.properties b/debug/org.eclipse.debug.ui/plugin.properties index 84c0b135789..efb35ddfc05 100644 --- a/debug/org.eclipse.debug.ui/plugin.properties +++ b/debug/org.eclipse.debug.ui/plugin.properties @@ -421,4 +421,8 @@ prototype.decorator.label = Prototype Decorator breakpointLabel.label= Label breakpointLabel.tooltip= Provide a custom label to quickly identify breakpoint breakpointLabelCommand = EditBreakpointLabel -breakpointLabelCommand.description = Opens inline editor to change breakpoint label \ No newline at end of file +breakpointLabelCommand.description = Opens inline editor to change breakpoint label + + +PinExpressionWithCurrentAction.label=Pin Evaluation Context +PinExpressionWithCurrentAction.tooltip=Pin current evaluation stackframe for this expression \ No newline at end of file diff --git a/debug/org.eclipse.debug.ui/plugin.xml b/debug/org.eclipse.debug.ui/plugin.xml index d0d3ddbace7..697ec17be5e 100644 --- a/debug/org.eclipse.debug.ui/plugin.xml +++ b/debug/org.eclipse.debug.ui/plugin.xml @@ -1305,6 +1305,19 @@ enablesFor="1" id="org.eclipse.debug.ui.watchExpressionActions.EditWatchExpression"> + + + + iter = getCurrentSelection().iterator(); iter.hasNext();) { + if (iter.next() instanceof IWatchExpression expression) { + if (expression.getPinnedContext() != null) { + expression.removePinnedContext(); + expression.setExpressionContext(context); + action.setText(ActionMessages.ExpressionsPinContext); + } else { + expression.setPinnedContext(context); + action.setText(ActionMessages.ExpressionsRemovePin); + } + if (expression.isEnabled()) { + expression.evaluate(); + } + } + } + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + + IDebugElement debugElement = getContext(); + if (debugElement == null) { + action.setEnabled(false); + return; + } else { + action.setEnabled(true); + } + if (getCurrentSelection() == null) { + return; + } + for (Object select : getCurrentSelection()) { + if (select instanceof IWatchExpression expression) { + if (expression.getPinnedContext() != null) { + action.setText(ActionMessages.ExpressionsRemovePin); + } else { + action.setText(ActionMessages.ExpressionsPinContext); + } + } else { + action.setEnabled(false); + } + + } + + } + + @Override + public void handleDebugEvents(DebugEvent[] events) { + for (DebugEvent event : events) { + if (event.getSource() instanceof IThread thread && thread.isTerminated()) { + for (IExpression exp : DebugPlugin.getDefault().getExpressionManager().getExpressions()) { + if (exp instanceof IWatchExpression expression && expression.getPinnedContext() != null) { + if (expression.getPinnedContext() instanceof IStackFrame frame && frame.isTerminated()) { + expression.removePinnedContext(); + expression.setExpressionContext(getContext()); + } + } + } + + } + } + + } + + @Override + public void init(IViewPart view) { + DebugPlugin.getDefault().addDebugEventListener(this); + + } + + @Override + public void init(IAction action) { + } + + @Override + public void dispose() { + DebugPlugin.getDefault().removeDebugEventListener(this); + } + + @Override + public void runWithEvent(IAction action, Event event) { + run(action); + } + +} diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java index be2ea36b977..9918d128d3e 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2014 IBM Corporation and others. + * Copyright (c) 2006, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -23,7 +23,10 @@ import org.eclipse.debug.internal.ui.DebugUIMessages; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.TreePath; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.RGB; /** @@ -163,4 +166,19 @@ protected String getExpressionValueText(IExpression expression, IValue value, IP return null; } + @Override + protected FontData getFontData(TreePath elementPath, IPresentationContext presentationContext, String columnId) + throws CoreException { + Object element = elementPath.getLastSegment(); + if (element instanceof IWatchExpression watchExp) { + if (watchExp.getPinnedContext() != null) { + var fontNew = JFaceResources.getFontDescriptor(IDebugUIConstants.PREF_VARIABLE_TEXT_FONT) + .getFontData()[0]; + return new FontData(fontNew.getName(), fontNew.getHeight(), + fontNew.getStyle() ^ (SWT.BOLD | SWT.ITALIC)); + } + } + return JFaceResources.getFontDescriptor(IDebugUIConstants.PREF_VARIABLE_TEXT_FONT).getFontData()[0]; + } + } diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultWatchExpressionModelProxy.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultWatchExpressionModelProxy.java index 1bfadc7e4dd..e491edb8127 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultWatchExpressionModelProxy.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultWatchExpressionModelProxy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2011 IBM Corporation and others. + * Copyright (c) 2005, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -113,8 +113,13 @@ protected void contextActivated(ISelection selection) { } } IWatchExpression expression = (IWatchExpression)getExpression(); - if (expression != null){ - expression.setExpressionContext(context); + if (expression != null) { + IDebugElement pinnedContext = expression.getPinnedContext(); + if (pinnedContext != null) { + expression.setExpressionContext(pinnedContext); + } else { + expression.setExpressionContext(context); + } } } }