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

GT.M Debug #106

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
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
1 change: 1 addition & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ vsc-extension-quickstart.md
python_scripts/**
images/**
package-lock.json
gtm-debug
73 changes: 73 additions & 0 deletions gtm-debug/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Direct Mode",
"program": "${workspaceFolder}/src/directMode.ts",
"outFiles": ["${workspaceFolder}/out/**/*.js"]
},
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "npm: watch"
},
{
"name": "Server",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/src/debugAdapter.ts",
"args": [
"--server=4711"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
]
},
{
"name": "Tests",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"-u",
"tdd",
"--timeout",
"999999",
"--colors",
"./out/tests/"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "Mock Sample",
"type": "mock",
"request": "launch",
"program": "${workspaceFolder}/${command:AskForProgramName}",
"stopOnEntry": true
}
],
"compounds": [
{
"name": "Extension + Server",
"configurations": [
"Extension",
"Server"
]
}
]
}
8 changes: 8 additions & 0 deletions gtm-debug/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Place your settings in this file to overwrite default and user settings.FALSE
{
"javascript.validate.enable": false,
"typescript.tsdk": "node_modules/typescript/lib",
"files.trimTrailingWhitespace": true,
"editor.insertSpaces": false,
"editor.formatOnSave": true
}
18 changes: 18 additions & 0 deletions gtm-debug/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
7 changes: 7 additions & 0 deletions gtm-debug/.vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.vscode/**/*
.gitignore
.travis.yml
appveyor.yml
src/**/*
out/tests/**/*
**/*.js.map
23 changes: 23 additions & 0 deletions gtm-debug/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## v0.0.5

Kill Direct Mode process on debug disconnect

## v0.0.4

Tree variable expansion

## v0.0.3

Set source and function breakpoints from the UI. Corresponding routines will be available in "Loaded Scripts".

Watch expressions that are evaluated on every step.

## v0.0.2

Cursor follows the stack.

Set breakpoints by clicking in the file (removing breakpoints must still be done manually)

## v0.0.1

Initial version. Basic stack, variable, and terminal capabilities. Can also display source code of the stack.
28 changes: 28 additions & 0 deletions gtm-debug/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# GT.M Debugger

A work in progress project.

Debugs by spawning a direct mode process and communicates through standard IO.

If you use Docker your `launch.json` might look like this:

```json
{
"configurations": [
{
"type": "gtm",
"request": "launch",
"name": "GT.M Docker",
"command": "docker",
"args": [
"exec",
"-i",
"profiledevelop",
"ksh",
"-c",
"'/v7dev/dm'"
]
}
]
}
```
121 changes: 121 additions & 0 deletions gtm-debug/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{
"name": "gtm-debug",
"displayName": "GT.M Debug",
"version": "0.0.5",
"publisher": "ing-bank",
"description": "Debugger for GT.M database",
"author": {
"name": "Alexander Tiplea",
"email": "[email protected]"
},
"license": "MIT",
"keywords": [
"multi-root ready"
],
"engines": {
"vscode": "^1.40.0",
"node": "^12.04.0"
},
"categories": [
"Debuggers"
],
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/ing-bank/vscode-psl/tree/gtm-debug/gtm-debug"
},
"scripts": {
"prepublish": "tsc -p ./src",
"compile": "tsc -p ./src",
"tslint": "tslint ./src/**/*.ts",
"watch": "tsc -w -p ./src",
"test": "mocha -u tdd ./out/tests/",
"postinstall": "node ./node_modules/vscode/bin/install",
"package": "vsce package",
"publish": "vsce publish"
},
"dependencies": {
"await-notify": "1.0.1",
"rxjs": "^6.5.3",
"vscode-debugadapter": "1.37.0"
},
"devDependencies": {
"@types/node": "^12",
"typescript": "^3.7.0",
"vscode": "1.1.36",
"tslint": "5.18.0",
"vsce": "1.66.0"
},
"main": "./out/extension",
"activationEvents": [
"onDebug"
],
"contributes": {
"breakpoints": [
{
"language": "mumps"
}
],
"debuggers": [
{
"type": "gtm",
"label": "GT.M Debug",
"program": "./out/debugAdapter.js",
"runtime": "node",
"configurationAttributes": {
"launch": {
"required": [
"command"
],
"properties": {
"command": {
"type": "string",
"description": "An executable that can supply Direct Mode."
},
"args": {
"type": "array",
"description": "An executable that can supply Direct Mode."
}
}
}
},
"initialConfigurations": [
{
"type": "gtm",
"request": "launch",
"name": "GT.M Docker",
"command": "docker",
"args": [
"exec",
"-i",
"gtm-container",
"ksh",
"-c",
"'/dm'"
]
}
],
"configurationSnippets": [
{
"label": "GT.M Debug: Launch Docker",
"description": "A new configuration for debugging with docker",
"body": {
"type": "gtm",
"request": "launch",
"name": "GT.M Docker",
"command": "docker",
"args": [
"exec",
"-i",
"gtm-container",
"ksh",
"-c",
"'/dm'"
]
}
}
]
}
]
}
}
7 changes: 7 additions & 0 deletions gtm-debug/src/debugAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/

