1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-25 09:55:29 +02:00

lsp4e-cpp: Generate LSP FileEvents from ResourceChangeEvents

FileEvents are useful for indexing and lsp4e (so far) does not send
them. It is not clear whether or not this will be implemented in lsp4e.
In the mean time, lsp4e-cpp can have its own mechanism to generate
the events.

Change-Id: I09aac4fda7755260f47b73fd683ca6d2ad317f81
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
This commit is contained in:
Marc-Andre Laperle 2017-09-23 21:44:05 -04:00 committed by Marc-André Laperle
parent 2fe856426c
commit 9dbf2af399
2 changed files with 162 additions and 0 deletions

View file

@ -12,10 +12,15 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Platform;
import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider;
@ -25,6 +30,8 @@ public class CPPLanguageServer extends ProcessStreamConnectionProvider {
private static final String CLANG_LANGUAGE_SERVER = "clangd"; //$NON-NLS-1$
private IResourceChangeListener fResourceListener;
public CPPLanguageServer() {
List<String> commands = new ArrayList<>();
File clangServerLocation = getClangServerLocation();
@ -37,6 +44,43 @@ public class CPPLanguageServer extends ProcessStreamConnectionProvider {
setCommands(commands);
}
@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 CPPResourceChangeListener(project);
project.getWorkspace().addResourceChangeListener(fResourceListener);
break;
}
}
@Override
public String toString() {
return "C/C++ Language Server: " + super.toString(); //$NON-NLS-1$

View file

@ -0,0 +1,118 @@
/*******************************************************************************
* Copyright (c) 2017 Ericsson and others.
* 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
*******************************************************************************/
package org.eclipse.lsp4e.cpp.language;
import java.io.IOException;
import java.net.URI;
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;
/**
* A resource listener used to generate FileEvents, as part of the LSP. This
* only listens to Added, Changed, Removed event on a specific project that as a
* C/C++ language server started.
*/
@SuppressWarnings("restriction")
final class CPPResourceChangeListener implements IResourceChangeListener {
private final IProject fProject;
CPPResourceChangeListener(IProject project) {
fProject = project;
}
@Override
public void resourceChanged(IResourceChangeEvent event) {
LanguageServerDefinition definition = LanguageServersRegistry.getInstance().getDefinition(CPPLanguageServer.ID);
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 static List<FileEvent> createFileEventsFromResourceEvent(IResourceChangeEvent event) {
List<FileEvent> fileEvents = new ArrayList<>();
try {
event.getDelta().accept((delta) -> {
if (delta.getResource() instanceof IFile && isRelevantDelta(delta)) {
FileEvent fileEvent = createFileEventFromDelta(delta);
if (fileEvent != null) {
fileEvents.add(fileEvent);
}
}
return true;
}, false);
} catch (CoreException e) {
// Do nothing
}
return fileEvents;
}
private ProjectSpecificLanguageServerWrapper getLanguageSeverWrapper(LanguageServerDefinition definition) {
try {
return LanguageServiceAccessor.getLSWrapperForConnection(fProject, definition, false);
} 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);
}
}