From efc8dc57d1db96b18cd275f1611d1a997e10ee3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Thu, 26 Oct 2023 16:16:31 +0200 Subject: [PATCH] Try to provide semantic tokens... --- .../pde/ls/BNDLanguageServerClient.java | 86 ++++++++++++++++--- .../eclipse/pde/ls/bnd/BNDLanguageServer.java | 4 +- .../pde/ls/bnd/BNDTextDocumentService.java | 65 +++++++++++++- 3 files changed, 140 insertions(+), 15 deletions(-) diff --git a/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/BNDLanguageServerClient.java b/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/BNDLanguageServerClient.java index a29ff78cb2..3553fb47a4 100644 --- a/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/BNDLanguageServerClient.java +++ b/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/BNDLanguageServerClient.java @@ -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; @@ -28,8 +29,8 @@ public class BNDLanguageServerClient implements StreamConnectionProvider { - private PipedInputStream input; - private PipedOutputStream output; + private InputStream input; + private OutputStream output; private Future listening; @Override @@ -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 launcher = LSPLauncher.createServerLauncher(server, pipedInputStream, - pipedOutputStream); - input = new PipedInputStream(pipedOutputStream); - output = new PipedOutputStream(pipedInputStream); + LinkedBlockingQueue inqueue = new LinkedBlockingQueue<>(10 * 1024 * 104); + LinkedBlockingQueue outqueue = new LinkedBlockingQueue<>(10 * 1024 * 104); + Launcher launcher = LSPLauncher.createServerLauncher(server, new QueueInputStream(inqueue), + new QueueOutputStream(outqueue)); + input = new QueueInputStream(outqueue); + output = new QueueOutputStream(inqueue); listening = launcher.startListening(); } @@ -75,4 +76,69 @@ public void stop() { } } + private static final class QueueInputStream extends InputStream { + + private final BlockingQueue byteSource; + private boolean closed; + + public QueueInputStream(BlockingQueue 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 byteSink; + private boolean closed; + + public QueueOutputStream(BlockingQueue 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(); + } + } + + } + } diff --git a/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDLanguageServer.java b/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDLanguageServer.java index 0e98aba072..5eab959f93 100644 --- a/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDLanguageServer.java +++ b/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDLanguageServer.java @@ -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; @@ -56,7 +57,8 @@ public CompletableFuture 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); } diff --git a/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDTextDocumentService.java b/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDTextDocumentService.java index 531ff910db..74087263b1 100644 --- a/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDTextDocumentService.java +++ b/ui/org.eclipse.pde.ls/src/org/eclipse/pde/ls/bnd/BNDTextDocumentService.java @@ -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; @@ -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; @@ -76,17 +78,69 @@ public void didSave(DidSaveTextDocumentParams params) { public CompletableFuture semanticTokensFull(SemanticTokensParams params) { System.out.println("BNDTextDocumentService.semanticTokensFull()"); return withDocument(params.getTextDocument(), document -> { - SemanticTokens tokens = new SemanticTokens(); + + int lines = document.getNumberOfLines(); + List list = new ArrayList<>(lines); + for (int i = 0; i < lines; i++) { + list.add(document.getLineInformation(i)); + } + PropertiesLineReader reader = new PropertiesLineReader(document); + List 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 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 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, CompletionList>> completion(CompletionParams params) { System.out.println("BNDTextDocumentService.completion()"); @@ -123,4 +177,7 @@ private static interface DocumentCallable { V call(IDocument document) throws Exception; } + private static final record Token(int line, int startChar, int length, int tokenType, int tokenModifiers) { + } + }