Skip to content
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
8 changes: 1 addition & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,7 @@ jobs:
- name: Build package
run: npm run esbuild

- name: Test language server
run: npm run test:server

- name: Test debugger
run: npm run test:debugger

- name: Test language server client
- name: Tests
run: |
Xvfb -ac :99 -screen 0 1280x1024x16 &
export DISPLAY=:99
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ licensed under the MIT license and adapted to the MetaModelica language server.
The debugger is based on [microsoft/vscode-mock-debug](https://github.com/microsoft/vscode-mock-debug) licensed under MIT.

[OpenModelica/tree-sitter-metamodelica](https://github.com/OpenModelica/tree-sitter-metamodelica)
v0.2.0 is included in this extension and is licensed under the [OSMC-PL
is included in this extension and is licensed under the [OSMC-PL
v1.8](./server/OSMC-License.txt).

## Acknowledgments
Expand Down
14 changes: 1 addition & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 3 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,10 @@
"test-compile": "tsc -b ./",
"lint": "eslint ./client/src ./server/src ./debugger/src --ext .ts,.tsx",
"tree-sitter-metamodelica": "cd src/server && node tree.sitter.metamodelica.download.js",
"tree-sitter-gdbmi": "cd node_modules/tree-sitter-gdbmi && npx tree-sitter generate && npx tree-sitter build --wasm --docker . && cd ../../scripts && node tree.sitter.gdbmi.js",
"tree-sitter-gdbmi": "cd node_modules/tree-sitter-gdbmi && npx tree-sitter generate && npx tree-sitter build --wasm --docker . && cd ../../src/debugger/parser && node tree.sitter.gdbmi.js",
"postinstall": "npm run tree-sitter-metamodelica && npm run tree-sitter-gdbmi",
"test-compile-post": "run-script-os",
"test-compile-post:win32": ".\\scripts\\e2e.bat",
"test-compile-post:default": "sh ./scripts/e2e.sh",
"test": "npm run test-compile && npm run test-compile-post",
"test:server": "cd test && npx mocha -r ts-node/register server/**/*.test.ts",
"test:debugger": "cd test && npx mocha -r ts-node/register debugger/**/*.test.ts",
"all": "npm run postinstall && npm run esbuild && npm run lint && npm run test:server && npm run test:debugger && npm run test && npm run vscode:prepublish"
"test": "npm run test-compile && node ./dist/test/runTest",
"all": "npm run postinstall && npm run esbuild && npm run lint && npm run test && npm run vscode:prepublish"
},
"dependencies": {
"vscode-languageclient": "^9.0.1",
Expand All @@ -156,7 +151,6 @@
"eslint": "^9.22.0",
"mocha": "^11.1.0",
"ts-node": "^10.9.2",
"run-script-os": "^1.1.6",
"@types/vscode": "^1.98.0",
"@vscode/test-electron": "^2.4.1",
"glob": "^11.0.1",
Expand Down
3 changes: 0 additions & 3 deletions scripts/e2e.bat

This file was deleted.

3 changes: 0 additions & 3 deletions scripts/e2e.sh

This file was deleted.

3 changes: 0 additions & 3 deletions scripts/tree.sitter.gdbmi.js

This file was deleted.

28 changes: 23 additions & 5 deletions src/debugger/gdb/gdbAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@
import { ChildProcess, spawn } from 'child_process';
import { EventEmitter } from 'events';
import { existsSync } from 'fs';
import * as vscode from 'vscode';

import * as CommandFactory from './commandFactory';
import { logger } from '../../util/logger';
import { GDBMIParser, GDBMIOutput,
GDBMIResult, GDBMIOutOfBandRecord, GDBMIAsyncOutput
GDBMIResult, GDBMIOutOfBandRecord, GDBMIAsyncOutput, GDBMIStreamRecordType
} from '../parser/gdbParser';

export enum GDBCommandFlag {
Expand Down Expand Up @@ -199,8 +200,7 @@ export class GDBAdapter extends EventEmitter {
this.processGDBMIOutOfBandRecord(miOutOfBandRecord);
}
} else {
this.programOutput += response;
// todo
this.writeToDebugConsole(response);
}

if (this.gdbmiCommandOutput) {
Expand All @@ -227,6 +227,13 @@ export class GDBAdapter extends EventEmitter {
});
}

private writeToDebugConsole(output: string) {
this.programOutput += output;
const debugConsole = vscode.debug.activeDebugConsole;
// Use the appendLine method
debugConsole.appendLine(output);
}

/**
* Processes GDB/MI out-of-band records.
*
Expand All @@ -249,8 +256,19 @@ export class GDBAdapter extends EventEmitter {
} else if (outOfBandRecord.miStreamRecord) {
// Handle stream records (e.g., console, target, or log output)
const streamOutput = outOfBandRecord.miStreamRecord?.value;
if (streamOutput) {
this.programOutput += streamOutput;
switch (outOfBandRecord.miStreamRecord?.type) {
case GDBMIStreamRecordType.consoleStream:
// todo. Add configuration to show/hide console output
break;
case GDBMIStreamRecordType.targetStream:
this.writeToDebugConsole(streamOutput);
break;
case GDBMIStreamRecordType.logStream:
// todo. Add configuration to show/hide log output
break;
default:
logger.error(`GDB: Unknown stream record type: ${outOfBandRecord.miStreamRecord?.type}`);
break;
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/debugger/parser/tree.sitter.gdbmi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const fs = require('fs');

fs.copyFileSync('../../../node_modules/tree-sitter-gdbmi/tree-sitter-gdbmi.wasm', 'tree-sitter-gdbmi.wasm');
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
*
*/

import { BreakpointHandler } from '../../../src/debugger/breakpoints/breakpoints';
import { BreakpointHandler } from '../../src/debugger/breakpoints/breakpoints';
import { DebugProtocol } from '@vscode/debugprotocol';
import assert from 'assert';

describe('Breakpoints', () => {
it('Add a new breakpoint', () => {
suite('Breakpoints', () => {
test('Add a new breakpoint', () => {
const handler = new BreakpointHandler();
const source: DebugProtocol.Source = { path: 'test/path' };
handler.addBreakpoint(1, source, 10);
Expand All @@ -49,7 +49,7 @@ describe('Breakpoints', () => {
assert.strictEqual(breakpoints[0].line, 10);
});

it('Retrieve breakpoints by source', () => {
test('Retrieve breakpoints by source', () => {
const handler = new BreakpointHandler();
const source1: DebugProtocol.Source = { path: 'test/path1' };
const source2: DebugProtocol.Source = { path: 'test/path2' };
Expand All @@ -68,7 +68,7 @@ describe('Breakpoints', () => {
assert.strictEqual(breakpoints2[0].line, 20);
});

it('Retrieve breakpoint IDs by file path', () => {
test('Retrieve breakpoint IDs by file path', () => {
const handler = new BreakpointHandler();
const source: DebugProtocol.Source = { path: 'test/path' };
handler.addBreakpoint(1, source, 10);
Expand All @@ -78,7 +78,7 @@ describe('Breakpoints', () => {
assert.deepStrictEqual(ids, [1, 2]);
});

it('Delete breakpoints by IDs', () => {
test('Delete breakpoints by IDs', () => {
const handler = new BreakpointHandler();
const source: DebugProtocol.Source = { path: 'test/path' };
handler.addBreakpoint(1, source, 10);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ import * as assert from 'assert';
import { exec } from 'child_process';
import * as process from 'process';

import { GDBAdapter } from '../../../src/debugger/gdb/gdbAdapter';
import * as CommandFactory from '../../../src/debugger/gdb/commandFactory';
import { setLogLevel } from '../../../src/util/logger';
import { GDBAdapter } from '../../src/debugger/gdb/gdbAdapter';
import * as CommandFactory from '../../src/debugger/gdb/commandFactory';
import { setLogLevel } from '../../src/util/logger';

async function which(programName: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
Expand Down Expand Up @@ -75,8 +75,8 @@ async function getOMCAndGDB(): Promise<[string, string]> {
return [omcExecutable, gdbExecutable];
}

describe('GDBAdapter', () => {
it('Start and stop GDBAdapter with omc', async () => {
suite('GDBAdapter', () => {
test('Start and stop GDBAdapter with omc', async () => {
setLogLevel('warning');

const adapter = new GDBAdapter();
Expand All @@ -87,7 +87,7 @@ describe('GDBAdapter', () => {
assert.equal(adapter.isGDBRunning(), false, "Assert GDB is not running any more.");
}).timeout("10s");

it('Run GDBAdapter with omc --version', async () => {
test('Run GDBAdapter with omc --version', async () => {
setLogLevel('warning');
const adapter = new GDBAdapter();
const [omcExecutable, gdbExecutable] = await getOMCAndGDB();
Expand All @@ -105,7 +105,7 @@ describe('GDBAdapter', () => {
assert.equal(adapter.isGDBRunning(), false, "Assert GDB is not running any more.");
}).timeout("10s");

it('Run GDBAdapter with omc and setupGDB', async () => {
test('Run GDBAdapter with omc and setupGDB', async () => {
setLogLevel('warning');
const adapter = new GDBAdapter();
const [omcExecutable, gdbExecutable] = await getOMCAndGDB();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@
*/

import * as assert from 'assert';
import { GDBMIParser } from '../../../src/debugger/parser/gdbParser';
import { setLogLevel } from '../../../src/util/logger';
import { GDBMIParser } from '../../src/debugger/parser/gdbParser';
import { setLogLevel } from '../../src/util/logger';

describe('GDB/MI Parser', () => {
it('Initialize parser', async () => {
suite('GDB/MI Parser', () => {
test('Initialize parser', async () => {
const gdbMiParser = new GDBMIParser();
await gdbMiParser.initialize();
});

it('Parse -break-insert output', async () => {
test('Parse -break-insert output', async () => {
setLogLevel("warning");
const gdbMiParser = new GDBMIParser();
await gdbMiParser.initialize();
Expand Down Expand Up @@ -80,15 +80,15 @@ describe('GDB/MI Parser', () => {
assert.deepEqual(gdbmiOutput, breakpointOutput);
}).timeout("2s");

it('Parse -exec-run output', async () => {
test('Parse -exec-run output', async () => {
const gdbMiParser = new GDBMIParser();
await gdbMiParser.initialize();
const gdbmiOutput = gdbMiParser.parse('10^running\n');
assert.equal(gdbmiOutput.miResultRecord?.token, 10, `Expected token 10 got ${gdbmiOutput.miResultRecord?.token}`);
assert.equal(gdbmiOutput.miResultRecord?.cls, "running", `Expected result class "running" got ${gdbmiOutput.miResultRecord?.cls}`);
}).timeout("2s");

it('Parse stop event output', async () => {
test('Parse stop event output', async () => {
const gdbMiParser = new GDBMIParser();
await gdbMiParser.initialize();
const gdbmiOutput = gdbMiParser.parse('*stopped,reason="exited-normally"\n');
Expand Down
15 changes: 14 additions & 1 deletion test/client/index.ts → test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import * as path from 'path';
import Mocha from 'mocha';
import {glob} from 'glob';
import * as fs from 'fs';

export function run(): Promise<void> {
// Create the mocha test
Expand All @@ -48,7 +49,19 @@ export function run(): Promise<void> {
const testsRoot = __dirname;

return new Promise((resolve, reject) => {
glob('**.test.js', { cwd: testsRoot }).then(files => {
// this code is running from dist/test folder so set the paths accordingly
// copy tree-sitter-metamodelica.wasm
let sourcePath = path.resolve(__dirname, '../../src/server/tree-sitter-metamodelica.wasm');
let destinationPath = path.resolve(__dirname, '../src/server/tree-sitter-metamodelica.wasm');
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
fs.copyFileSync(sourcePath, destinationPath);
// copy tree-sitter-gdbmi.wasm
sourcePath = path.resolve(__dirname, '../../src/debugger/parser/tree-sitter-gdbmi.wasm');
destinationPath = path.resolve(__dirname, '../src/debugger/parser/tree-sitter-gdbmi.wasm');
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
fs.copyFileSync(sourcePath, destinationPath);
// add all test files to the mocha test suite
glob('**/**.test.js', { cwd: testsRoot }).then(files => {
// Add files to the test suite
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));

Expand Down
4 changes: 1 addition & 3 deletions test/client/runTest.ts → test/runTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,11 @@ async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../../');
console.log(extensionDevelopmentPath);
const extensionDevelopmentPath = path.resolve(__dirname, '../../');

// The path to test runner
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './index');
console.log(extensionTestsPath);

// Download VS Code, unzip it and run the integration test
await runTests({ extensionDevelopmentPath, extensionTestsPath });
Expand Down
8 changes: 4 additions & 4 deletions test/server/declarations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ const expectedSymbols = [
)
];

describe('nodeToDocumentSymbol', () => {
it('type to TypeParameter', async () => {
suite('nodeToDocumentSymbol', () => {
test('type to TypeParameter', async () => {
const parser = await initializeMetaModelicaParser();
const tree = parser.parse("type Temperature = Real(unit = \"K \");");
const queries = new MetaModelicaQueries(parser.getLanguage());
Expand All @@ -111,8 +111,8 @@ describe('nodeToDocumentSymbol', () => {
});
});

describe('getAllDeclarationsInTree', () => {
it('Definitions and types', async () => {
suite('getAllDeclarationsInTree', () => {
test('Definitions and types', async () => {
const parser = await initializeMetaModelicaParser();
const tree = parser.parse(metaModelicaTestString);
const queries = new MetaModelicaQueries(parser.getLanguage());
Expand Down
4 changes: 2 additions & 2 deletions test/server/diagnostics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ const expectedDiagnostics: LSP.Diagnostic[] = [
}
];

describe('getAllDeclarationsInTree', () => {
it('Definitions and types', async () => {
suite('getAllDeclarationsInTree', () => {
test('Definitions and types', async () => {
const parser = await initializeMetaModelicaParser();
const tree = parser.parse(metaModelicaTestString);
const queries = new MetaModelicaQueries(parser.getLanguage());
Expand Down
8 changes: 4 additions & 4 deletions test/server/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,19 @@ end M;
`;
const parsedMetaModelicaTestString = "(stored_definition classDefinition: (class_definition classType: (class_type model: (MODEL)) classSpecifier: (class_specifier identifier: (identifier (IDENT)) comment: (string_comment (STRING)) composition: (composition element: (element componentClause: (component_clause typeSpecifier: (type_specifier (T_REAL)) componentDeclaration: (component_declaration declaration: (declaration identifier: (IDENT) modification: (modification classModification: (class_modification (LPAR) argument: (argument (element_modification_or_replaceable (element_modification componentReference: (component_reference (IDENT)) modification: (modification (EQUALS) expression: (expression (simple_expression (UNSIGNED_INTEGER))))))) (COMMA) argument: (argument (element_modification_or_replaceable (element_modification componentReference: (component_reference (IDENT)) modification: (modification (EQUALS) expression: (expression (simple_expression (T_TRUE))))))) (RPAR)))) comment: (comment (string_comment (STRING)))))) element: (element componentClause: (component_clause typeSpecifier: (type_specifier namePath: (name_path identifier: (IDENT))) componentDeclaration: (component_declaration declaration: (declaration identifier: (IDENT) modification: (modification classModification: (class_modification (LPAR) argument: (argument (element_modification_or_replaceable (element_modification componentReference: (component_reference (IDENT))))) (RPAR)) (EQUALS) expression: (expression (simple_expression (MINUS) (UNSIGNED_REAL) (STAR) (component_reference__function_call componentReference: (component_reference (IDENT))))))))))) (T_END) endIdentifier: (identifier (IDENT)))))";

describe('MetaModelica tree-sitter parser', () => {
it('Initialize parser', async () => {
suite('MetaModelica tree-sitter parser', () => {
test('Initialize parser', async () => {
await initializeMetaModelicaParser();
});

it('Parse string', async () => {
test('Parse string', async () => {
const parser = await initializeMetaModelicaParser();
const tree = parser.parse(metaModelicaTestString);
const parsedString = tree.rootNode.toString();
assert.equal(parsedString, parsedMetaModelicaTestString);
});

it('Identifier of type class', async () => {
test('Identifier of type class', async () => {
const parser = await initializeMetaModelicaParser();
const tree = parser.parse("type Temperature = Real(unit = \"K \");");
const classNode = tree.rootNode.childForFieldName("classDefinitionList")!;
Expand Down
Loading