add bare bones for a lsp
This commit is contained in:
parent
6b60fa9d33
commit
52211ea02c
3
prometeu-lsp/prometeu-lsp-api/build.gradle.kts
Normal file
3
prometeu-lsp/prometeu-lsp-api/build.gradle.kts
Normal file
@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
id("gradle.java-library-conventions")
|
||||
}
|
||||
9
prometeu-lsp/prometeu-lsp-v1/build.gradle.kts
Normal file
9
prometeu-lsp/prometeu-lsp-v1/build.gradle.kts
Normal file
@ -0,0 +1,9 @@
|
||||
plugins {
|
||||
id("gradle.java-library-conventions")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":prometeu-infra"))
|
||||
|
||||
implementation("org.eclipse.lsp4j:org.eclipse.lsp4j:1.0.0")
|
||||
}
|
||||
@ -0,0 +1,271 @@
|
||||
package p.studio.lsp;
|
||||
|
||||
import org.eclipse.lsp4j.*;
|
||||
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
||||
import org.eclipse.lsp4j.launch.LSPLauncher;
|
||||
import org.eclipse.lsp4j.services.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public final class PrometeuStudioLspMain {
|
||||
|
||||
private static final String HOST = "127.0.0.1";
|
||||
private static final int PORT = 7777;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
InetAddress bindAddress = InetAddress.getByName(HOST);
|
||||
|
||||
try (ServerSocket serverSocket = new ServerSocket(PORT, 50, bindAddress)) {
|
||||
System.out.println("Prometeu Studio LSP listening on " + HOST + ":" + PORT);
|
||||
|
||||
while (true) {
|
||||
Socket socket = serverSocket.accept();
|
||||
|
||||
Thread clientThread = new Thread(() -> handleClient(socket));
|
||||
clientThread.setName("prometeu-lsp-client");
|
||||
clientThread.setDaemon(true);
|
||||
clientThread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleClient(Socket socket) {
|
||||
try {
|
||||
System.out.println("VS Code connected: " + socket.getRemoteSocketAddress());
|
||||
|
||||
InputStream input = socket.getInputStream();
|
||||
OutputStream output = socket.getOutputStream();
|
||||
|
||||
PrometeuLanguageServer server = new PrometeuLanguageServer();
|
||||
|
||||
Launcher<LanguageClient> launcher =
|
||||
LSPLauncher.createServerLauncher(server, input, output);
|
||||
|
||||
LanguageClient client = launcher.getRemoteProxy();
|
||||
server.connect(client);
|
||||
|
||||
launcher.startListening();
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("LSP client failed: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PrometeuLanguageServer implements LanguageServer, LanguageClientAware {
|
||||
|
||||
private LanguageClient client;
|
||||
private final TextDocumentService textDocumentService = new PrometeuTextDocumentService(this);
|
||||
private final WorkspaceService workspaceService = new PrometeuWorkspaceService();
|
||||
|
||||
private boolean shutdownRequested = false;
|
||||
|
||||
@Override
|
||||
public void connect(LanguageClient client) {
|
||||
this.client = client;
|
||||
|
||||
if (textDocumentService instanceof PrometeuTextDocumentService service) {
|
||||
service.connect(client);
|
||||
}
|
||||
}
|
||||
|
||||
public LanguageClient client() {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
|
||||
ServerCapabilities capabilities = new ServerCapabilities();
|
||||
|
||||
TextDocumentSyncOptions syncOptions = new TextDocumentSyncOptions();
|
||||
syncOptions.setOpenClose(true);
|
||||
syncOptions.setChange(TextDocumentSyncKind.Full);
|
||||
|
||||
SaveOptions saveOptions = new SaveOptions();
|
||||
saveOptions.setIncludeText(true);
|
||||
syncOptions.setSave(saveOptions);
|
||||
|
||||
capabilities.setTextDocumentSync(syncOptions);
|
||||
capabilities.setHoverProvider(true);
|
||||
|
||||
InitializeResult result = new InitializeResult(capabilities);
|
||||
|
||||
ServerInfo serverInfo = new ServerInfo();
|
||||
serverInfo.setName("Prometeu Studio LSP");
|
||||
serverInfo.setVersion("0.1.0");
|
||||
result.setServerInfo(serverInfo);
|
||||
|
||||
return CompletableFuture.completedFuture(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialized(InitializedParams params) {
|
||||
if (client != null) {
|
||||
client.logMessage(new MessageParams(
|
||||
MessageType.Info,
|
||||
"Hello from Prometeu Studio LSP"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> shutdown() {
|
||||
shutdownRequested = true;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit() {
|
||||
System.out.println("LSP client requested exit. shutdownRequested=" + shutdownRequested);
|
||||
|
||||
// Importantíssimo:
|
||||
// Como isso está dentro do Studio, NÃO use System.exit().
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDocumentService getTextDocumentService() {
|
||||
return textDocumentService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkspaceService getWorkspaceService() {
|
||||
return workspaceService;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PrometeuTextDocumentService implements TextDocumentService {
|
||||
|
||||
private final PrometeuLanguageServer server;
|
||||
private LanguageClient client;
|
||||
|
||||
private PrometeuTextDocumentService(PrometeuLanguageServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
private void connect(LanguageClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didOpen(DidOpenTextDocumentParams params) {
|
||||
String uri = params.getTextDocument().getUri();
|
||||
String text = params.getTextDocument().getText();
|
||||
|
||||
System.out.println("didOpen: " + uri);
|
||||
|
||||
publishHelloDiagnostic(uri, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChange(DidChangeTextDocumentParams params) {
|
||||
String uri = params.getTextDocument().getUri();
|
||||
|
||||
String text = "";
|
||||
if (!params.getContentChanges().isEmpty()) {
|
||||
text = params.getContentChanges().get(0).getText();
|
||||
}
|
||||
|
||||
System.out.println("didChange: " + uri);
|
||||
|
||||
publishHelloDiagnostic(uri, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didClose(DidCloseTextDocumentParams params) {
|
||||
String uri = params.getTextDocument().getUri();
|
||||
|
||||
System.out.println("didClose: " + uri);
|
||||
|
||||
if (client != null) {
|
||||
client.publishDiagnostics(new PublishDiagnosticsParams(uri, List.of()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didSave(DidSaveTextDocumentParams params) {
|
||||
String uri = params.getTextDocument().getUri();
|
||||
|
||||
System.out.println("didSave: " + uri);
|
||||
|
||||
if (client != null) {
|
||||
client.logMessage(new MessageParams(
|
||||
MessageType.Info,
|
||||
"Prometeu Studio saw save: " + uri
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Hover> hover(HoverParams params) {
|
||||
MarkupContent content = new MarkupContent();
|
||||
content.setKind(MarkupKind.MARKDOWN);
|
||||
content.setValue("""
|
||||
**Prometeu Studio LSP**
|
||||
|
||||
Hello from Java + LSP4J.
|
||||
|
||||
This hover came from the Studio process.
|
||||
""");
|
||||
|
||||
Hover hover = new Hover();
|
||||
hover.setContents(content);
|
||||
|
||||
return CompletableFuture.completedFuture(hover);
|
||||
}
|
||||
|
||||
private void publishHelloDiagnostic(String uri, String text) {
|
||||
if (client == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Diagnostic diagnostic = new Diagnostic();
|
||||
|
||||
diagnostic.setRange(new Range(
|
||||
new Position(0, 0),
|
||||
new Position(0, Math.max(1, firstLineLength(text)))
|
||||
));
|
||||
|
||||
diagnostic.setSeverity(DiagnosticSeverity.Information);
|
||||
diagnostic.setSource("Prometeu Studio");
|
||||
diagnostic.setMessage("Hello from Prometeu Studio LSP");
|
||||
|
||||
client.publishDiagnostics(new PublishDiagnosticsParams(
|
||||
uri,
|
||||
List.of(diagnostic)
|
||||
));
|
||||
}
|
||||
|
||||
private int firstLineLength(String text) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int newline = text.indexOf('\n');
|
||||
|
||||
if (newline < 0) {
|
||||
return text.length();
|
||||
}
|
||||
|
||||
return newline;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PrometeuWorkspaceService implements WorkspaceService {
|
||||
|
||||
@Override
|
||||
public void didChangeConfiguration(DidChangeConfigurationParams params) {
|
||||
System.out.println("didChangeConfiguration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
|
||||
System.out.println("didChangeWatchedFiles: " + params.getChanges().size() + " changes");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,9 +5,13 @@ plugins {
|
||||
rootProject.name = "prometeu-studio"
|
||||
|
||||
include("prometeu-infra")
|
||||
|
||||
include("prometeu-packer:prometeu-packer-api")
|
||||
include("prometeu-packer:prometeu-packer-v1")
|
||||
|
||||
include("prometeu-lsp:prometeu-lsp-api")
|
||||
include("prometeu-lsp:prometeu-lsp-v1")
|
||||
|
||||
include("prometeu-compiler:frontends:prometeu-frontend-pbs")
|
||||
include("prometeu-compiler:prometeu-compiler-core")
|
||||
include("prometeu-compiler:prometeu-build-pipeline")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
35
tools/vscode-extension/.gitignore
vendored
Normal file
35
tools/vscode-extension/.gitignore
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
# Build output
|
||||
out/
|
||||
dist/
|
||||
|
||||
# VS Code package output
|
||||
*.vsix
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
|
||||
# Logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Test / coverage
|
||||
coverage/
|
||||
.vscode-test/
|
||||
|
||||
# Environment / local config
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editor local state
|
||||
.vscode/settings.json
|
||||
.vscode/*.log
|
||||
17
tools/vscode-extension/.vscode/launch.json
vendored
Normal file
17
tools/vscode-extension/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run Prometeu VS Code Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: compile"
|
||||
}
|
||||
]
|
||||
}
|
||||
12
tools/vscode-extension/.vscode/tasks.json
vendored
Normal file
12
tools/vscode-extension/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "compile",
|
||||
"group": "build",
|
||||
"problemMatcher": "$tsc",
|
||||
"label": "npm: compile"
|
||||
}
|
||||
]
|
||||
}
|
||||
139
tools/vscode-extension/package-lock.json
generated
Normal file
139
tools/vscode-extension/package-lock.json
generated
Normal file
@ -0,0 +1,139 @@
|
||||
{
|
||||
"name": "prometeu-vscode-extension",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "prometeu-vscode-extension",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/vscode": "^1.90.0",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.90.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz",
|
||||
"integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/vscode": {
|
||||
"version": "1.118.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.118.0.tgz",
|
||||
"integrity": "sha512-Ah6eTlqDcwIMELEVwQMO++rJAFBRz/oLluLD/vWdYrH1KuI9kfpaM+7pg0OvvascgcJy+ghLCERAYouM4QbzGw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
|
||||
"integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "5.1.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
||||
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vscode-jsonrpc": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
|
||||
"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageclient": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz",
|
||||
"integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimatch": "^5.1.0",
|
||||
"semver": "^7.3.7",
|
||||
"vscode-languageserver-protocol": "3.17.5"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.82.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-protocol": {
|
||||
"version": "3.17.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
|
||||
"integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"vscode-jsonrpc": "8.2.0",
|
||||
"vscode-languageserver-types": "3.17.5"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-types": {
|
||||
"version": "3.17.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
|
||||
"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
69
tools/vscode-extension/package.json
Normal file
69
tools/vscode-extension/package.json
Normal file
@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "prometeu-vscode-extension",
|
||||
"displayName": "Prometeu VS Code Extension",
|
||||
"description": "VS Code bridge for Prometeu Studio.",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"vscode": "^1.90.0"
|
||||
},
|
||||
"categories": [
|
||||
"Programming Languages"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:pbs"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
"id": "pbs",
|
||||
"aliases": [
|
||||
"PBS",
|
||||
"Prometeu Base Script"
|
||||
],
|
||||
"extensions": [
|
||||
".pbs",
|
||||
".barrel"
|
||||
]
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "prometeu.connectStudioLsp",
|
||||
"title": "Prometeu: Connect to Studio LSP"
|
||||
},
|
||||
{
|
||||
"command": "prometeu.restartStudioLsp",
|
||||
"title": "Prometeu: Restart Studio LSP"
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"title": "Prometeu",
|
||||
"properties": {
|
||||
"prometeu.studio.host": {
|
||||
"type": "string",
|
||||
"default": "127.0.0.1",
|
||||
"description": "Prometeu Studio LSP host."
|
||||
},
|
||||
"prometeu.studio.port": {
|
||||
"type": "number",
|
||||
"default": 7777,
|
||||
"description": "Prometeu Studio LSP TCP port."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc -p ./",
|
||||
"watch": "tsc -watch -p ./"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/vscode": "^1.90.0",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
159
tools/vscode-extension/src/extension.ts
Normal file
159
tools/vscode-extension/src/extension.ts
Normal file
@ -0,0 +1,159 @@
|
||||
import * as net from "node:net";
|
||||
import * as vscode from "vscode";
|
||||
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
StreamInfo
|
||||
} from "vscode-languageclient/node";
|
||||
|
||||
let client: LanguageClient | undefined;
|
||||
let output: vscode.OutputChannel;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
output = vscode.window.createOutputChannel("Prometeu LSP");
|
||||
output.appendLine("Prometeu VS Code extension activated.");
|
||||
|
||||
const connectCommand = vscode.commands.registerCommand(
|
||||
"prometeu.connectStudioLsp",
|
||||
async () => {
|
||||
await startClient(context);
|
||||
}
|
||||
);
|
||||
|
||||
const restartCommand = vscode.commands.registerCommand(
|
||||
"prometeu.restartStudioLsp",
|
||||
async () => {
|
||||
await stopClient();
|
||||
await startClient(context);
|
||||
}
|
||||
);
|
||||
|
||||
context.subscriptions.push(output, connectCommand, restartCommand);
|
||||
|
||||
void startClient(context);
|
||||
}
|
||||
|
||||
export async function deactivate(): Promise<void> {
|
||||
await stopClient();
|
||||
}
|
||||
|
||||
async function startClient(context: vscode.ExtensionContext): Promise<void> {
|
||||
if (client) {
|
||||
output.appendLine("Prometeu LSP client is already running.");
|
||||
return;
|
||||
}
|
||||
|
||||
const config = vscode.workspace.getConfiguration("prometeu.studio");
|
||||
|
||||
const host = config.get<string>("host", "127.0.0.1");
|
||||
const port = config.get<number>("port", 7777);
|
||||
|
||||
output.show(true);
|
||||
output.appendLine(`Connecting to Prometeu Studio LSP at ${host}:${port}...`);
|
||||
|
||||
const serverOptions: ServerOptions = async (): Promise<StreamInfo> => {
|
||||
return new Promise<StreamInfo>((resolve, reject) => {
|
||||
const socket = net.createConnection({ host, port });
|
||||
|
||||
let settled = false;
|
||||
|
||||
const connectTimeout = setTimeout(() => {
|
||||
if (settled) {
|
||||
return;
|
||||
}
|
||||
|
||||
settled = true;
|
||||
socket.destroy();
|
||||
reject(new Error("Connection timed out."));
|
||||
}, 3000);
|
||||
|
||||
socket.once("connect", () => {
|
||||
if (settled) {
|
||||
return;
|
||||
}
|
||||
|
||||
settled = true;
|
||||
clearTimeout(connectTimeout);
|
||||
|
||||
output.appendLine("TCP connection established with Prometeu Studio.");
|
||||
|
||||
resolve({
|
||||
reader: socket,
|
||||
writer: socket
|
||||
});
|
||||
});
|
||||
|
||||
socket.once("error", (error) => {
|
||||
if (settled) {
|
||||
return;
|
||||
}
|
||||
|
||||
settled = true;
|
||||
clearTimeout(connectTimeout);
|
||||
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
documentSelector: [
|
||||
{
|
||||
scheme: "file",
|
||||
language: "pbs"
|
||||
}
|
||||
],
|
||||
synchronize: {
|
||||
fileEvents: [
|
||||
vscode.workspace.createFileSystemWatcher("**/*.pbs")
|
||||
]
|
||||
},
|
||||
initializationOptions: {
|
||||
clientKind: "vscode",
|
||||
prometeuClientVersion: context.extension.packageJSON.version
|
||||
},
|
||||
outputChannel: output
|
||||
};
|
||||
|
||||
client = new LanguageClient(
|
||||
"prometeuStudioLsp",
|
||||
"Prometeu Studio LSP",
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
|
||||
try {
|
||||
await client.start();
|
||||
|
||||
output.appendLine("Prometeu Studio LSP client started.");
|
||||
vscode.window.showInformationMessage("Connected to Prometeu Studio LSP.");
|
||||
} catch (error) {
|
||||
client = undefined;
|
||||
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
|
||||
output.appendLine(`Failed to start Prometeu LSP client: ${message}`);
|
||||
vscode.window.showErrorMessage(`Could not connect to Prometeu Studio LSP: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function stopClient(): Promise<void> {
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentClient = client;
|
||||
client = undefined;
|
||||
|
||||
output.appendLine("Stopping Prometeu Studio LSP client...");
|
||||
|
||||
try {
|
||||
await currentClient.stop();
|
||||
output.appendLine("Prometeu Studio LSP client stopped.");
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
output.appendLine(`Failed to stop Prometeu LSP client cleanly: ${message}`);
|
||||
}
|
||||
}
|
||||
20
tools/vscode-extension/tsconfig.json
Normal file
20
tools/vscode-extension/tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "Node16",
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"ES2022"
|
||||
],
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "Node16",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user