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:
parent
2fe856426c
commit
9dbf2af399
2 changed files with 162 additions and 0 deletions
|
@ -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$
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue