blob: c145fac24c089cdc20ba301eb5170041c9884ccc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Red Hat Inc. and others.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Mickael Istria (Red Hat Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.lsp4e.server;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.lsp4j.jsonrpc.messages.Message;
import org.eclipse.lsp4j.services.LanguageServer;
/**
* Abstraction of a connection which we can start/stop and connect to via streams.
* It's typically used to wrap startup of language servers and to retrieve their
* streams.
* There most likely an existing Java class already taking care of this somewhere
* in a popular API. In such case, we should consider getting read of this one and
* use a more popular similar interface.
* Note that in the context of Eclipse, the ILaunch might be such interface but I'm
* not sure we want to bind to org.eclipse.debug from this Language Server bindings.
*
* This method MUST implement meaningful {@link #hashCode()} and {@link #equals(Object)}
* to prevent multiple connections to be initiated multiple times.
*
* @since 0.1.0
*/
public interface StreamConnectionProvider {
public void start() throws IOException;
public InputStream getInputStream();
public OutputStream getOutputStream();
/**
* Returns the {@link InputStream} connected to the error output of the process
* running the language server. If the error output is redirected to standard
* output it returns <code>null</code>.
*
* @return the {@link InputStream} connected to the error output of the language
* server process or <code>null</code> if it's redirected or process not
* yet started.
*/
public @Nullable InputStream getErrorStream();
/**
* Forwards a copy of an {@link InputStream} to an {@link OutputStream}.
*
* @param input
* the {@link InputStream} that will be copied
* @param output
* the {@link OutputStream} to forward the copy to
* @return a newly created {@link InputStream} that copies all data to the
* provided {@link OutputStream}
*/
public default InputStream forwardCopyTo(InputStream input, OutputStream output) {
if (input == null)
return null;
if (output == null)
return input;
FilterInputStream filterInput = new FilterInputStream(input) {
@Override
public int read() throws IOException {
int res = super.read();
System.err.print((char) res);
return res;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int bytes = super.read(b, off, len);
byte[] payload = new byte[bytes];
System.arraycopy(b, off, payload, 0, bytes);
output.write(payload, 0, payload.length);
return bytes;
}
@Override
public int read(byte[] b) throws IOException {
int bytes = super.read(b);
byte[] payload = new byte[bytes];
System.arraycopy(b, 0, payload, 0, bytes);
output.write(payload, 0, payload.length);
return bytes;
}
};
return filterInput;
}
/**
* User provided initialization options.
*/
public default Object getInitializationOptions(URI rootUri){
return null;
}
/**
* Returns an object that describes the experimental features supported
* by the client.
* @implNote The returned object gets serialized by LSP4J, which itself uses
* GSon, so a GSon object can work too.
* @since 0.12
* @return an object whose fields represent the different experimental features
* supported by the client.
*/
public default Object getExperimentalFeaturesPOJO() {
return null;
}
/**
* Provides trace level to be set on language server initialization.<br>
* Legal values: "off" | "messages" | "verbose".
*
* @param rootUri
* the workspace root URI.
*
* @return the initial trace level to set
* @see "https://microsoft.github.io/language-server-protocol/specification#initialize"
*/
public default String getTrace(URI rootUri) {
return "off"; //$NON-NLS-1$
}
public void stop();
/**
* Allows to hook custom behavior on messages.
* @param message a message
* @param languageServer the language server receiving/sending the message.
* @param rootURI
*/
public default void handleMessage(Message message, LanguageServer languageServer, URI rootURI) {}
}