Skip to content

Commit

Permalink
Adding opt-in to use the api.lsp services to fill in language feature…
Browse files Browse the repository at this point in the history
…s for a given mime-type.
  • Loading branch information
lahodaj committed Oct 9, 2024
1 parent 8cab2ae commit 9fb21fe
Show file tree
Hide file tree
Showing 11 changed files with 635 additions and 53 deletions.
1 change: 1 addition & 0 deletions ide/api.lsp/nbproject/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
</test-dependencies>
<public-packages>
<package>org.netbeans.api.lsp</package>
<package>org.netbeans.api.lsp.bridge</package>
<package>org.netbeans.spi.lsp</package>
</public-packages>
</data>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.api.lsp.bridge;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.PACKAGE)
public @interface RegisterLSPServices {
public String[] mimeTypes();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.netbeans.modules.lsp.bridge;

import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import org.netbeans.api.lsp.bridge.RegisterLSPServices;
import org.openide.filesystems.annotations.LayerBuilder;
import org.openide.filesystems.annotations.LayerBuilder.File;
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
import org.openide.filesystems.annotations.LayerGenerationException;
import org.openide.util.lookup.ServiceProvider;

@ServiceProvider(service=Processor.class)
public final class RegisterLSPServicesProcessor extends LayerGeneratingProcessor {

@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> hash = new HashSet<String>();
hash.add(RegisterLSPServices.class.getCanonicalName());
return hash;
}

@Override
protected boolean handleProcess(
Set<? extends TypeElement> annotations, RoundEnvironment roundEnv
) throws LayerGenerationException {
for (Element e : roundEnv.getElementsAnnotatedWith(RegisterLSPServices.class)) {
RegisterLSPServices services = (RegisterLSPServices) e.getAnnotation(RegisterLSPServices.class);
if (services == null) {
continue;
}
LayerBuilder builder = layer(e);
for (String mimeType : services.mimeTypes()) {
File f = builder.file("Editors/" + mimeType + "/org-netbeans-modules-lsp-client-bridge-BridgingLanguageServerProvider.instance");
f.stringvalue("instanceOf", "org.netbeans.modules.lsp.client.spi.LanguageServerProvider");
f.write();
}
}
return true;
}

}
2 changes: 1 addition & 1 deletion ide/lsp.client/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.

