PT #150740880: VSCode/Eclipse file watching. Back to project finder

Eclipse client file change listening mechanics

Reworked file/project observer implementation

Merge fixes
This commit is contained in:
BoykoAlex
2017-10-13 17:06:59 -04:00
parent aef5d309c6
commit d4a9907b0d
62 changed files with 1455 additions and 1056 deletions

View File

@@ -15,7 +15,8 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0",
org.eclipse.ui.workbench,
org.eclipse.jface,
org.eclipse.xtext.xbase.lib,
org.springframework.tooling.ls.eclipse.commons
org.springframework.tooling.ls.eclipse.commons,
org.eclipse.core.resources
Import-Package: com.google.gson;version="2.7.0",
org.eclipse.jface.preference,
org.eclipse.lsp4j.jsonrpc.messages;version="0.1.0.v20170117-0759",

View File

@@ -13,6 +13,7 @@ package org.springframework.tooling.boot.java.ls;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import org.eclipse.lsp4e.server.StreamConnectionProvider;
@@ -41,7 +42,12 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi
this.provider = new SpringBootJavaLanguageServer();
}
}
@Override
public Object getInitializationOptions(URI rootUri) {
return provider.getInitializationOptions(rootUri);
}
@Override
public void start() throws IOException {
this.provider.start();

View File

@@ -0,0 +1,132 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.tooling.boot.java.ls;
import java.io.IOException;
import java.net.URI;
import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.lsp4e.LanguageServersRegistry;
import org.eclipse.lsp4e.LanguageServersRegistry.LanguageServerDefinition;
import org.eclipse.lsp4e.LanguageServiceAccessor;
import org.eclipse.lsp4e.ProjectSpecificLanguageServerWrapper;
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
import org.eclipse.lsp4j.FileChangeType;
import org.eclipse.lsp4j.FileEvent;
/**
* Resource listener for LSP4E taken from CPP-LS
* https://github.com/eclipse/cdt/blob/master/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/CPPResourceChangeListener.java
*
* @author Alex Boyko
*
*/
@SuppressWarnings("restriction")
public class ResourceListener implements IResourceChangeListener {
private final String lsId;
private final IProject fProject;
private List<PathMatcher> pathMatchers;
ResourceListener(String lsId, IProject project, List<PathMatcher> pathMatchers) {
this.lsId = lsId;
fProject = project;
this.pathMatchers = pathMatchers;
}
@Override
public void resourceChanged(IResourceChangeEvent event) {
LanguageServerDefinition definition = LanguageServersRegistry.getInstance().getDefinition(lsId);
ProjectSpecificLanguageServerWrapper wrapper = getLanguageSeverWrapper(definition);
if (event.getType() != IResourceChangeEvent.POST_CHANGE || !isRelevantDelta(event.getDelta())
|| wrapper == null) {
return;
}
sendFileEvents(wrapper, createFileEventsFromResourceEvent(event));
}
private static void sendFileEvents(ProjectSpecificLanguageServerWrapper wrapper, List<FileEvent> fileEvents) {
if (!fileEvents.isEmpty()) {
DidChangeWatchedFilesParams params = new DidChangeWatchedFilesParams(fileEvents);
wrapper.getServer().getWorkspaceService().didChangeWatchedFiles(params);
}
}
private List<FileEvent> createFileEventsFromResourceEvent(IResourceChangeEvent event) {
List<FileEvent> fileEvents = new ArrayList<>();
try {
event.getDelta().accept((delta) -> {
if (delta.getResource() instanceof IFile && isRelevantDelta(delta) && isApplicableFile((IFile) delta.getResource())) {
FileEvent fileEvent = createFileEventFromDelta(delta);
if (fileEvent != null) {
fileEvents.add(fileEvent);
}
}
return true;
}, false);
} catch (CoreException e) {
// Do nothing
}
return fileEvents;
}
private boolean isApplicableFile(IFile resource) {
return pathMatchers.stream().filter(m -> m.matches(resource.getLocation().toFile().toPath())).findFirst().isPresent();
}
private ProjectSpecificLanguageServerWrapper getLanguageSeverWrapper(LanguageServerDefinition definition) {
try {
return LanguageServiceAccessor.getLSWrapperForConnection(fProject, definition);
} catch (IOException e) {
// Do nothing
return null;
}
}
private static boolean isRelevantDelta(IResourceDelta delta) {
int kind = delta.getKind();
int flags = delta.getFlags();
if (delta.getResource() instanceof IFile && kind == IResourceDelta.CHANGED) {
return (flags & IResourceDelta.CONTENT) != 0;
}
return kind == IResourceDelta.ADDED || kind == IResourceDelta.CHANGED || kind == IResourceDelta.REMOVED;
}
private static FileEvent createFileEventFromDelta(IResourceDelta delta) {
URI locationURI = delta.getResource().getLocationURI();
if (locationURI == null) {
return null;
}
FileChangeType changeType = null;
if (delta.getKind() == IResourceDelta.ADDED) {
changeType = FileChangeType.Created;
} else if (delta.getKind() == IResourceDelta.CHANGED) {
changeType = FileChangeType.Changed;
} else if (delta.getKind() == IResourceDelta.REMOVED) {
changeType = FileChangeType.Deleted;
} else {
throw new IllegalStateException("Unsupported resource delta kind: " + delta.getKind()); //$NON-NLS-1$
}
return new FileEvent(locationURI.toString(), changeType);
}
}

View File

@@ -13,30 +13,30 @@ package org.springframework.tooling.boot.java.ls;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.internal.launching.StandardVMType;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider;
import org.eclipse.lsp4j.jsonrpc.messages.Message;
import org.eclipse.lsp4j.jsonrpc.messages.NotificationMessage;
import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.ui.PlatformUI;
import org.osgi.framework.Bundle;
import com.google.gson.JsonObject;
/**
* @author Martin Lippert
*/
@SuppressWarnings("restriction")
public class SpringBootJavaLanguageServer extends ProcessStreamConnectionProvider {
private ResourceListener fResourceListener;
public SpringBootJavaLanguageServer() {
List<String> commands = new ArrayList<>();
@@ -107,4 +107,44 @@ public class SpringBootJavaLanguageServer extends ProcessStreamConnectionProvide
Files.copy(stream, dataFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
@Override
public void stop() {
super.stop();
if (fResourceListener != null) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(fResourceListener);
fResourceListener = null;
}
}
@Override
public Object getInitializationOptions(URI rootPath) {
installResourceChangeListener(rootPath);
return super.getInitializationOptions(rootPath);
}
private void installResourceChangeListener(URI rootPath) {
if (rootPath == null || fResourceListener != null) {
return;
}
IContainer[] containers = ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(rootPath);
if (containers.length == 0) {
return;
}
for (IContainer c : containers) {
if (!(c instanceof IProject)) {
continue;
}
IProject project = (IProject) c;
fResourceListener = new ResourceListener("org.eclipse.languageserver.languages.springbootjava", project, Arrays.asList(
FileSystems.getDefault().getPathMatcher("glob:**/pom.xml"),
FileSystems.getDefault().getPathMatcher("glob:**/build.gradle")
));
project.getWorkspace().addResourceChangeListener(fResourceListener);
break;
}
}
}