Skip to content
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
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
* Copyright (c) 2000, 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -25,15 +25,19 @@
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IDisconnect;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.internal.core.DebugCoreMessages;
import org.eclipse.debug.internal.core.LaunchManager;
import org.osgi.service.prefs.BackingStoreException;

/**
* A launch is the result of launching a debug session
Expand Down Expand Up @@ -475,7 +479,24 @@ protected void fireChanged() {
* properly created/initialized.
*/
protected void fireTerminate() {
setAttribute(DebugPlugin.ATTR_TERMINATE_TIMESTAMP, Long.toString(System.currentTimeMillis()));
String timeStamp = Long.toString(System.currentTimeMillis());
setAttribute(DebugPlugin.ATTR_TERMINATE_TIMESTAMP, timeStamp);
Comment thread
SougandhS marked this conversation as resolved.
ILaunchConfiguration launchConfig = getLaunchConfiguration();
if (launchConfig != null) {
try {
Comment thread
SougandhS marked this conversation as resolved.
if (launchConfig.isLocal()) {
ILaunchConfigurationWorkingCopy launchCopy = launchConfig.getWorkingCopy();
launchCopy.setAttribute(DebugPlugin.ATTR_TERMINATE_TIMESTAMP, timeStamp);
launchCopy.doSave();
} else {
IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(DebugPlugin.getUniqueIdentifier());
prefs.put(launchConfig.getName(), timeStamp);
prefs.flush();
}
Comment on lines +487 to +495

@SougandhS SougandhS Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @iloveeclipse, is this how it should be handled for #2744 (comment) ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no. Correct is launchConfig.isLocal(). Not correct is how the prefs are saved
prefs.put(launchConfig.getMemento(), timeStamp);: this persists entire config as a preference key! I believe in the same category launch configs are "identified" by the name. There shouldn't be two configs with same name as far as I remember it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update key with launchConfig names 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated 👍

Comment thread
SougandhS marked this conversation as resolved.
Comment thread
SougandhS marked this conversation as resolved.
} catch (CoreException | BackingStoreException e) {
DebugPlugin.log(e);
}
}
if (!fSuppressChange) {
((LaunchManager)getLaunchManager()).fireUpdate(this, LaunchManager.TERMINATE);
((LaunchManager)getLaunchManager()).fireUpdate(new ILaunch[] {this}, LaunchManager.TERMINATE);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2025 IBM Corporation and others.
* Copyright (c) 2000, 2026 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 @@ -2039,4 +2039,100 @@ public void launchConfigurationAdded(ILaunchConfiguration configuration) {

}

@Test
public void testSharedTerminateTimeStampPersistence() throws Exception {
IProject project = getProject();
ILaunchConfigurationWorkingCopy workingCopy = newConfiguration(project, "testSharedTerminateTimestamp");
Set<ILaunch> terminatedLaunches = Collections.synchronizedSet(new HashSet<>());

ILaunchesListener2 listener = new ILaunchesListener2() {
@Override
public void launchesRemoved(ILaunch[] launches) {
}

@Override
public void launchesChanged(ILaunch[] launches) {
}

@Override
public void launchesAdded(ILaunch[] launches) {
}

@Override
public void launchesTerminated(ILaunch[] launches) {
terminatedLaunches.addAll(Arrays.asList(launches));
}
};

DebugPlugin.getDefault().getLaunchManager().addLaunchListener(listener);
ILaunch launch = workingCopy.launch(ILaunchManager.DEBUG_MODE, null);
IProcess process = null;

try {
process = DebugPlugin.newProcess(launch, new MockProcess(0), "test");
waitWhile(() -> !terminatedLaunches.contains(launch), () -> "Launch termination event did not occur");
IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(DebugPlugin.getUniqueIdentifier());
String stamp = prefs.get(workingCopy.getName(), null);
assertNotNull(stamp, "Missing persisted terminate timestamp");
long timestamp = Long.parseLong(stamp);
assertTrue(timestamp <= System.currentTimeMillis(), "Terminate timestamp should be before current time");
} finally {
DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(listener);
if (launch != null) {
getLaunchManager().removeLaunch(launch);
}
if (process != null) {
process.terminate();
}
}
}

@Test
public void testLocalTerminateTimeStampPersistence() throws Exception {
ILaunchConfigurationWorkingCopy workingCopy = newConfiguration(null, "testLocalTerminateTimestamp");
Set<ILaunch> terminatedLaunches = Collections.synchronizedSet(new HashSet<>());

ILaunchesListener2 listener = new ILaunchesListener2() {
@Override
public void launchesRemoved(ILaunch[] launches) {
}

@Override
public void launchesChanged(ILaunch[] launches) {
}

@Override
public void launchesAdded(ILaunch[] launches) {
}

@Override
public void launchesTerminated(ILaunch[] launches) {
terminatedLaunches.addAll(Arrays.asList(launches));
}
};
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(listener);
ILaunch launch = workingCopy.launch(ILaunchManager.DEBUG_MODE, null);
IProcess process = null;

try {
process = DebugPlugin.newProcess(launch, new MockProcess(0), "test");
waitWhile(() -> !terminatedLaunches.contains(launch), () -> "Launch termination event did not occur");
ILaunchConfiguration config = launch.getLaunchConfiguration();
assertNotNull(config);
assertTrue(config.isLocal());
String timeStamp = config.getAttribute(DebugPlugin.ATTR_TERMINATE_TIMESTAMP, (String) null);
assertNotNull(timeStamp, "Terminate timestamp was not persisted");
long timestamp = Long.parseLong(timeStamp);
assertTrue(timestamp <= System.currentTimeMillis(), "Terminate timestamp should be before current time");
} finally {
DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(listener);
if (launch != null) {
getLaunchManager().removeLaunch(launch);
}
if (process != null) {
process.terminate();
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -261,5 +261,12 @@ public class ActionMessages extends NLS {
public static String ExpressionPasteDialog;
public static String ExpressionPasteRemember;
public static String ExpressionPastePromptButton;
public static String LaunchActionToolTip_Seconds;
public static String LaunchActionToolTip_Minutes;
public static String LaunchActionToolTip_OneMinute;
public static String LaunchActionToolTip_OneHour;
public static String LaunchActionToolTip_Hours;
public static String LaunchActionToolTip_OneDay;
public static String LaunchActionToolTip_Days;

}
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,15 @@ ExpressionPasteSingleButton=Single Expression
ExpressionPastePromptButton=Prompt
ExpressionPasteTitle=Paste Multiline Expression
ExpressionPasteDialog=You are pasting a multiline expression. Choose whether to paste it as a single combined expression or as separate multiple expressions.
ExpressionPasteRemember=Remember my preference next time
ExpressionPasteRemember=Remember my preference next time

LaunchActionToolTip_Seconds = a moment ago
LaunchActionToolTip_OneMinute = 1 min ago
LaunchActionToolTip_Minutes = {0} mins ago
LaunchActionToolTip_OneHour = 1 hour ago
LaunchActionToolTip_Hours = {0} hours ago
LaunchActionToolTip_OneDay = 1 day ago
LaunchActionToolTip_Days = {0} days ago



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, 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -22,6 +22,8 @@

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
Expand Down Expand Up @@ -50,6 +52,7 @@
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
Expand Down Expand Up @@ -353,6 +356,8 @@ protected void fillMenu(Menu menu) {
LaunchAction action= new LaunchAction(launch, getMode());
if (checkIfLaunchActive(launch, launches)) {
action.setText(action.getText() + " \u2699"); //$NON-NLS-1$
} else {
addRecentLaunchTimeTooltip(launch, action);
}
addToMenu(menu, action, accelerator);
accelerator++;
Expand All @@ -368,6 +373,8 @@ protected void fillMenu(Menu menu) {
LaunchAction action= new LaunchAction(launch, getMode());
if (checkIfLaunchActive(launch, launches)) {
action.setText(action.getText() + " \u2699"); //$NON-NLS-1$
} else {
addRecentLaunchTimeTooltip(launch, action);
}
addToMenu(menu, action, accelerator);
Comment thread
SougandhS marked this conversation as resolved.
accelerator++;
Expand Down Expand Up @@ -627,4 +634,71 @@ private LaunchConfigurationManager getLaunchConfigurationManager() {
protected String getLaunchGroupIdentifier() {
return fLaunchGroup.getIdentifier();
}

/**
* Adds a tooltip showing how long ago the given launch was terminated if
* there's a valid terminate timestamp attribute.
*
* @param launch launch configuration
* @param launchAction launch action to update
*/
private void addRecentLaunchTimeTooltip(ILaunchConfiguration launch, LaunchAction launchAction) {
try {
String timeStamp;
if (launch.isLocal()) {
timeStamp = launch.getAttribute(DebugPlugin.ATTR_TERMINATE_TIMESTAMP, ""); //$NON-NLS-1$
} else {
IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(DebugPlugin.getUniqueIdentifier());
timeStamp = prefs.get(launch.getName(), ""); //$NON-NLS-1$
}

if (!timeStamp.isEmpty()) {
long timestamp = Long.parseLong(timeStamp);
launchAction.setToolTipText(getRelativeTime(timestamp));
}
} catch (CoreException | NumberFormatException e) {
DebugUIPlugin.log(e);
}
}

/**
* Returns a human-readable relative time string for the given timestamp.
*
* @param timestamp timestamp in milliseconds since the epoch
* @return relative time string
*/
private String getRelativeTime(long timestamp) {
long diffMillis = Math.max(0L, System.currentTimeMillis() - timestamp);
long seconds = diffMillis / 1000;

if (seconds < 60) {
return ActionMessages.LaunchActionToolTip_Seconds;
}

long minutes = seconds / 60;

if (minutes == 1) {
return ActionMessages.LaunchActionToolTip_OneMinute;
}
if (minutes < 60) {
return NLS.bind(ActionMessages.LaunchActionToolTip_Minutes, minutes);
}

long hours = minutes / 60;

if (hours == 1) {
return ActionMessages.LaunchActionToolTip_OneHour;
}
if (hours < 24) {
return NLS.bind(ActionMessages.LaunchActionToolTip_Hours, hours);
}

long days = hours / 24;

if (days == 1) {
return ActionMessages.LaunchActionToolTip_OneDay;
}
return NLS.bind(ActionMessages.LaunchActionToolTip_Days, days);
}

}
Loading