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

Detect Apama, fix up settings, use stdio LSP, miscellaneous cleanup #63

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
86c26d3
Spike ExecutableResolver
bph-c8y Oct 23, 2024
5242bf8
Begin to use ExecutableResolver within Extension
bph-c8y Oct 23, 2024
1f6aea1
config: remove default apamahome, rationalise some descriptions
bph-c8y Oct 23, 2024
9d311db
settings: camel case for better VSCode rendering
bph-c8y Oct 23, 2024
858006e
make sure camelcase change is made in code
bph-c8y Oct 23, 2024
52d8d0d
ExecutableResolver: cleaning up, adding a logger, fixing a bug
bph-c8y Oct 23, 2024
229e7f1
extension: scope out roughly the logic to resolve apama_env on Unix
bph-c8y Oct 23, 2024
7d1b8fe
extension: roughly add back the automatic spawning logic
bph-c8y Nov 13, 2024
af1a3d8
extension: remove some of the weird spawning logic
bph-c8y Nov 13, 2024
dffc52f
Write up some Windows logic
bph-c8y Oct 23, 2024
17ae3ba
Move release notes from README.md to GitHub Releases
bph-c8y Oct 23, 2024
a6a776b
readme: more aggressive in requirements
bph-c8y Oct 23, 2024
05fad7c
README: more refinement
bph-c8y Oct 23, 2024
f158ef4
Don't resolve a failed path on failure
bph-c8y Oct 24, 2024
10363a8
Use ExecutableResolver to find correlator, rather than LSP
bph-c8y Oct 24, 2024
445a545
Remove language server host option
bph-c8y Oct 24, 2024
c764e41
extension: working spawn on Linux
bph-c8y Nov 18, 2024
14e4316
extension: experimental windows support
bph-c8y Nov 18, 2024
5d14789
extension: remove unused imports
bph-c8y Nov 18, 2024
7b6aa1c
extension: some clean up, split up logging for language server
bph-c8y Nov 18, 2024
2858fce
Attempt to clean up process (not working at the minute)
bph-c8y Nov 19, 2024
0aeed2f
lsp: migrate from tcp to stdio
bph-c8y Nov 25, 2024
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: 10 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,36 @@ For more information about Apama and EPL please visit the [Apama Community](http

Also available is a [VSCode extension for PySys testing](https://marketplace.visualstudio.com/items?itemName=ApamaCommunity.pysys-vscode-extension) .

## Features of the epl-syntax-highlighting extension
## Features of the plugin

* Enables features of the extension for correct matching versions of Apama.
* Supports EPL language diagnostics from Apama 10.5.3+
* Supports EPL language diagnostics.
* Support for debugging and launching pure single-file and multi-file EPL applications in a correlator.
* Supports use of the apama_project tool.
* Supports using the Apama Language Server for advanced syntax highlighting and error detection.
* Apama based settings for current and upcoming changes live.

## Requirements
A minimum version of Apama 10.15.5 is required for advanced functionality.

## Limitations

* Debug of deployed projects only.
* Diagnostics are limited to EPL files currently (imported packages may not work).
* Completion is currently only snippet and history based.

## Theme based syntax highlighting

Based on the theme you choose the EPL code will be highlighted and easier to read than plain text files. This has been the case since the beginning of this extension, but it is more complete now (v1.0) and won't change significantly from here onward.
## EPL Syntax highlighting

![example code](images/mainpage.PNG)

## Settings

There are various settings available for the extension now. All the Apama configuration entries are prefixed 'Apama', and searching for 'Apama' will show all of them.

* ApamaHome contains the path to the installation directory of the version you wish to use.
* apamaHome contains the path to the installation directory of the version you wish to use.
* DebugHost is the default host for a correlator started for debug (allowing remote instance).
* DebugPort is the default port for a correlator started for debug.
* LangserverType is a dropdown that controls the LSP for vscode, it can be local (starts and attaches), remote (attaches) or disabled.
* LangserverType is a dropdown that controls the LSP for vscode, it can be local (starts and attaches) or disabled.
* Langserver.Host is the host that vscode should connect to the Langserver on.
* Langserver.Port is the port the Langserver is running on.
* Langserver.MaxErrors is the maximum number of diagnostics that should be returned by the LSP (INACTIVE)
Expand Down Expand Up @@ -112,18 +114,8 @@ Debugging the application also follows the standard vscode patterns.

![tasks](images/10-debug.gif)

## Requirements

To use the diagnostics capability you must have version 10.5.3 or later of Apama installed.

## Development

## Release Notes

## v2.0.0

* Stops the extension startup from stealing application focus.
* Changes all extension preferences: the "softwareag" prefixed has been removed. No migration path is provided.
**Please see https://github.com/ApamaCommunity/apama-vscode-extensions/releases for the latest release notes. The notes below have been kept for historical purposes.**

## v1.2.1

Expand Down
32 changes: 8 additions & 24 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,45 +24,29 @@
"configuration": {
"title": "Apama",
"properties": {
"apama.apamahome": {
"apama.apamaHome": {
"type": "string",
"default": "c:\\apama",
"default": null,
"description": "Home directory for the Apama installation."
},
"apama.debugport": {
"apama.debugPort": {
"type": "integer",
"default": "15904",
"description": "Default port for correlator debugging."
"description": "Port for correlator debugging."
},
"apama.debughost": {
"apama.debugHost": {
"type": "string",
"default": "127.0.0.1",
"description": "Default host for correlator debugging."
"description": "Host for correlator debugging."
},
"apama.langserver.type": {
"apama.langServer.type": {
"type": "string",
"enum": [
"local",
"remote",
"disabled"
],
"default": "local",
"description": "Whether vscode should start the language server locally."
},
"apama.langserver.port": {
"type": "integer",
"default": "30030",
"description": "The Apama language server port."
},
"apama.langserver.host": {
"type": "string",
"default": "127.0.0.1",
"description": "Default host the Apama langserver will listen for connections on."
},
"apama.langserver.maxErrors": {
"type": "integer",
"default": "100",
"description": "The maximum number of diagnostics that the Apama language server will return."
"description": "Configure if the Language Server is enabled."
},
"apama.c8y.url": {
"type": "string",
Expand Down
6 changes: 3 additions & 3 deletions src/apama_debug/apamadebugconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export class ApamaDebugConfigurationProvider implements DebugConfigurationProvid
name: "Debug Apama Application",
request: "launch",
correlator: {
port: config.get("debugport"),
host: config.get("debughost"),
port: config.get("debugPort"),
host: config.get("debugHost"),
args: ["-g"]
}
}];
Expand Down Expand Up @@ -59,7 +59,7 @@ export class ApamaDebugConfigurationProvider implements DebugConfigurationProvid
config.injectionList = getInjectionList(this.apamaEnv, folder.uri.fsPath);
config.correlator = {};
config.correlator.host = "127.0.0.1";
config.correlator.port = workspace.getConfiguration("apama").get("debugport");
config.correlator.port = workspace.getConfiguration("apama").get("debugPort");
config.correlator.args = ["-g"];
}

Expand Down
4 changes: 2 additions & 2 deletions src/apama_util/apamaenvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ export class ApamaEnvironment {
private updateCommands() {
this.workspaceConfig = workspace.getConfiguration(confignode);
//overridden in config?
if (this.workspaceConfig.has('apamahome')) {
if (this.workspaceConfig.has('apamaHome')) {
//shouldn't be undefined here because has checks, but for linting need to cover
this.apamaHome = this.workspaceConfig.get('apamahome') || this.apamaHome;
this.apamaHome = this.workspaceConfig.get('apamaHome') || this.apamaHome;
}
else {
//otherwise set default in config
Expand Down
2 changes: 1 addition & 1 deletion src/apama_util/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class ApamaCommandProvider {
registerCommands(): void {

if (this.context !== undefined) {
const port: any = workspace.getConfiguration("apama").get("debugport");
const port: any = workspace.getConfiguration("apama").get("debugPort");
this.context.subscriptions.push.apply(this.context.subscriptions,
[
//
Expand Down
130 changes: 62 additions & 68 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,70 @@
"use_strict";

import * as net from 'net';
import * as os from 'os';
import * as path from 'path';

import { ExtensionContext, Disposable, tasks, debug, workspace, WorkspaceConfiguration} from 'vscode';

import {
LanguageClient, LanguageClientOptions, ServerOptions
Executable,
LanguageClient, LanguageClientOptions,
TransportKind
} from 'vscode-languageclient/node';


import { ApamaEnvironment } from './apama_util/apamaenvironment';
import { ApamaTaskProvider } from './apama_util/apamataskprovider';
import { ApamaDebugConfigurationProvider } from './apama_debug/apamadebugconfig';
import { ApamaProjectView } from './apama_project/apamaProjectView';
import { ApamaCommandProvider } from './apama_util/commands';//MY CHANGES
import { ApamaRunner } from './apama_util/apamarunner';
import { ApamaCommandProvider } from './apama_util/commands';
import { Logger } from './logger/logger';
//import { CumulocityView } from './c8y/cumulocityView';

import * as semver from 'semver';
import { ExecutableResolver } from './settings/ExecutableResolver';

let client : LanguageClient;
let languageClient : LanguageClient;
const logger = new Logger('ApamaCommunity.apama-extensions');

//
// client activation function, this is the entrypoint for the client
//
export async function activate(context: ExtensionContext): Promise<void> {
/**
* Extension entry point.
*/
const commands: Disposable[] = [];

const logger = new Logger('ApamaCommunity.apama-extensions');

logger.appendLine('Started EPL Extension');

const config = workspace.getConfiguration('apama');
const userApamaHome = config.get('apamaHome');

// See if we can find a correlator.
const executableResolver = new ExecutableResolver("correlator", logger)

let resolve;
if (userApamaHome != undefined) {
// If the user has specified an Apama Home, we only use that.
resolve = await executableResolver.resolve(path.join(userApamaHome as string, "bin"));
} else {
resolve = await executableResolver.resolve();
}

if (resolve.kind == "success") {
logger.info(`executableResolve.resolve(): ${resolve.path}`)
} else {
logger.info(`Could not find Apama on system`);
return Promise.resolve();
}

createLangServerTCP(config, `${path.dirname(resolve.path)}/apama_env`);

const apamaEnv: ApamaEnvironment = new ApamaEnvironment();
const taskprov = new ApamaTaskProvider(logger, apamaEnv);
context.subscriptions.push(tasks.registerTaskProvider("apama", taskprov));

const provider = new ApamaDebugConfigurationProvider(logger, apamaEnv);

context.subscriptions.push(debug.registerDebugConfigurationProvider('apama', provider));

context.subscriptions.push(provider);

const commandprov = new ApamaCommandProvider(logger, apamaEnv, context);

commands.push(commandprov);

//this needs a workspace folder which under some circumstances can be undefined.
//but we can ignore in that case and things shjould still work
if (workspace.workspaceFolders !== undefined) {
Expand All @@ -53,61 +73,36 @@ export async function activate(context: ExtensionContext): Promise<void> {
projView.refresh();
}

//EPL Applications view is still WIP - needs more work
//const c8yView = new CumulocityView(apamaEnv, logger, context);


// Checks that the specified correlator version is above 10.5.3 before attempting to
// connect to the language server.
let corrVersion = "";
const versionCmd = new ApamaRunner("version", apamaEnv.getCorrelatorCmdline());
versionCmd.run(".", ["--version"]).then( version => {
const versionlines = version.stdout.split('\n');
const pat = new RegExp(/correlator\sv(\d+\.\d+\.\d+)\.\d+\.\d+/);
for (let index = 0; index < versionlines.length; index++) {
const line = versionlines[index];
if (pat.test(line)) {
corrVersion = RegExp.$1;
}
}

if (semver.lt(corrVersion, '10.5.3')) {
logger.appendLine(`Version: ${corrVersion} doesn't support the Apama Language Server - Skipping`);
}
else {
const config = workspace.getConfiguration("apama.langserver");
createLangServerTCP(apamaEnv, config, logger);
}
})

// Push the disposable to the context's subscriptions so that the
// client can be deactivated on extension deactivation
commands.forEach(command => context.subscriptions.push(command));

return Promise.resolve();
}


// This method connects to an existing language server running.
// It used to spawn a language server, but it did so inconsistently depending on configuration,
// and in an unorthodox manner.
async function createLangServerTCP(apamaEnv: ApamaEnvironment, config: WorkspaceConfiguration, logger: Logger): Promise<LanguageClient> {
async function createLangServerTCP(config: WorkspaceConfiguration, apamaEnvPath: string): Promise<null> {
/**
* Spawns a language server, and then proceeds to connect the language client up to it.
*/
const lsType: string | undefined = config.get<string>("type");
if (lsType === "disabled") {
return Promise.reject("Apama Language Server disabled");
}

const serverOptions: ServerOptions = () => {
return new Promise((resolve) => {
const clientSocket = new net.Socket();
clientSocket.connect(config.port, config.host, () => {
logger.debug(`Connected to socket at: ${config.host}:${config.port}`)
resolve({
reader: clientSocket,
writer: clientSocket,
});
});
});
let commandStr;
let args;
if (os.platform() == "win32") {
commandStr = `${path.dirname(apamaEnvPath)}/eplbuddy.exe`
args = ['-s']
} else {
commandStr = apamaEnvPath
args = [`eplbuddy`, "-s"]
}

const serverOptions: Executable = {
transport: TransportKind.stdio,
command: commandStr,
args: args
};

// Options of the language client
Expand All @@ -122,14 +117,13 @@ async function createLangServerTCP(apamaEnv: ApamaEnvironment, config: Workspace
fileEvents: workspace.createFileSystemWatcher('**/.mon')
}
};

client = new LanguageClient(`Apama Language Client (host ${config.host} port ${config.port})`, serverOptions, clientOptions);
await client.start();
return client;
languageClient = new LanguageClient(`Apama Language Client`, serverOptions, clientOptions);
await languageClient.start();
return null;
}

// this method is called when your extension is deactivated
export function deactivate() : void { return; }



export function deactivate() {
return Promise.all([
languageClient.stop(),
]);
}
Loading
Loading