Skip to content

Commit

Permalink
Try to provide semantic tokens...
Browse files Browse the repository at this point in the history
  • Loading branch information
laeubi committed Oct 26, 2023
1 parent 69573b3 commit efc8dc5
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@

import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;

import org.eclipse.lsp4e.server.StreamConnectionProvider;
import org.eclipse.lsp4j.jsonrpc.Launcher;
Expand All @@ -28,8 +29,8 @@

public class BNDLanguageServerClient implements StreamConnectionProvider {

private PipedInputStream input;
private PipedOutputStream output;
private InputStream input;
private OutputStream output;
private Future<Void> listening;

@Override
Expand All @@ -51,12 +52,12 @@ public OutputStream getOutputStream() {
public void start() throws IOException {
System.out.println("BNDLanguageServerClient.start()");
BNDLanguageServer server = new BNDLanguageServer();
PipedOutputStream pipedOutputStream = new PipedOutputStream();
PipedInputStream pipedInputStream = new PipedInputStream();
Launcher<LanguageClient> launcher = LSPLauncher.createServerLauncher(server, pipedInputStream,
pipedOutputStream);
input = new PipedInputStream(pipedOutputStream);
output = new PipedOutputStream(pipedInputStream);
LinkedBlockingQueue<Integer> inqueue = new LinkedBlockingQueue<>(10 * 1024 * 104);
LinkedBlockingQueue<Integer> outqueue = new LinkedBlockingQueue<>(10 * 1024 * 104);
Launcher<LanguageClient> launcher = LSPLauncher.createServerLauncher(server, new QueueInputStream(inqueue),
new QueueOutputStream(outqueue));
input = new QueueInputStream(outqueue);
output = new QueueOutputStream(inqueue);
listening = launcher.startListening();
}

Expand All @@ -75,4 +76,69 @@ public void stop() {
}
}

private static final class QueueInputStream extends InputStream {

private final BlockingQueue<Integer> byteSource;
private boolean closed;

public QueueInputStream(BlockingQueue<Integer> byteSource) {
this.byteSource = byteSource;
}

@Override
public int read() throws IOException {
if (closed) {
return -1;
}
try {
Integer take = byteSource.take();
if (take < 0) {
closed = true;
}
return take;
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}

@Override
public void close() throws IOException {
closed = true;
}

}

private static final class QueueOutputStream extends OutputStream {

private final BlockingQueue<Integer> byteSink;
private boolean closed;

public QueueOutputStream(BlockingQueue<Integer> byteSink) {
this.byteSink = byteSink;
}

@Override
public void write(int b) throws IOException {
if (closed) {
throw new IOException("closed");
}
try {
byteSink.put(b);
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}

@Override
public void close() throws IOException {
closed = true;
try {
byteSink.put(-1);
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.eclipse.lsp4j.CompletionOptions;
import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4j.InitializeResult;
import org.eclipse.lsp4j.SemanticTokenModifiers;
import org.eclipse.lsp4j.SemanticTokenTypes;
import org.eclipse.lsp4j.SemanticTokensLegend;
import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
Expand Down Expand Up @@ -56,7 +57,8 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
res.getCapabilities().setTextDocumentSync(TextDocumentSyncKind.Full);
res.getCapabilities().setSemanticTokensProvider(
new SemanticTokensWithRegistrationOptions(
new SemanticTokensLegend(List.of(SemanticTokenTypes.Keyword), List.of()),
new SemanticTokensLegend(List.of(SemanticTokenTypes.Property, SemanticTokenTypes.Comment),
List.of(SemanticTokenModifiers.Readonly)),
Boolean.TRUE));
return CompletableFuture.completedFuture(res);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*******************************************************************************/
package org.eclipse.pde.ls.bnd;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
Expand All @@ -35,6 +36,7 @@
import aQute.bnd.help.Syntax;
import aQute.bnd.properties.Document;
import aQute.bnd.properties.IDocument;
import aQute.bnd.properties.IRegion;
import aQute.bnd.properties.LineType;
import aQute.bnd.properties.PropertiesLineReader;

Expand Down Expand Up @@ -76,17 +78,69 @@ public void didSave(DidSaveTextDocumentParams params) {
public CompletableFuture<SemanticTokens> semanticTokensFull(SemanticTokensParams params) {
System.out.println("BNDTextDocumentService.semanticTokensFull()");
return withDocument(params.getTextDocument(), document -> {
SemanticTokens tokens = new SemanticTokens();

int lines = document.getNumberOfLines();
List<IRegion> list = new ArrayList<>(lines);
for (int i = 0; i < lines; i++) {
list.add(document.getLineInformation(i));
}

PropertiesLineReader reader = new PropertiesLineReader(document);
List<Token> tokens = new ArrayList<>();
LineType type;
while ((type = reader.next()) != LineType.eof) {
// TODO how to use SemanticTokens ?!?
// TODO https://github.com/eclipse/lsp4e/issues/861 woudl be good to encode
// type/modifier not by plain int...
if (type == LineType.entry) {
String key = reader.key();
IRegion region = reader.region();
tokens.add(new Token(getLine(region, list), 0, key.length(), 0, 0));
} else if (type == LineType.comment) {
// TODO https://github.com/bndtools/bnd/issues/5843
IRegion region = reader.region();
tokens.add(new Token(getLine(region, list), 0, region.getLength(), 1, 0));
}
}
// TODO https://github.com/eclipse/lsp4e/issues/861
return null;
SemanticTokens semanticTokens = new SemanticTokens(new ArrayList<>());
List<Integer> data = semanticTokens.getData();
int lastLine = 0;
int lastStartChar = 0;
// See
// https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#textDocument_semanticTokens
for (Token token : tokens) {
// TODO https://github.com/eclipse/lsp4e/issues/861 can Token record + encoding
// probably be part of lsp4j?
System.out.println(token);
int lineDelta = token.line() - lastLine;
data.add(lineDelta);
if (lastLine == token.line()) {
data.add(token.startChar() - lastStartChar);
} else {
data.add(token.startChar());
}
data.add(token.length());
data.add(token.tokenType());
data.add(token.tokenModifiers());
lastLine = token.line();
lastStartChar = token.startChar();
}
return semanticTokens;
});
}

private int getLine(IRegion region, List<IRegion> list) {
int s = region.getOffset();
for (int i = 0; i < list.size(); i++) {
IRegion r = list.get(i);
int offsetStart = r.getOffset();
int offsetEnd = offsetStart + r.getLength();
if (s >= offsetStart && s <= offsetEnd) {
return i;
}
}
return -1;
}

@Override
public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(CompletionParams params) {
System.out.println("BNDTextDocumentService.completion()");
Expand Down Expand Up @@ -123,4 +177,7 @@ private static interface DocumentCallable<V> {
V call(IDocument document) throws Exception;
}

private static final record Token(int line, int startChar, int length, int tokenType, int tokenModifiers) {
}

}

0 comments on commit efc8dc5

Please sign in to comment.