PT #167595632: Update CMs after Classpath sent off to LS (Experimental)
This commit is contained in:
@@ -17,10 +17,14 @@ import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
@@ -58,6 +62,10 @@ import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IEditorReference;
|
||||
import org.eclipse.ui.IFileEditorInput;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.progress.UIJob;
|
||||
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
|
||||
@@ -358,6 +366,31 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
}
|
||||
}
|
||||
|
||||
public STS4LanguageClientImpl() {
|
||||
classpathService.addNotificationsSentCallback(projectNames -> {
|
||||
List<IProject> projects = projectNames.stream().map(projectName -> ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
for (IWorkbenchWindow ww : PlatformUI.getWorkbench().getWorkbenchWindows()) {
|
||||
for (IWorkbenchPage page : ww.getPages()) {
|
||||
for (IEditorReference editorRef : page.getEditorReferences()) {
|
||||
IEditorPart editor = editorRef.getEditor(false);
|
||||
if (editor != null) {
|
||||
if (editor.getEditorInput() instanceof IFileEditorInput) {
|
||||
IFile file = ((IFileEditorInput)editor.getEditorInput()).getFile();
|
||||
if (file != null && projects.contains(file.getProject())) {
|
||||
ITextViewer viewer = editor.getAdapter(ITextViewer.class);
|
||||
if (viewer instanceof ISourceViewerExtension5) {
|
||||
((ISourceViewerExtension5)viewer).updateCodeMinings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> addClasspathListener(ClasspathListenerParams params) {
|
||||
return CompletableFuture.completedFuture(classpathService.addClasspathListener(params.getCallbackCommandId(), params.isBatched()));
|
||||
|
||||
@@ -15,14 +15,22 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.management.Notification;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.ListenerList;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
@@ -32,10 +40,15 @@ import org.springframework.tooling.jdt.ls.commons.classpath.ClasspathListenerMan
|
||||
* {@link ReusableClasspathListenerHandler} is an 'abstracted' version of the jdtls ClasspathListenerHandler.
|
||||
*/
|
||||
public class ReusableClasspathListenerHandler {
|
||||
|
||||
public interface NotificationSentCallback {
|
||||
void sent(Collection<String> projectNames);
|
||||
}
|
||||
|
||||
private final Logger logger;
|
||||
private final ClientCommandExecutor conn;
|
||||
private final Supplier<Comparator<IProject>> projectSorterFactory;
|
||||
private final ListenerList<NotificationSentCallback> notificationsSentCallbacks;
|
||||
|
||||
public ReusableClasspathListenerHandler(Logger logger, ClientCommandExecutor conn) {
|
||||
this(logger, conn, null);
|
||||
@@ -45,13 +58,40 @@ public class ReusableClasspathListenerHandler {
|
||||
this.logger = logger;
|
||||
this.projectSorterFactory = projectSorterFactory;
|
||||
this.conn = conn;
|
||||
this.notificationsSentCallbacks = new ListenerList<>();
|
||||
logger.log("Instantiating ReusableClasspathListenerHandler");
|
||||
}
|
||||
|
||||
private class CallbackJob extends Job {
|
||||
|
||||
public CallbackJob() {
|
||||
super("Classpath Notiifcation Post Processing");
|
||||
setSystem(true);
|
||||
}
|
||||
|
||||
private Set<String> projectNames = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
if (!projectNames.isEmpty()) {
|
||||
notificationsSentCallbacks.forEach(callback -> callback.sent(projectNames));
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
|
||||
void queueProjects(Collection<String> projectNames) {
|
||||
this.projectNames.addAll(projectNames);
|
||||
schedule();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Subscriptions {
|
||||
|
||||
private Map<String, SendClasspathNotificationsJob> subscribers = null;
|
||||
private ClasspathListenerManager classpathListener = null;
|
||||
private CallbackJob callbackJob = new CallbackJob();
|
||||
|
||||
|
||||
public synchronized void subscribe(String callbackCommandId, boolean isBatched) {
|
||||
if (subscribers==null) {
|
||||
@@ -72,7 +112,19 @@ public class ReusableClasspathListenerHandler {
|
||||
}
|
||||
|
||||
});
|
||||
subscribers.put(callbackCommandId, new SendClasspathNotificationsJob(logger, conn, callbackCommandId, isBatched));
|
||||
final SendClasspathNotificationsJob job = new SendClasspathNotificationsJob(logger, conn, callbackCommandId, isBatched);
|
||||
subscribers.put(callbackCommandId, job);
|
||||
job.addJobChangeListener(new JobChangeAdapter() {
|
||||
|
||||
@Override
|
||||
public void done(IJobChangeEvent event) {
|
||||
List<String> projectNames = job.notificationsSentForProjects;
|
||||
if (projectNames != null) {
|
||||
callbackJob.queueProjects(projectNames);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
logger.log("subsribers = " + subscribers);
|
||||
sendInitialEvents(callbackCommandId);
|
||||
}
|
||||
@@ -167,4 +219,11 @@ public class ReusableClasspathListenerHandler {
|
||||
return subscribptions.isEmpty();
|
||||
}
|
||||
|
||||
public void addNotificationsSentCallback(NotificationSentCallback callback) {
|
||||
notificationsSentCallbacks.add(callback);
|
||||
}
|
||||
|
||||
public void removeNotificationsSentCallback(NotificationSentCallback callback) {
|
||||
notificationsSentCallbacks.remove(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
@@ -39,6 +40,8 @@ public class SendClasspathNotificationsJob extends Job {
|
||||
private final Logger logger;
|
||||
private String callbackCommandId;
|
||||
|
||||
List<String> notificationsSentForProjects;
|
||||
|
||||
/**
|
||||
* Used only if caller has requested 'batched' events. This buffer, accumulates messsages to be sent out all at once,
|
||||
* rather than one by one.
|
||||
@@ -103,6 +106,7 @@ public class SendClasspathNotificationsJob extends Job {
|
||||
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
notificationsSentForProjects = null;
|
||||
synchronized (projectLocations) { //Could use some Eclipse job rule. But its really a bit of a PITA to create the right one.
|
||||
try {
|
||||
// Try to see if classpath needs to be sent for the projects that have been
|
||||
@@ -177,6 +181,7 @@ public class SendClasspathNotificationsJob extends Job {
|
||||
try {
|
||||
logger.log("executing callback "+callbackCommandId+" "+projectName+" "+deleted+" "+ classpath.getEntries().size());
|
||||
Object r = conn.executeClientCommand(callbackCommandId, projectLoc.toString(), projectName, deleted, classpath);
|
||||
notificationsSentForProjects = ImmutableList.of(projectName);
|
||||
logger.log("executing callback "+callbackCommandId+" SUCCESS ["+r+"]");
|
||||
} catch (Exception e) {
|
||||
logger.log("executing callback "+callbackCommandId+" FAILED");
|
||||
@@ -190,6 +195,8 @@ public class SendClasspathNotificationsJob extends Job {
|
||||
try {
|
||||
logger.log("executing callback "+callbackCommandId+" "+buffer.size()+" batched events");
|
||||
Object r = conn.executeClientCommand(callbackCommandId, buffer.toArray(new Object[buffer.size()]));
|
||||
notificationsSentForProjects = ImmutableList.copyOf(buffer.stream().filter(l -> l instanceof List)
|
||||
.map(l -> (List<?>) l).map(l -> (String) l.get(1)).collect(Collectors.toList()));
|
||||
logger.log("executing callback "+callbackCommandId+" SUCCESS ["+r+"]");
|
||||
} catch (Exception e) {
|
||||
logger.log("executing callback "+callbackCommandId+" FAILED");
|
||||
|
||||
Reference in New Issue
Block a user