Skip to content

Commit

Permalink
first cut of 'runInTerminal' for external terminals
Browse files Browse the repository at this point in the history
  • Loading branch information
weinand committed Sep 7, 2016
1 parent 1a227a7 commit e190921
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 79 deletions.
2 changes: 1 addition & 1 deletion extensions/node-debug/node-debug.azure.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"account": "monacobuild",
"container": "debuggers",
"zip": "5333dfa/node-debug.zip",
"zip": "864e0bd/node-debug.zip",
"output": ""
}
86 changes: 12 additions & 74 deletions src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ import stdfork = require('vs/base/node/stdFork');
import {IMessageService, CloseAction} from 'vs/platform/message/common/message';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {ITerminalService} from 'vs/workbench/parts/terminal/electron-browser/terminal';
import {ITerminalService as IExternalTerminalService} from 'vs/workbench/parts/execution/common/execution';
import debug = require('vs/workbench/parts/debug/common/debug');
import {Adapter} from 'vs/workbench/parts/debug/node/debugAdapter';
import v8 = require('vs/workbench/parts/debug/node/v8Protocol');
import {IOutputService} from 'vs/workbench/parts/output/common/output';
import {ExtensionsChannelId} from 'vs/platform/extensionManagement/common/extensionManagement';
import {TerminalSupport} from 'vs/workbench/parts/debug/electron-browser/terminalSupport';


import {shell} from 'electron';

Expand Down Expand Up @@ -53,7 +56,6 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
private stopServerPending: boolean;
private sentPromises: TPromise<DebugProtocol.Response>[];
private capabilities: DebugProtocol.Capabilities;
private static terminalId: number;

private _onDidInitialize: Emitter<DebugProtocol.InitializedEvent>;
private _onDidStop: Emitter<DebugProtocol.StoppedEvent>;
Expand All @@ -72,7 +74,8 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
@IMessageService private messageService: IMessageService,
@ITelemetryService private telemetryService: ITelemetryService,
@IOutputService private outputService: IOutputService,
@ITerminalService private terminalService: ITerminalService
@ITerminalService private terminalService: ITerminalService,
@IExternalTerminalService private nativeTerminalService: IExternalTerminalService
) {
super();
this.emittedStopped = false;
Expand Down Expand Up @@ -341,87 +344,22 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
return (new Date().getTime() - this.startTime) / 1000;
}

