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

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions org.eclipse.wildwebdeveloper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
"astro-vscode" : "2.15.4",
"firefox-debugadapter": "2.15.0",
"typescript": "5.9.2",
"typescript-language-server": "4.3.4",
"typescript-language-server": "4.4.1",
"typescript-lit-html-plugin": "0.9.0",
"typescript-plugin-css-modules": "5.2.0",
"yaml-language-server": "1.18.0",
"vscode-css-languageservice": "6.3.7",
"vscode-html-languageservice": "5.5.1",
"vscode-json-languageservice": "5.6.1",
"@vue/language-server" : "2.2.10",
"@vue/typescript-plugin" : "2.2.10",
"@vue/language-server" : "3.0.7",
"@vue/typescript-plugin" : "3.0.7",
"fsevents" : "2.3.3",
"vscode-css-languageserver": "file:target/vscode-css-languageserver-1.0.0.tgz",
"vscode-html-languageserver": "file:target/vscode-html-languageserver-1.0.0.tgz",
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.wildwebdeveloper/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@
<server
class="org.eclipse.wildwebdeveloper.jsts.JSTSLanguageServer"
clientImpl="org.eclipse.wildwebdeveloper.jsts.JSTSLanguageClientImpl"
serverInterface="org.eclipse.wildwebdeveloper.jsts.JSTSLanguageServerAPI"
id="org.eclipse.wildwebdeveloper.jsts"
label="JavaScript-TypeScript Language Server">
</server>
Expand Down Expand Up @@ -568,7 +569,6 @@
clientImpl="org.eclipse.wildwebdeveloper.vue.VueClientImpl"
serverInterface="org.eclipse.wildwebdeveloper.vue.VueLanguageServerAPI"
id="org.eclipse.wildwebdeveloper.vue"
singleton="true"
label="VUE Language Server"/>
<contentTypeMapping contentType="org.eclipse.wildwebdeveloper.vue" languageId="vue" id="org.eclipse.wildwebdeveloper.vue"/>
</extension>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public Object getInitializationOptions(URI rootUri) {
// plugins.add(new TypeScriptPlugin("@angular/language-service"));
plugins.add(new TypeScriptPlugin("typescript-plugin-css-modules"));
plugins.add(new TypeScriptPlugin("typescript-lit-html-plugin"));
plugins.add(new TypeScriptPlugin("@vue/typescript-plugin", new String[] {"vue"}));
plugins.add(new TypeScriptPlugin("@vue/typescript-plugin", "@vue/language-server", new String[] {"vue"}));
options.put("plugins", plugins.stream().map(TypeScriptPlugin::toMap).toArray());

// If the tsserver path is not explicitly specified, tsserver will use the local
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*******************************************************************************
* Copyright (c) Dawid Pakuła 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:
* Dawid Pakuła <[email protected]> - initial implementation
*******************************************************************************/
package org.eclipse.wildwebdeveloper.jsts;

import org.eclipse.lsp4j.services.LanguageServer;

public interface JSTSLanguageServerAPI extends LanguageServer {

public final static String TS_REQUEST_COMMAND = "typescript.tsserverRequest";
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ public TypeScriptPlugin(String name) throws IOException {
}

public TypeScriptPlugin(String name, String[] languages) throws IOException {
this(name, name, null);
}

public TypeScriptPlugin(String name, String locationName, String[] languages) throws IOException {
pluginName = name;
URL fileURL = FileLocator.toFileURL(getClass().getResource("/node_modules/" + name));
URL fileURL = FileLocator.toFileURL(getClass().getResource("/node_modules/" + locationName));
pluginProbeLocation = new File(fileURL.getPath()).getAbsolutePath();
pluginLanguages = languages;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*******************************************************************************
* Copyright (c) 2025 Dawid Pakuła 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:
* Dawid Pakuła <[email protected]> - initial implementation
*******************************************************************************/
package org.eclipse.wildwebdeveloper.jsts.request;

public class ExecuteInfo {

private int executionTarget = 0;

private boolean expectsResult = true;

private boolean isAsync = false;

private boolean lowPriority = true;

public int getExecutionTarget() {
return executionTarget;
}

public void setExecutionTarget(int executionTarget) {
this.executionTarget = executionTarget;
}

public boolean isExpectsResult() {
return expectsResult;
}

public void setExpectsResult(boolean expectsResult) {
this.expectsResult = expectsResult;
}

public boolean isAsync() {
return isAsync;
}

public void setAsync(boolean isAsync) {
this.isAsync = isAsync;
}

public boolean isLowPriority() {
return lowPriority;
}

public void setLowPriority(boolean lowPriority) {
this.lowPriority = lowPriority;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,82 @@
*******************************************************************************/
package org.eclipse.wildwebdeveloper.vue;

import static org.eclipse.wildwebdeveloper.css.ui.preferences.CSSPreferenceServerConstants.isMatchCssSection;
import static org.eclipse.wildwebdeveloper.html.ui.preferences.HTMLPreferenceServerConstants.isMatchHtmlSection;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import org.eclipse.lsp4e.LanguageClientImpl;
import org.eclipse.lsp4e.client.DefaultLanguageClient;
import org.eclipse.lsp4j.ConfigurationItem;
import org.eclipse.lsp4j.ConfigurationParams;
import org.eclipse.lsp4j.MessageParams;
import org.eclipse.lsp4j.MessageType;
import org.eclipse.wildwebdeveloper.css.ui.preferences.CSSPreferenceServerConstants;
import org.eclipse.wildwebdeveloper.html.ui.preferences.HTMLPreferenceServerConstants;
import org.eclipse.wildwebdeveloper.ui.preferences.Settings;

public class VueClientImpl extends LanguageClientImpl implements VueLanguageServerExtention {
public class VueClientImpl extends DefaultLanguageClient implements VueLanguageServerExtention {

@Override
public void projectLoadingFinish(Object object) {
// TODO should this set some state because only now stuff will work like hover..
// or maybe even after projectLanguageService "enabled" call
logMessage(new MessageParams(MessageType.Info, "Vue project loading finished"));
}

@Override
public void projectLoadingStart(Object object) {
logMessage(new MessageParams(MessageType.Info, "Vue project loading started"));
}

@Override
public void projectLanguageService(Map<String,Object> data) {
logMessage(new MessageParams(MessageType.Info, "Language Service is " + (((Boolean)data.get("languageServiceEnabled")).booleanValue()?"":"not yet ") + "enabled for project " + data.get("projectName")));
public void projectLanguageService(Map<String, Object> data) {
logMessage(new MessageParams(MessageType.Info,
"Language Service is "
+ (((Boolean) data.get("languageServiceEnabled")).booleanValue() ? "" : "not yet ")
+ "enabled for project " + data.get("projectName")));
}

@Override
public void tsserverRequest(Object[] params) {
logMessage(new MessageParams(MessageType.Info, "Forward TS message " + params[0]));
}

@Override
public CompletableFuture<List<Object>> configuration(ConfigurationParams params) {
return CompletableFuture.supplyAsync(() -> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vue consume same configuration as HTML/CSS LS, so I just copy/paste

// The HTML language server asks for a given uri, the settings for 'css',
// 'javascript', 'html'
// See
// https://github.com/microsoft/vscode/blob/7bd27b4287b49e61a1cb49e18f370260144c8685/extensions/html-language-features/server/src/htmlServer.ts#L123
List<Object> settings = new ArrayList<>();
for (ConfigurationItem item : params.getItems()) {
String section = item.getSection();
if (isMatchHtmlSection(section)) {
// 'html' section, returns the html settings
Settings htmlSettings = HTMLPreferenceServerConstants.getGlobalSettings();
settings.add(htmlSettings.findSettings(section.split("[.]")));
} else if (isMatchCssSection(section)) {
// 'css' section, returns the css settings
Settings cssSettings = CSSPreferenceServerConstants.getGlobalSettings();
settings.add(cssSettings.findSettings(section.split("[.]")));
} else if (section.equals("vue.suggest.defineAssignment")) {
settings.add(true);
} else if (section.equals("vue.suggest.propNameCasing")) {
settings.add("preferKebabCase");
} else if (section.equals("vue.suggest.componentNameCasing")) {
settings.add("preferPascalCase");
} else {
// TODO match javascript section once those preferences will be
// implemented.
settings.add(null);
}
}
return settings;
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,41 @@
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.ILog;
import org.eclipse.lsp4e.LSPEclipseUtils;
import org.eclipse.lsp4e.LanguageServers;
import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider;
import org.eclipse.lsp4j.ExecuteCommandParams;
import org.eclipse.lsp4j.jsonrpc.messages.Message;
import org.eclipse.lsp4j.jsonrpc.messages.NotificationMessage;
import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.wildwebdeveloper.embedder.node.NodeJSManager;
import org.eclipse.wildwebdeveloper.jsts.JSTSLanguageServerAPI;
import org.eclipse.wildwebdeveloper.jsts.request.ExecuteInfo;

public class VueLanguageServer extends ProcessStreamConnectionProvider {
private static String tsserverPath = null;
private static String vuePath = null;
private static String TS_REQUEST = "tsserver/request";

public VueLanguageServer() {

List<String> commands = new ArrayList<>();
commands.add(NodeJSManager.getNodeJsLocation().getAbsolutePath());
try {
if (vuePath == null || tsserverPath == null) {
if (vuePath == null) {
resolvePaths();
}
commands.add(vuePath);
commands.add("--stdio");
setCommands(commands);
setWorkingDirectory(System.getProperty("user.dir"));
//setWorkingDirectory(System.getProperty("user.dir"));
} catch (IOException e) {
ILog.get().error(e.getMessage(), e);
}
Expand All @@ -53,44 +60,56 @@ private void resolvePaths() throws IOException {
URL url = FileLocator
.toFileURL(getClass().getResource("/node_modules/@vue/language-server/bin/vue-language-server.js"));
vuePath = new File(url.getPath()).getAbsolutePath();

url = FileLocator.toFileURL(getClass().getResource("/node_modules/typescript/lib"));
tsserverPath = new File(url.getPath()).getAbsolutePath();

}


@Override
protected ProcessBuilder createProcessBuilder() {
ProcessBuilder builder = super.createProcessBuilder();
builder.environment().put("VUE_NONPOLLING_WATCHER", Boolean.toString(true));
builder.environment().put("NODE_ENV", "production");
return builder;
}

@Override
public Object getInitializationOptions(URI rootUri) {
Map<String, Object> options = new HashMap<>();
setWorkingDirectory(Paths.get(rootUri).toString());

options.put("typescript", Collections.singletonMap("tsdk", tsserverPath));
options.put("diagnosticModel", 0);
options.put("additionalExtensions", new String[] {});

Map<String, Object> legend = new HashMap<>();
legend.put("tokenTypes", new String[] {"component"} );
legend.put("tokenModifiers", new String[] {} );
options.put("semanticTokensLegend", legend);

Map<String, Object> vue = new HashMap<>();
vue.put("hybridMode", false);

options.put("vue", vue);

return options;
public String toString() {
return "VUE Language Server: " + super.toString();
}

@Override
public String toString() {
return "VUE Language Server: " + super.toString();
public void handleMessage(Message message, LanguageServer languageServer, URI rootURI) {
Copy link
Contributor Author

@zulus zulus Sep 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone have know howto move this to VueClientImpl I'll be happy to do this

if (message instanceof NotificationMessage) {
NotificationMessage msg = (NotificationMessage) message;
if (msg.getMethod().equals(TS_REQUEST)) {
forwardTS((Object[]) msg.getParams(), (VueLanguageServerAPI) languageServer, rootURI);
}
}
super.handleMessage(message, languageServer, rootURI);
}

@SuppressWarnings("restriction")
private void forwardTS(Object[] params, VueLanguageServerAPI languageServer, URI rootURI) {
Object requestId = params[0];
String commandId = (String) params[1];
Object args = params.length > 2 ? params[2] : null;

LanguageServers.forProject(LSPEclipseUtils.findResourceFor(rootURI).getProject())
.collectAll((w, ls) -> CompletableFuture.completedFuture(ls)).thenAccept((lss) -> {
lss.stream().filter(JSTSLanguageServerAPI.class::isInstance).map(JSTSLanguageServerAPI.class::cast)
.findAny().ifPresent(jsts -> {
jsts.getWorkspaceService()
.executeCommand(new ExecuteCommandParams(JSTSLanguageServerAPI.TS_REQUEST_COMMAND,
Arrays.asList(new Object[] { commandId, args, new ExecuteInfo() })))
.whenComplete((result, e) -> {
Object body = null;
if (result instanceof Map) {
body = ((Map<?, ?>)result).get("body");
}
languageServer.tsserverResponse(new Object[] {requestId, body});
});
});
});
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.concurrent.CompletableFuture;

import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.wildwebdeveloper.vue.autoinsert.AutoInsertParams;
Expand All @@ -38,5 +39,9 @@ public interface VueLanguageServerAPI extends LanguageServer {
@JsonRequest("volar/client/autoInsert")
CompletableFuture<Either<String, AutoInsertResponse>> autoInsert(AutoInsertParams params);

@JsonNotification("tsserver/response")
void tsserverResponse(Object any);



}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ public interface VueLanguageServerExtention {

@JsonNotification(value = "vue/projectLanguageService")
public void projectLanguageService(Map<String,Object> data);


@JsonNotification(value = "tsserver/request")
public void tsserverRequest(Object[] params);
}
Loading