Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions ide/lsp.client/apichanges.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,34 @@
<apidef name="lsp_client">LSP Client API</apidef>
</apidefs>
<changes>
<change id="LanguageIdProvider">
<api name="lsp_client" />
<summary>Adding LanguageIdProvider</summary>
<version major="0" minor="1.34" />
<date day="27" month="2" year="2026" />
<author login="mmatblsi" />
<compatibility addition="yes" binary="compatible" source="compatible" />
<description>
<p>
While NetBeans uses mimetypes as primary identifier for source types,
LSP uses languageId as a carrier to inform what language/type of file
is being edited. Even a single language server can provide support
for multiple languages. One such example is the typescript language
server, which defaults to typescript, but also supports the
typescript variant that embeds react templates (TSX).
</p>
<p>
To support this an implementation can provide a resolver. The
resolver has to implement the interface
<code>org.netbeans.modules.lsp.client.spi.LanguageIdResolver</code>
and will be provided by a lookup provided to the
<code>LanguageServerDescription</code>. For each opened file
the resolver will be called with the file object and will return
the language id if it can resolve it for the given file.
</p>
</description>
<class name="LanguageIdResolver" package="org.netbeans.modules.lsp.client.spi"/>
</change>
<change id="MultiMimeLanguageServerProvider">
<api name="lsp_client" />
<summary>Adding MultiMimeLanguageServerProvider</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import org.netbeans.modules.lsp.client.bindings.LanguageClientImpl;
import org.netbeans.modules.lsp.client.bindings.TextDocumentSyncServerCapabilityHandler;
import org.netbeans.modules.lsp.client.options.MimeTypeInfo;
import org.netbeans.modules.lsp.client.spi.LanguageIdResolver;
import org.netbeans.modules.lsp.client.spi.ServerRestarter;
import org.netbeans.modules.lsp.client.spi.LanguageServerProvider;
import org.netbeans.modules.lsp.client.spi.LanguageServerProvider.LanguageServerDescription;
Expand Down Expand Up @@ -372,7 +373,9 @@ public void close() throws IOException {
}
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));
process = LanguageServerProviderAccessor.getINSTANCE().getProcess(desc);
Lookup serverLookup = LanguageServerProviderAccessor.getINSTANCE().getLookup(desc);
b = new LSPBindings(server, result, process, serverLookup.lookup(LanguageIdResolver.class));
// Register cleanup via LSPReference#run
new LSPReference(b, Utilities.activeReferenceQueue());
lci.setBindings(b);
Expand Down Expand Up @@ -426,7 +429,7 @@ public void write(int w) throws IOException {
LanguageServer server = launcher.getRemoteProxy();
InitializeResult result = initServer(null, server, root);
server.initialized(new InitializedParams());
LSPBindings bindings = new LSPBindings(server, result, null);
LSPBindings bindings = new LSPBindings(server, result, null, null);

lc.setBindings(bindings);

Expand Down Expand Up @@ -521,11 +524,13 @@ public static synchronized Set<LSPBindings> getAllBindings() {
private final LanguageServer server;
private final InitializeResult initResult;
private final Process process;
private final LanguageIdResolver languageIdResolver;

private LSPBindings(LanguageServer server, InitializeResult initResult, Process process) {
private LSPBindings(LanguageServer server, InitializeResult initResult, Process process, LanguageIdResolver languageIdResolver) {
this.server = server;
this.initResult = initResult;
this.process = process;
this.languageIdResolver = languageIdResolver;
}

public TextDocumentService getTextDocumentService() {
Expand All @@ -541,6 +546,16 @@ public InitializeResult getInitResult() {
return initResult;
}

public String resolveLanguageId(FileObject fileObject) {
if(languageIdResolver != null) {
String languageId = languageIdResolver.resolveLanguageId(fileObject);
if (languageId != null) {
return languageId;
}
}
return FileUtil.getMIMEType(fileObject);
}

@SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
public static synchronized void addBackgroundTask(FileObject file, BackgroundTask task) {
RequestProcessor.Task req = WORKER.create(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.modules.lsp.client.spi.LanguageServerProvider.LanguageServerDescription;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;

/**
*
Expand Down Expand Up @@ -57,4 +58,5 @@ public static void setINSTANCE (LanguageServerProviderAccessor instance) {
public abstract LSPBindings getBindings(LanguageServerDescription desc);
public abstract void setBindings(LanguageServerDescription desc, LSPBindings bindings);
public abstract LanguageServerDescription createLanguageServerDescription(@NonNull LanguageServer server);
public abstract Lookup getLookup(LanguageServerDescription desc);
}
Original file line number Diff line number Diff line change
Expand Up @@ -315,14 +315,13 @@ private void ensureDidOpenSent(Document doc, boolean sync) {
}
});

// @todo: the mimetype is not the language ID
TextDocumentItem textDocumentItem = new TextDocumentItem(uri,
FileUtil.getMIMEType(file),
0,
text[0]);

for (LSPBindings server : servers) {
if (server.getOpenedFiles().add(file)) {
TextDocumentItem textDocumentItem = new TextDocumentItem(uri,
server.resolveLanguageId(file),
0,
text[0]);
server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(textDocumentItem));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ ACSD_Marks_CB=Keep Marks Checkbox

text/x-generic-lsp=Language Server Protocol Client (generic)
LanguageDescriptionPanel.debugger.text=Enable &Breakpoints
LanguageDescriptionPanel.languageIdLabel.text=Language Identifier:
LanguageDescriptionPanel.languageId.text=
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.netbeans.api.io.InputOutput;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.modules.lsp.client.spi.LanguageIdResolver;
import org.netbeans.modules.lsp.client.spi.LanguageServerProvider;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
Expand All @@ -35,6 +36,7 @@
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.Lookups;

/**
*
Expand All @@ -57,6 +59,7 @@ public LanguageServerDescription startServer(Lookup lookup) {
FileObject server = FileUtil.getConfigFile("Editors/" + mti.mimeType + "/org-netbeans-modules-lsp-client-options-GenericLanguageServer.instance");
String[] command = (String[]) server.getAttribute("command");
String name = (String) server.getAttribute("name");
String languageId = (String) server.getAttribute("languageId");

if (name == null) {
name = command[0];
Expand Down Expand Up @@ -130,7 +133,16 @@ private void update() {
io.show();
}
});
return LanguageServerDescription.create(process.getInputStream(), process.getOutputStream(), process);
Lookup serverLookup = null;
if(languageId != null && ! languageId.isBlank()) {
serverLookup = Lookups.fixed(new LanguageIdResolver() {
@Override
public String resolveLanguageId(FileObject fileObject) {
return languageId;
}
});
}
return LanguageServerDescription.create(process.getInputStream(), process.getOutputStream(), process, serverLookup);
} catch (Throwable t) {
t.printStackTrace(); //TODO
return null;
Expand Down
Loading
Loading