提交 ead95230 编写于 作者: A Amy Qiu

Integrate native module for WindowsShellHelper

上级 cd6d1ffc
...@@ -561,6 +561,11 @@ ...@@ -561,6 +561,11 @@
"from": "vscode-textmate@3.1.5", "from": "vscode-textmate@3.1.5",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-3.1.5.tgz" "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-3.1.5.tgz"
}, },
"windows-process-tree": {
"version": "0.1.1",
"from": "windows-process-tree@0.1.1",
"resolved": "https://registry.npmjs.org/windows-process-tree/-/windows-process-tree-0.1.1.tgz"
},
"winreg": { "winreg": {
"version": "1.2.0", "version": "1.2.0",
"from": "winreg@1.2.0", "from": "winreg@1.2.0",
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'windows-process-tree' {
function get(rootPid: number, callback: Function): void;
export = get;
}
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import * as cp from 'child_process'; import * as cp from 'child_process';
import * as platform from 'vs/base/common/platform'; import * as platform from 'vs/base/common/platform';
import * as path from 'path'; import windowsProcessTree = require('windows-process-tree');
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import { Emitter, debounceEvent } from 'vs/base/common/event'; import { Emitter, debounceEvent } from 'vs/base/common/event';
import { ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal'; import { ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal';
...@@ -34,8 +34,10 @@ export class WindowsShellHelper { ...@@ -34,8 +34,10 @@ export class WindowsShellHelper {
this._onCheckShell = new Emitter<TPromise<string>>(); this._onCheckShell = new Emitter<TPromise<string>>();
// The debounce is necessary to prevent multiple processes from spawning when // The debounce is necessary to prevent multiple processes from spawning when
// the enter key or output is spammed // the enter key or output is spammed
debounceEvent(this._onCheckShell.event, (l, e) => e, 200, true)(() => { debounceEvent(this._onCheckShell.event, (l, e) => e, 150, true)(() => {
setTimeout(() => {
this.checkShell(); this.checkShell();
}, 50);
}); });
this._xterm.on('lineFeed', () => this._onCheckShell.fire()); this._xterm.on('lineFeed', () => this._onCheckShell.fire());
...@@ -52,58 +54,27 @@ export class WindowsShellHelper { ...@@ -52,58 +54,27 @@ export class WindowsShellHelper {
} }
} }
private getChildProcessDetails(pid: number): TPromise<{ executable: string, pid: number }[]> { private traverseTree(tree: any): string {
return new TPromise((resolve, reject) => { if (SHELL_EXECUTABLES.indexOf(tree.name) === -1) {
this._wmicProcess = cp.execFile('wmic.exe', ['process', 'where', `parentProcessId=${pid}`, 'get', 'ExecutablePath,ProcessId'], (err, stdout, stderr) => { return tree.name;
this._wmicProcess = null;
if (this._isDisposed) {
reject(null);
} }
if (err) { if (!tree.children || tree.children.length === 0) {
reject(err); return tree.name;
} else if (stderr.length > 0) {
resolve([]); // No processes found
} else {
const childProcessLines = stdout.split('\n').slice(1).filter(str => !/^\s*$/.test(str));
const childProcessDetails = childProcessLines.map(str => {
const s = str.split(' ');
return { executable: s[0], pid: Number(s[1]) };
});
resolve(childProcessDetails);
}
});
});
}
private refreshShellProcessTree(pid: number, parent: string): TPromise<string> {
return this.getChildProcessDetails(pid).then(result => {
// When we didn't find any child processes of the process
if (result.length === 0) {
// Case where we found a child process already and are checking further down the pid tree
// We have reached the end here so we know that parent is the deepest first child of the tree
if (parent) {
return TPromise.as(parent);
} }
// Case where we haven't found a child and only the root shell is left let favouriteChild = 0;
if (this._childProcessIdStack.length === 1) { for (; favouriteChild < tree.children.length; favouriteChild++) {
return TPromise.as(this._rootShellExecutable); const child = tree.children[favouriteChild];
if (!child.children || child.children.length === 0) {
break;
} }
// Otherwise, we go up the tree to find the next valid deepest child of the root if (child.children[0].name !== 'conhost.exe') {
this._childProcessIdStack.pop(); break;
return this.refreshShellProcessTree(this._childProcessIdStack[this._childProcessIdStack.length - 1], null);
} }
// We only go one level deep when checking for children of processes other then shells
if (SHELL_EXECUTABLES.indexOf(path.basename(result[0].executable)) === -1) {
return TPromise.as(result[0].executable);
} }
// Save the pid in the stack and keep looking for children of that child if (favouriteChild >= tree.children.length) {
this._childProcessIdStack.push(result[0].pid); return tree.name;
return this.refreshShellProcessTree(result[0].pid, result[0].executable);
}, error => {
if (!this._isDisposed) {
return error;
} }
}); return this.traverseTree(tree.children[favouriteChild]);
} }
public dispose(): void { public dispose(): void {
...@@ -117,6 +88,10 @@ export class WindowsShellHelper { ...@@ -117,6 +88,10 @@ export class WindowsShellHelper {
* Returns the innermost shell executable running in the terminal * Returns the innermost shell executable running in the terminal
*/ */
public getShellName(): TPromise<string> { public getShellName(): TPromise<string> {
return this.refreshShellProcessTree(this._childProcessIdStack[this._childProcessIdStack.length - 1], null); return new TPromise<string>(resolve => {
windowsProcessTree(this._rootProcessId, (tree) => {
resolve(this.traverseTree(tree));
});
});
} }
} }
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册