Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: a16edb817a1c32075eb77ef3f7fd3fb10e4a58c3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*******************************************************************************
 * 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;
	}

	/**
	 * 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) {}

}

Back to the top