mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Integrate native module for WindowsShellHelper
This commit is contained in:
parent
cd6d1ffc42
commit
ead952302a
5
npm-shrinkwrap.json
generated
5
npm-shrinkwrap.json
generated
|
@ -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",
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
"vscode-debugprotocol": "1.22.0",
|
||||
"vscode-ripgrep": "0.0.25",
|
||||
"vscode-textmate": "^3.1.5",
|
||||
"windows-process-tree": "0.1.1",
|
||||
"winreg": "1.2.0",
|
||||
"xterm": "Tyriar/xterm.js#vscode-release/1.15",
|
||||
"yauzl": "2.8.0"
|
||||
|
|
9
src/typings/windows-process-tree.d.ts
vendored
Normal file
9
src/typings/windows-process-tree.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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;
|
||||
}
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
// 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);
|
||||
if (child.children[0].name !== 'conhost.exe') {
|
||||
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 (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));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue