Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Language and diagram server built using Gradle #85

Merged
merged 3 commits into from
Nov 15, 2022
Merged
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
14 changes: 14 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@
"request": "launch",
"type": "extensionHost"
},
{
"env": {
"LF_LS_PORT": "7670"
},
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"name": "Launch Extension (Socket)",
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"request": "launch",
"type": "extensionHost"
},
{
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
Expand Down
2 changes: 1 addition & 1 deletion lingua-franca
Submodule lingua-franca updated 242 files
35 changes: 11 additions & 24 deletions src/build_lds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import simpleGit, { SimpleGit } from 'simple-git'
import { Command, OptionValues } from 'commander'
import * as config from './config'
import { exit } from 'process';
import { execSync } from 'child_process'
import { bold, green, red } from 'colorette'
import which from 'which'
import { javacVersionChecker, VersionCheckResult } from './version_checker';
Expand All @@ -34,30 +35,17 @@ function getOpts() {
}

/**
* Copy jars produced by the Maven build.
* Copy jar produced by the Gradle build.
*/
function copyJars() {
function copyJar() {
if (fs.existsSync(config.libDirPath)) {
rimraf.sync(config.libDirPath);
}
fs.mkdirSync(config.libDirPath);

// Copy the LDS jar.
fs.copyFileSync(config.ldsJarFile,
fs.copyFileSync(config.sourceLdsJarFile,
path.join(config.libDirPath, config.ldsJarName))

// Copy SWT plugins, needed by LDS.
fs.readdirSync(config.swtJarsDirPath).forEach(
(name: string) => {
let found = name.match(config.swtJarRegex)
if (found !== null) {
// Copy file, strip version numbers.
fs.copyFileSync(path.join(config.swtJarsDirPath, name),
path.join(config.libDirPath,
name.replace(found.groups.version, '')))
}
}
)
}

/**
Expand Down Expand Up @@ -129,14 +117,13 @@ async function build() {
} else {
await fetchDeps(opts).catch((err) => { console.log(err); process.exit(1)})
}
const mvn = (require('maven')).create({
cwd: repo
});
console.log("> starting Maven build...")
mvn.execute(['clean', 'package', '-P', 'lds', '-U'], { 'skipTests' : 'true' })
.then(() => {
copyJars()
});
console.log("> starting Gradle build...")
try {
execSync("./gradlew generateLanguageDiagramServer", { cwd: repo, stdio: 'inherit' });
copyJar();
} catch(e) {
console.error(e);
}
}

/**
Expand Down
26 changes: 3 additions & 23 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ export const rtiVersion: Version = new Version('0.0.0');
/** Name of the Language and Diagram Server jar. */
export const ldsJarName = 'lflang-lds.jar';

/** Regex for matching SWT jars and capturing their version number. */
export const swtJarRegex = /org\.eclipse\.swt\..+(?<version>\.x86.+)\.jar$/;

/** Name of the Language and Diagram Server package. */
export const pkgName = 'org.lflang.lds';

/** Name of the Lingua Franca repo. */
export const repoName = 'lingua-franca';

Expand All @@ -78,21 +72,7 @@ export const baseDirPath = path.resolve(path.dirname(require.main.filename), '..
/** Absolute path to the directory in which to put the jar files. */
export const libDirPath = path.resolve(baseDirPath, libDirName);

/** Absolute path to the directory in which to find the SWT jar files. */
export const swtJarsDirPath = path.resolve(baseDirPath,
path.join(repoName, pkgName, 'target', 'repository', 'plugins'));

/** Absolute path to the language and diagram server jar. */
export const ldsJarFile = path.resolve(baseDirPath,
path.join(repoName, pkgName, 'target', 'exe', ldsJarName));

/** Dictionary mapping OSes to the names of their corresponding SWT jars. */
export const swtJarsByOs = defaultDict('org.eclipse.swt.gtk.linux.jar')({
'win32': 'org.eclipse.swt.win32.win32.jar',
'darwin': 'org.eclipse.swt.cocoa.macosx.jar'
});

/** Dictionary mapping OSes to their corresponding classpath separators. */
export const classPathSeparatorsByOs = defaultDict(':')({
'win32': ';',
});
// TODO handle version in file name
export const sourceLdsJarFile = path.resolve(baseDirPath,
path.join(repoName, 'org.lflang.diagram', 'build', 'libs', 'org.lflang.diagram-0.3.1-SNAPSHOT-lds.jar'));
lhstrh marked this conversation as resolved.
Show resolved Hide resolved
71 changes: 55 additions & 16 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import * as fs from 'fs';

import { Trace } from 'vscode-jsonrpc';
import * as vscode from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient';
import { connect, NetConnectOpts, Socket } from 'net';
import { LanguageClient, LanguageClientOptions, ServerOptions, StreamInfo } from 'vscode-languageclient';
import { legend, semanticTokensProvider } from './highlight';
import * as config from './config';
import { registerBuildCommands } from './build_commands';
import * as checkDependencies from './check_dependencies';

let client: LanguageClient;
let socket: Socket

export async function activate(context: vscode.ExtensionContext) {

Expand All @@ -30,20 +32,8 @@ export async function activate(context: vscode.ExtensionContext) {
(vscode.window.showErrorMessage)
()
)) return;
const jarInLibDir = filename => context.asAbsolutePath(path.join(config.libDirName, filename));
const ldsJar = jarInLibDir(config.ldsJarName);
const swtJar = jarInLibDir(config.swtJarsByOs[os.platform()]);
console.assert(fs.existsSync(ldsJar));
const javaArgs = [
'-cp',
ldsJar + config.classPathSeparatorsByOs[os.platform()] + swtJar,
'org.lflang.diagram.lsp.LanguageDiagramServer'
];

const serverOptions: ServerOptions = {
run : { command: 'java', args: javaArgs },
debug: { command: 'java', args: javaArgs, options: { env: createDebugEnv() } }
};

const serverOptions: ServerOptions = createServerOptions(context);

const clientOptions: LanguageClientOptions = {
documentSelector: ['lflang'],
Expand All @@ -68,6 +58,48 @@ export async function activate(context: vscode.ExtensionContext) {
registerBuildCommands(context, client);
}

/**
* Depending on the launch configuration, returns {@link ServerOptions} that either
* connects to a socket or starts the LS as a process. It uses a socket if the
* environment variable `LF_LS_PORT` is present. Otherwise it runs the jar located
* at `lib/lflang-lds.jar`.
*/
function createServerOptions(context: vscode.ExtensionContext): ServerOptions {
// Connect to language server via socket if a port is specified as an env variable
if (typeof process.env.LF_LS_PORT !== 'undefined') {
const connectionInfo: NetConnectOpts = {
port: parseInt(process.env.LF_LS_PORT, 10),
};
console.log('Connecting to language server on port: ', connectionInfo.port);

return async () => {
socket = connect(connectionInfo);
const result: StreamInfo = {
writer: socket,
reader: socket,
};
return result;
};
} else { // Start LDS Jar
const ldsJar = context.asAbsolutePath(path.join(config.libDirName, config.ldsJarName));

console.log('Spawning the language server as a process.');
console.assert(fs.existsSync(ldsJar));

return {
run: {
command: 'java',
args: ['-Djava.awt.headless=true', '-jar', ldsJar]
},
debug: {
command: 'java',
args: ['-Djava.awt.headless=true', '-jar', ldsJar],
options: { env: createDebugEnv() }
},
};
}
}

function createDebugEnv() {
return Object.assign({
JAVA_OPTS:'-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n,quiet=y'
Expand All @@ -78,5 +110,12 @@ export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
return client.stop();
if (socket) {
// Don't call client.stop when we are connected via socket for development.
// That call will end the LS server, leading to a bad dev experience.
socket.end();
return;
} else {
return client.stop();
}
}