import { GtmDebugSession } from './session';

GtmDebugSession.run(GtmDebugSession);
88 changes: 88 additions & 0 deletions gtm-debug/src/directMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { spawn, ChildProcessWithoutNullStreams } from 'child_process';
import { fromEvent, Observable, Subject } from 'rxjs';
import { map, filter, first } from 'rxjs/operators';


export class DirectMode {
dmProcess: ChildProcessWithoutNullStreams;
stdout: Observable<string>;
stderr: Observable<string>;

private outputBuffer: string = '';
private count: number = 0;
private responsesSubject: Subject<string> = new Subject();

static zPrompt: string = 'vscode-debug m>';

constructor(command: string, args: string[]) {

this.dmProcess = spawn(command, args);

this.stdout = fromEvent<Buffer>(this.dmProcess.stdout, 'data').pipe(map(x => x.toString()));
this.stderr = fromEvent<Buffer>(this.dmProcess.stderr, 'data').pipe(map(x => x.toString()));

this.setPrompt();
this.listen();
}

execute(msg: string): Observable<string> {
const header = `${this.count}_${msg}`;
this.dmProcess.stdin.write(`WRITE "${DirectMode.escapeMumps(header)}",! ${msg}\n`);
this.count++;
return this.responsesSubject.pipe(
filter(response => response.startsWith(header)),
map(response => {
if (header === response) { return ''; }
else { return response.replace(header + '\n', ''); }
}),
first(),
);
}

setPrompt(): Observable<string> {
return this.execute(`SET $ZPROMPT="${DirectMode.zPrompt}"`);
}

zPrint(location?: string): Observable<string> {
return this.execute(`ZPRINT ${location || ''}`);
}

zWrite(pattern?: string): Observable<string> {
return this.execute(`ZWRITE ${pattern || ''}`);
}

zShow(): Observable<string> {
return this.execute(`ZSHOW`);
}

zStep(step: 'INTO' | 'OUTOF' | 'OVER'): Observable<string> {
return this.execute(`ZSTEP ${step}`);
}

zContinue(): Observable<string> {
return this.execute(`ZCONTINUE`);
}

getBreakPoints(): Observable<string> {
return this.execute(`ZSHOW "B"`);
}

setBreakPoint(location: string): Observable<string> {
return this.execute(`ZBREAK ${location}`);
}

listen(): void {
this.stdout.subscribe(out => {
this.outputBuffer += out;
const pieces = this.outputBuffer.split(new RegExp(`^${DirectMode.zPrompt}\n?$`, 'gm'));
for (const response of pieces.slice(0, -1)) {
this.responsesSubject.next(response.trimLeft());
}
this.outputBuffer = pieces[pieces.length - 1] || '';
});
}

static escapeMumps(msg: string) {
return msg.replace(/"/g, '""');
}
}
Loading