javac.source=1.8
javac.release=17
javac.compilerargs=-Xlint -Xlint:-serial
javadoc.arch=${basedir}/arch.xml
release.external/org.eclipse.lsp4j-0.13.0.jar=modules/ext/org.eclipse.lsp4j-0.13.0.jar
Expand Down
102 changes: 56 additions & 46 deletions ide/lsp.client/src/org/netbeans/modules/lsp/client/LSPBindings.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import org.eclipse.lsp4j.WorkspaceEditCapabilities;
import org.eclipse.lsp4j.jsonrpc.Launcher;
import org.eclipse.lsp4j.launch.LSPLauncher;
import org.eclipse.lsp4j.services.LanguageClientAware;
import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.eclipse.lsp4j.services.WorkspaceService;
Expand Down Expand Up @@ -302,55 +303,64 @@ private static LSPBindings buildBindings(ServerDescription inDescription, Projec
foundServer = true;
try {
LanguageClientImpl lci = new LanguageClientImpl();
InputStream in = LanguageServerProviderAccessor.getINSTANCE().getInputStream(desc);
OutputStream out = LanguageServerProviderAccessor.getINSTANCE().getOutputStream(desc);
Process p = LanguageServerProviderAccessor.getINSTANCE().getProcess(desc);
Launcher.Builder<LanguageServer> launcherBuilder = new LSPLauncher.Builder<LanguageServer>()
.setLocalService(lci)
.setRemoteInterface(LanguageServer.class)
.setInput(in)
.setOutput(out)
.configureGson(gson -> {
gson.registerTypeAdapter(SemanticTokensLegend.class, new InstanceCreator<SemanticTokensLegend>() {
@Override
public SemanticTokensLegend createInstance(Type type) {
return new SemanticTokensLegend(Collections.emptyList(), Collections.emptyList());
}
LanguageServer server = LanguageServerProviderAccessor.getINSTANCE().getServer(desc);
Process process;
if (server == null) {
InputStream in = LanguageServerProviderAccessor.getINSTANCE().getInputStream(desc);
OutputStream out = LanguageServerProviderAccessor.getINSTANCE().getOutputStream(desc);
process = LanguageServerProviderAccessor.getINSTANCE().getProcess(desc);
Launcher.Builder<LanguageServer> launcherBuilder = new LSPLauncher.Builder<LanguageServer>()
.setLocalService(lci)
.setRemoteInterface(LanguageServer.class)
.setInput(in)
.setOutput(out)
.configureGson(gson -> {
gson.registerTypeAdapter(SemanticTokensLegend.class, new InstanceCreator<SemanticTokensLegend>() {
@Override
public SemanticTokensLegend createInstance(Type type) {
return new SemanticTokensLegend(Collections.emptyList(), Collections.emptyList());
}
});
gson.registerTypeAdapter(SemanticTokens.class, new InstanceCreator<SemanticTokens>() {
@Override
public SemanticTokens createInstance(Type type) {
return new SemanticTokens(Collections.emptyList());
}
});
});
gson.registerTypeAdapter(SemanticTokens.class, new InstanceCreator<SemanticTokens>() {
@Override
public SemanticTokens createInstance(Type type) {
return new SemanticTokens(Collections.emptyList());
}
});
});

if (LOG.isLoggable(Level.FINER)) {
PrintWriter pw = new PrintWriter(new Writer() {
StringBuffer sb = new StringBuffer();

@Override
public void write(char[] cbuf, int off, int len) throws IOException {
sb.append(cbuf, off, len);
}

@Override
public void flush() throws IOException {
LOG.finer(sb.toString());
}

@Override
public void close() throws IOException {
sb.setLength(0);
sb.trimToSize();
}
});
launcherBuilder.traceMessages(pw);
if (LOG.isLoggable(Level.FINER)) {
PrintWriter pw = new PrintWriter(new Writer() {
StringBuffer sb = new StringBuffer();

@Override
public void write(char[] cbuf, int off, int len) throws IOException {
sb.append(cbuf, off, len);
}

@Override
public void flush() throws IOException {
LOG.finer(sb.toString());
}

@Override
public void close() throws IOException {
sb.setLength(0);
sb.trimToSize();
}
});
launcherBuilder.traceMessages(pw);
}
Launcher<LanguageServer> launcher = launcherBuilder.create();
launcher.startListening();
server = launcher.getRemoteProxy();
} else {
process = null;
if (server instanceof LanguageClientAware aware) {
aware.connect(lci);
}
}
Launcher<LanguageServer> launcher = launcherBuilder.create();
launcher.startListening();
LanguageServer server = launcher.getRemoteProxy();
InitializeResult result = initServer(p, server, dir); //XXX: what if a different root is expected????
InitializeResult result = initServer(process, server, dir); //XXX: what if a different root is expected????
server.initialized(new InitializedParams());
b = new LSPBindings(server, result, LanguageServerProviderAccessor.getINSTANCE().getProcess(desc));
// Register cleanup via LSPReference#run
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import java.io.InputStream;
import java.io.OutputStream;
import org.eclipse.lsp4j.services.LanguageServer;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.modules.lsp.client.spi.LanguageServerProvider.LanguageServerDescription;
import org.openide.util.Exceptions;

Expand Down Expand Up @@ -51,6 +53,8 @@ public static void setINSTANCE (LanguageServerProviderAccessor instance) {
public abstract InputStream getInputStream(LanguageServerDescription desc);
public abstract OutputStream getOutputStream(LanguageServerDescription desc);
public abstract Process getProcess(LanguageServerDescription desc);
public abstract LanguageServer getServer(LanguageServerDescription desc);
public abstract LSPBindings getBindings(LanguageServerDescription desc);
public abstract void setBindings(LanguageServerDescription desc, LSPBindings bindings);
public abstract LanguageServerDescription createLanguageServerDescription(@NonNull LanguageServer server);
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,18 @@ protected void query(CompletionResultSet resultSet, Document doc, int caretOffse
}
for (CompletionItem i : items) {
String insert = i.getInsertText() != null ? i.getInsertText() : i.getLabel();
String leftLabel = encode(i.getLabel());
String leftLabel;
String rightLabel;
if (i.getDetail() != null) {
rightLabel = encode(i.getDetail());
if (i.getLabelDetails() != null) {
leftLabel = encode(i.getLabel() + (i.getLabelDetails().getDetail() != null ? i.getLabelDetails().getDetail() : ""));
rightLabel = encode(i.getLabelDetails().getDescription());
} else {
rightLabel = null;
leftLabel = encode(i.getLabel());
if (i.getDetail() != null) {
rightLabel = encode(i.getDetail());
} else {
rightLabel = null;
}
}
String sortText = i.getSortText() != null ? i.getSortText() : i.getLabel();
CompletionItemKind kind = i.getKind();
Expand Down Expand Up @@ -298,6 +304,7 @@ public String getText() {
default:
case "plaintext": documentation.append("<pre>\n").append(content.getValue()).append("\n</pre>"); break;
case "markdown": documentation.append(HtmlRenderer.builder().build().render(Parser.builder().build().parse(content.getValue()))); break;
case "html": documentation.append(content.getValue()); break;
}
}
return documentation.toString();
Expand Down
Loading

0 comments on commit 9fb21fe

Please sign in to comment.