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

Integrate native module for WindowsShellHelper

上级 cd6d1ffc
......@@ -561,6 +561,11 @@
"from": "vscode-textmate@3.1.5",
"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": {
"version": "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 @@
import * as cp from 'child_process';
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 { Emitter, debounceEvent } from 'vs/base/common/event';
import { ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal';
......@@ -34,8 +34,10 @@ export class WindowsShellHelper {
this._onCheckShell = new Emitter<TPromise<string>>();
// The debounce is necessary to prevent multiple processes from spawning when
// the enter key or output is spammed
debounceEvent(this._onCheckShell.event, (l, e) => e, 200, true)(() => {
this.checkShell();
debounceEvent(this._onCheckShell.event, (l, e) => e, 150, true)(() => {
setTimeout(() => {
this.checkShell();
}, 50);
});
this._xterm.on('lineFeed', () => this._onCheckShell.fire());
......@@ -52,58 +54,27 @@ export class WindowsShellHelper {
}
}
private getChildProcessDetails(pid: number): TPromise<{ executable: string, pid: number }[]> {
return new TPromise((resolve, reject) => {
this._wmicProcess = cp.execFile('wmic.exe', ['process', 'where', `parentProcessId=${pid}`, 'get', 'ExecutablePath,ProcessId'], (err, stdout, stderr) => {
this._wmicProcess = null;
if (this._isDisposed) {
reject(null);
}
if (err) {
reject(err);
} 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
if (this._childProcessIdStack.length === 1) {
return TPromise.as(this._rootShellExecutable);
}
// Otherwise, we go up the tree to find the next valid deepest child of the root
this._childProcessIdStack.pop();
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);
private traverseTree(tree: any): string {
if (SHELL_EXECUTABLES.indexOf(tree.name) === -1) {
return tree.name;
}
if (!tree.children || tree.children.length === 0) {
return tree.name;
}
let favouriteChild = 0;
for (; favouriteChild < tree.children.length; favouriteChild++) {
const child = tree.children[favouriteChild];
if (!child.children || child.children.length === 0) {
break;
}
// Save the pid in the stack and keep looking for children of that child
this._childProcessIdStack.push(result[0].pid);
return this.refreshShellProcessTree(result[0].pid, result[0].executable);
}, error => {
if (!this._isDisposed) {
return error;
if (child.children[0].name !== 'conhost.exe') {
break;
}
});
}
if (favouriteChild >= tree.children.length) {
return tree.name;
}
return this.traverseTree(tree.children[favouriteChild]);
}
public dispose(): void {
......@@ -117,6 +88,10 @@ export class WindowsShellHelper {
* Returns the innermost shell executable running in the terminal
*/
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.
先完成此消息的编辑!
想要评论请 注册