protected dispatchRequest(request: DebugProtocol.Request): void {
const response: DebugProtocol.Response = {
type: 'response',
seq: 0,
command: request.command,
request_seq: request.seq,
success: true
};
protected dispatchRequest(request: DebugProtocol.Request, response: DebugProtocol.Response): void {

if (request.command === 'runInTerminal') {
this.runInTerminal(<DebugProtocol.RunInTerminalRequestArguments>request.arguments).then(() => {
(<DebugProtocol.RunInTerminalResponse>response).body = {
// nothing to return for now..
};

TerminalSupport.runInTerminal(this.terminalService, this.nativeTerminalService, <DebugProtocol.RunInTerminalRequestArguments>request.arguments, <DebugProtocol.RunInTerminalResponse>response).then(() => {
this.sendResponse(response);
}, e => {
response.success = false;
response.message = 'error while handling request';
response.message = e.message;
this.sendResponse(response);
});
}
}

protected runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): TPromise<void> {
return (!RawDebugSession.terminalId ? this.terminalService.createNew(args.title || nls.localize('debuggee', "debuggee")) : TPromise.as(RawDebugSession.terminalId)).then(id => {
RawDebugSession.terminalId = id;
return this.terminalService.show(false).then(terminalPanel => {
this.terminalService.setActiveTerminalById(id);
const command = this.prepareCommand(args);
terminalPanel.sendTextToActiveTerminal(command, true);
});
});
}

private prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments): string {
let command = '';

if (platform.isWindows) {

const quote = (s: string) => {
s = s.replace(/\"/g, '""');
return (s.indexOf(' ') >= 0 || s.indexOf('"') >= 0) ? `"${s}"` : s;
};

if (args.cwd) {
command += `cd ${quote(args.cwd)} && `;
}
if (args.env) {
command += 'cmd /C "';
for (let key in args.env) {
command += `set "${key}=${args.env[key]}" && `;
}
}
for (let a of args.args) {
command += `${quote(a)} `;
}
if (args.env) {
command += '"';
}
} else {
const quote = (s: string) => {
s = s.replace(/\"/g, '\\"');
return s.indexOf(' ') >= 0 ? `"${s}"` : s;
};

if (args.cwd) {
command += `cd ${quote(args.cwd)} ; `;
}
if (args.env) {
command += 'env';
for (let key in args.env) {
command += ` ${quote(key + '=' + args.env[key])}`;
}
command += ' ';
}
for (let a of args.args) {
command += `${quote(a)} `;
}
response.success = false;
response.message = `unknown request '${request.command}'`;
this.sendResponse(response);
}

return command;
}

private connectServer(port: number): TPromise<void> {
Expand Down
85 changes: 85 additions & 0 deletions src/vs/workbench/parts/debug/electron-browser/terminalSupport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import nls = require('vs/nls');
import platform = require('vs/base/common/platform');
import {TPromise} from 'vs/base/common/winjs.base';
import {ITerminalService} from 'vs/workbench/parts/terminal/electron-browser/terminal';
import {ITerminalService as IExternalTerminalService} from 'vs/workbench/parts/execution/common/execution';


export class TerminalSupport {

private static terminalId: number;

public static runInTerminal(terminalService: ITerminalService, nativeTerminalService: IExternalTerminalService, args: DebugProtocol.RunInTerminalRequestArguments, response: DebugProtocol.RunInTerminalResponse): TPromise<void> {

if (args.kind === 'external') {
return nativeTerminalService.runInTerminal(args.title, args.cwd, args.args, args.env);
}
return this.runInIntegratedTerminal(terminalService, args);
}

private static runInIntegratedTerminal(terminalService: ITerminalService, args: DebugProtocol.RunInTerminalRequestArguments): TPromise<void> {

return (!TerminalSupport.terminalId ? terminalService.createNew(args.title || nls.localize('debuggee', "debuggee")) : TPromise.as(TerminalSupport.terminalId)).then(id => {
TerminalSupport.terminalId = id;
return terminalService.show(false).then(terminalPanel => {
terminalService.setActiveTerminalById(id);
const command = this.prepareCommand(args);
terminalPanel.sendTextToActiveTerminal(command, true);
});
});
}

private static prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments): string {
let command = '';

if (platform.isWindows) {

const quote = (s: string) => {
s = s.replace(/\"/g, '""');
return (s.indexOf(' ') >= 0 || s.indexOf('"') >= 0) ? `"${s}"` : s;
};

if (args.cwd) {
command += `cd ${quote(args.cwd)} && `;
}
if (args.env) {
command += 'cmd /C "';
for (let key in args.env) {
command += `set "${key}=${args.env[key]}" && `;
}
}
for (let a of args.args) {
command += `${quote(a)} `;
}
if (args.env) {
command += '"';
}
} else {
const quote = (s: string) => {
s = s.replace(/\"/g, '\\"');
return s.indexOf(' ') >= 0 ? `"${s}"` : s;
};

if (args.cwd) {
command += `cd ${quote(args.cwd)} ; `;
}
if (args.env) {
command += 'env';
for (let key in args.env) {
command += ` ${quote(key + '=' + args.env[key])}`;
}
command += ' ';
}
for (let a of args.args) {
command += `${quote(a)} `;
}
}

return command;
}
}
12 changes: 10 additions & 2 deletions src/vs/workbench/parts/debug/node/v8Protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export abstract class V8Protocol {

protected abstract onServerError(err: Error): void;
protected abstract onEvent(event: DebugProtocol.Event): void;
protected abstract dispatchRequest(request: DebugProtocol.Request);
protected abstract dispatchRequest(request: DebugProtocol.Request, response: DebugProtocol.Response);

protected connect(readable: stream.Readable, writable: stream.Writable): void {

Expand Down Expand Up @@ -140,7 +140,15 @@ export abstract class V8Protocol {
}
break;
case 'request':
this.dispatchRequest(<DebugProtocol.Request>rawData);
const request = <DebugProtocol.Request>rawData;
const resp: DebugProtocol.Response = {
type: 'response',
seq: 0,
command: request.command,
request_seq: request.seq,
success: true
};
this.dispatchRequest(request, resp);
break;
}
} catch (e) {
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/parts/execution/common/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
'use strict';

import {createDecorator} from 'vs/platform/instantiation/common/instantiation';
import {TPromise} from 'vs/base/common/winjs.base';

export const ITerminalService = createDecorator<ITerminalService>('nativeTerminalService');

export interface ITerminalService {
_serviceBrand: any;
openTerminal(path: string): void;
runInTerminal(title: string, cwd: string, args: string[], env: { [key: string]: string; }): TPromise<void>;
}
Binary file not shown.
Loading

0 comments on commit e190921

Please sign in to comment.