Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
4986a041
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
4986a041
编写于
7月 12, 2018
作者:
D
Daniel Imms
提交者:
GitHub
7月 12, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #54090 from Microsoft/tyriar/terminalProcess
Move terminalProcess into the renderer process
上级
8dbf4c5d
6dd7bdee
变更
11
显示空白变更内容
内联
并排
Showing
11 changed file
with
294 addition
and
370 deletion
+294
-370
build/gulpfile.vscode.js
build/gulpfile.vscode.js
+0
-1
src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts
...rkbench/api/electron-browser/mainThreadTerminalService.ts
+1
-1
src/vs/workbench/api/node/extHostTerminalService.ts
src/vs/workbench/api/node/extHostTerminalService.ts
+22
-38
src/vs/workbench/buildfile.js
src/vs/workbench/buildfile.js
+0
-2
src/vs/workbench/parts/terminal/common/terminal.ts
src/vs/workbench/parts/terminal/common/terminal.ts
+3
-3
src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts
...parts/terminal/electron-browser/terminalProcessManager.ts
+56
-68
src/vs/workbench/parts/terminal/node/terminal.ts
src/vs/workbench/parts/terminal/node/terminal.ts
+8
-17
src/vs/workbench/parts/terminal/node/terminalEnvironment.ts
src/vs/workbench/parts/terminal/node/terminalEnvironment.ts
+34
-25
src/vs/workbench/parts/terminal/node/terminalProcess.ts
src/vs/workbench/parts/terminal/node/terminalProcess.ts
+102
-144
src/vs/workbench/parts/terminal/node/terminalProcessExtHostProxy.ts
...kbench/parts/terminal/node/terminalProcessExtHostProxy.ts
+30
-35
src/vs/workbench/parts/terminal/test/node/terminalEnvironment.test.ts
...ench/parts/terminal/test/node/terminalEnvironment.test.ts
+38
-36
未找到文件。
build/gulpfile.vscode.js
浏览文件 @
4986a041
...
...
@@ -78,7 +78,6 @@ const vscodeResources = [
'
out-build/vs/workbench/parts/webview/electron-browser/webview-pre.js
'
,
'
out-build/vs/**/markdown.css
'
,
'
out-build/vs/workbench/parts/tasks/**/*.json
'
,
'
out-build/vs/workbench/parts/terminal/electron-browser/terminalProcess.js
'
,
'
out-build/vs/workbench/parts/welcome/walkThrough/**/*.md
'
,
'
out-build/vs/workbench/services/files/**/*.exe
'
,
'
out-build/vs/workbench/services/files/**/*.md
'
,
...
...
src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts
浏览文件 @
4986a041
...
...
@@ -178,7 +178,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
};
this
.
_proxy
.
$createProcess
(
request
.
proxy
.
terminalId
,
shellLaunchConfigDto
,
request
.
cols
,
request
.
rows
);
request
.
proxy
.
onInput
(
data
=>
this
.
_proxy
.
$acceptProcessInput
(
request
.
proxy
.
terminalId
,
data
));
request
.
proxy
.
onResize
(
(
cols
,
rows
)
=>
this
.
_proxy
.
$acceptProcessResize
(
request
.
proxy
.
terminalId
,
cols
,
rows
));
request
.
proxy
.
onResize
(
dimensions
=>
this
.
_proxy
.
$acceptProcessResize
(
request
.
proxy
.
terminalId
,
dimensions
.
cols
,
dimensions
.
rows
));
request
.
proxy
.
onShutdown
(()
=>
this
.
_proxy
.
$acceptProcessShutdown
(
request
.
proxy
.
terminalId
));
}
...
...
src/vs/workbench/api/node/extHostTerminalService.ts
浏览文件 @
4986a041
...
...
@@ -5,17 +5,15 @@
'
use strict
'
;
import
*
as
vscode
from
'
vscode
'
;
import
*
as
cp
from
'
child_process
'
;
import
*
as
os
from
'
os
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
*
as
terminalEnvironment
from
'
vs/workbench/parts/terminal/node/terminalEnvironment
'
;
import
Uri
from
'
vs/base/common/uri
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
ExtHostTerminalServiceShape
,
MainContext
,
MainThreadTerminalServiceShape
,
IMainContext
,
ShellLaunchConfigDto
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
IMessageFromTerminalProcess
}
from
'
vs/workbench/parts/terminal/node/terminal
'
;
import
{
ExtHostConfiguration
}
from
'
vs/workbench/api/node/extHostConfiguration
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
EXT_HOST_CREATION_DELAY
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
TerminalProcess
}
from
'
vs/workbench/parts/terminal/node/terminalProcess
'
;
const
RENDERER_NO_PROCESS_ID
=
-
1
;
...
...
@@ -226,7 +224,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
private
_proxy
:
MainThreadTerminalServiceShape
;
private
_activeTerminal
:
ExtHostTerminal
;
private
_terminals
:
ExtHostTerminal
[]
=
[];
private
_terminalProcesses
:
{
[
id
:
number
]:
cp
.
Child
Process
}
=
{};
private
_terminalProcesses
:
{
[
id
:
number
]:
Terminal
Process
}
=
{};
private
_terminalRenderers
:
ExtHostTerminalRenderer
[]
=
[];
public
get
activeTerminal
():
ExtHostTerminal
{
return
this
.
_activeTerminal
;
}
...
...
@@ -359,7 +357,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
const
terminalConfig
=
this
.
_extHostConfiguration
.
getConfiguration
(
'
terminal.integrated
'
);
const
locale
=
terminalConfig
.
get
(
'
setLocaleVariables
'
)
?
platform
.
locale
:
undefined
;
if
(
!
shellLaunchConfig
.
executable
)
{
// TODO: This duplicates some of TerminalConfigHelper.mergeDefaultShellPathAndArgs and should be merged
// this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
...
...
@@ -383,41 +380,33 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
// const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
// const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...this._configHelper.config.env[platformKey] }, lastActiveWorkspaceRoot);
// const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
// shellLaunchConfig.env = envFromShell;
// Merge process env with the env from config
const
parentEnv
=
{
...
process
.
env
};
// terminalEnvironment.mergeEnvironments(parentEnv, envFromConfig);
const
env
=
{
...
process
.
env
};
// terminalEnvironment.mergeEnvironments(env, envFromConfig);
terminalEnvironment
.
mergeEnvironments
(
env
,
shellLaunchConfig
.
env
);
// Continue env initialization, merging in the env from the launch
// config and adding keys that are needed to create the process
const
env
=
terminalEnvironment
.
createTerminalEnv
(
parentEnv
,
shellLaunchConfig
,
initialCwd
,
locale
,
cols
,
rows
);
const
cwd
=
Uri
.
parse
(
require
.
toUrl
(
'
../../parts/terminal/node
'
)).
fsPath
;
const
options
=
{
env
,
cwd
,
execArgv
:
[]
};
const
locale
=
terminalConfig
.
get
(
'
setLocaleVariables
'
)
?
platform
.
locale
:
undefined
;
terminalEnvironment
.
addTerminalEnvironmentKeys
(
env
,
locale
);
// Fork the process and listen for messages
this
.
_logService
.
debug
(
`Terminal process launching on ext host`
,
options
);
this
.
_terminalProcesses
[
id
]
=
cp
.
fork
(
Uri
.
parse
(
require
.
toUrl
(
'
bootstrap
'
)).
fsPath
,
[
'
--type=terminal
'
],
options
);
this
.
_terminalProcesses
[
id
].
on
(
'
message
'
,
(
message
:
IMessageFromTerminalProcess
)
=>
{
switch
(
message
.
type
)
{
case
'
pid
'
:
this
.
_proxy
.
$sendProcessPid
(
id
,
<
number
>
message
.
content
);
break
;
case
'
title
'
:
this
.
_proxy
.
$sendProcessTitle
(
id
,
<
string
>
message
.
content
);
break
;
case
'
data
'
:
this
.
_proxy
.
$sendProcessData
(
id
,
<
string
>
message
.
content
);
break
;
}
});
this
.
_terminalProcesses
[
id
].
on
(
'
exit
'
,
(
exitCode
)
=>
this
.
_onProcessExit
(
id
,
exitCode
));
this
.
_logService
.
debug
(
`Terminal process launching on ext host`
,
shellLaunchConfig
,
initialCwd
,
cols
,
rows
,
env
);
this
.
_terminalProcesses
[
id
]
=
new
TerminalProcess
(
shellLaunchConfig
,
initialCwd
,
cols
,
rows
,
env
);
this
.
_terminalProcesses
[
id
].
onProcessIdReady
(
pid
=>
this
.
_proxy
.
$sendProcessPid
(
id
,
pid
));
this
.
_terminalProcesses
[
id
].
onProcessTitleChanged
(
title
=>
this
.
_proxy
.
$sendProcessTitle
(
id
,
title
));
this
.
_terminalProcesses
[
id
].
onProcessData
(
data
=>
this
.
_proxy
.
$sendProcessData
(
id
,
data
));
this
.
_terminalProcesses
[
id
].
onProcessExit
((
exitCode
)
=>
this
.
_onProcessExit
(
id
,
exitCode
));
}
public
$acceptProcessInput
(
id
:
number
,
data
:
string
):
void
{
if
(
this
.
_terminalProcesses
[
id
].
connected
)
{
this
.
_terminalProcesses
[
id
].
send
({
event
:
'
input
'
,
data
});
}
this
.
_terminalProcesses
[
id
].
input
(
data
);
}
public
$acceptProcessResize
(
id
:
number
,
cols
:
number
,
rows
:
number
):
void
{
if
(
this
.
_terminalProcesses
[
id
].
connected
)
{
try
{
this
.
_terminalProcesses
[
id
].
send
({
event
:
'
resize
'
,
cols
,
rows
}
);
this
.
_terminalProcesses
[
id
].
resize
(
cols
,
rows
);
}
catch
(
error
)
{
// We tried to write to a closed pipe / channel.
if
(
error
.
code
!==
'
EPIPE
'
&&
error
.
code
!==
'
ERR_IPC_CHANNEL_CLOSED
'
)
{
...
...
@@ -425,19 +414,14 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
}
}
}
}
public
$acceptProcessShutdown
(
id
:
number
):
void
{
if
(
this
.
_terminalProcesses
[
id
].
connected
)
{
this
.
_terminalProcesses
[
id
].
send
({
event
:
'
shutdown
'
});
}
this
.
_terminalProcesses
[
id
].
shutdown
();
}
private
_onProcessExit
(
id
:
number
,
exitCode
:
number
):
void
{
// Remove listeners
const
process
=
this
.
_terminalProcesses
[
id
];
process
.
removeAllListeners
(
'
message
'
);
process
.
removeAllListeners
(
'
exit
'
);
this
.
_terminalProcesses
[
id
].
dispose
();
// Remove process reference
delete
this
.
_terminalProcesses
[
id
];
...
...
src/vs/workbench/buildfile.js
浏览文件 @
4986a041
...
...
@@ -27,8 +27,6 @@ exports.collectModules = function () {
createModuleDescription
(
'
vs/workbench/services/files/node/watcher/nsfw/watcherApp
'
,
[]),
createModuleDescription
(
'
vs/workbench/node/extensionHostProcess
'
,
[]),
createModuleDescription
(
'
vs/workbench/parts/terminal/node/terminalProcess
'
,
[])
];
return
modules
;
...
...
src/vs/workbench/parts/terminal/common/terminal.ts
浏览文件 @
4986a041
...
...
@@ -596,9 +596,9 @@ export interface ITerminalProcessExtHostProxy extends IDisposable {
emitPid
(
pid
:
number
):
void
;
emitExit
(
exitCode
:
number
):
void
;
onInput
(
listener
:
(
data
:
string
)
=>
void
):
void
;
onResize
(
listener
:
(
cols
:
number
,
rows
:
number
)
=>
void
):
void
;
onShutdown
(
listener
:
()
=>
void
):
void
;
onInput
:
Event
<
string
>
;
onResize
:
Event
<
{
cols
:
number
,
rows
:
number
}
>
;
onShutdown
:
Event
<
void
>
;
}
export
interface
ITerminalProcessExtHostRequest
{
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts
浏览文件 @
4986a041
...
...
@@ -3,21 +3,20 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
cp
from
'
child_process
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
*
as
terminalEnvironment
from
'
vs/workbench/parts/terminal/node/terminalEnvironment
'
;
import
Uri
from
'
vs/base/common/uri
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
ProcessState
,
ITerminalProcessManager
,
IShellLaunchConfig
,
ITerminalConfigHelper
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
IConfigurationResolverService
}
from
'
vs/workbench/services/configurationResolver/common/configurationResolver
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
IHistoryService
}
from
'
vs/workbench/services/history/common/history
'
;
import
{
ITerminalChildProcess
,
IMessageFromTerminalProcess
}
from
'
vs/workbench/parts/terminal/node/terminal
'
;
import
{
ITerminalChildProcess
}
from
'
vs/workbench/parts/terminal/node/terminal
'
;
import
{
TerminalProcessExtHostProxy
}
from
'
vs/workbench/parts/terminal/node/terminalProcessExtHostProxy
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
TerminalProcess
}
from
'
vs/workbench/parts/terminal/node/terminalProcess
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
IConfigurationResolverService
}
from
'
vs/workbench/services/configurationResolver/common/configurationResolver
'
;
/** The amount of time to consider terminal errors to be related to the launch */
const
LAUNCHING_DURATION
=
500
;
...
...
@@ -50,13 +49,13 @@ export class TerminalProcessManager implements ITerminalProcessManager {
public
get
onProcessExit
():
Event
<
number
>
{
return
this
.
_onProcessExit
.
event
;
}
constructor
(
private
_terminalId
:
number
,
private
_configHelper
:
ITerminalConfigHelper
,
@
IWorkspaceContextService
private
readonly
_workspaceContextService
:
IWorkspaceContextService
,
private
readonly
_terminalId
:
number
,
private
readonly
_configHelper
:
ITerminalConfigHelper
,
@
IHistoryService
private
readonly
_historyService
:
IHistoryService
,
@
IConfigurationResolverService
private
readonly
_configurationResolverService
:
IConfigurationResolverService
,
@
IInstantiationService
private
readonly
_instantiationService
:
IInstantiationService
,
@
ILogService
private
_logService
:
ILogService
@
ILogService
private
readonly
_logService
:
ILogService
,
@
IWorkspaceContextService
private
readonly
_workspaceContextService
:
IWorkspaceContextService
,
@
IConfigurationResolverService
private
readonly
_configurationResolverService
:
IConfigurationResolverService
)
{
this
.
ptyProcessReady
=
new
TPromise
<
void
>
(
c
=>
{
this
.
onProcessReady
(()
=>
{
...
...
@@ -68,13 +67,11 @@ export class TerminalProcessManager implements ITerminalProcessManager {
public
dispose
():
void
{
if
(
this
.
_process
)
{
if
(
this
.
_process
.
connected
)
{
// If the process was still connected this dispose came from
// within VS Code, not the process, so mark the process as
// killed by the user.
this
.
processState
=
ProcessState
.
KILLED_BY_USER
;
this
.
_process
.
send
({
event
:
'
shutdown
'
});
}
this
.
_process
.
shutdown
();
this
.
_process
=
null
;
}
this
.
_disposables
.
forEach
(
d
=>
d
.
dispose
());
...
...
@@ -94,7 +91,6 @@ export class TerminalProcessManager implements ITerminalProcessManager {
if
(
extensionHostOwned
)
{
this
.
_process
=
this
.
_instantiationService
.
createInstance
(
TerminalProcessExtHostProxy
,
this
.
_terminalId
,
shellLaunchConfig
,
cols
,
rows
);
}
else
{
const
locale
=
this
.
_configHelper
.
config
.
setLocaleVariables
?
platform
.
locale
:
undefined
;
if
(
!
shellLaunchConfig
.
executable
)
{
this
.
_configHelper
.
mergeDefaultShellPathAndArgs
(
shellLaunchConfig
);
}
...
...
@@ -109,23 +105,41 @@ export class TerminalProcessManager implements ITerminalProcessManager {
const
envFromShell
=
terminalEnvironment
.
resolveConfigurationVariables
(
this
.
_configurationResolverService
,
{
...
shellLaunchConfig
.
env
},
lastActiveWorkspaceRoot
);
shellLaunchConfig
.
env
=
envFromShell
;
// Merge process env with the env from config
const
parentEnv
=
{
...
process
.
env
};
terminalEnvironment
.
mergeEnvironments
(
parentEnv
,
envFromConfig
);
// Merge process env with the env from config and from shellLaunchConfig
const
env
=
{
...
process
.
env
};
terminalEnvironment
.
mergeEnvironments
(
env
,
envFromConfig
);
terminalEnvironment
.
mergeEnvironments
(
env
,
shellLaunchConfig
.
env
);
// Continue env initialization, merging in the env from the launch
// config and adding keys that are needed to create the process
const
env
=
terminalEnvironment
.
createTerminalEnv
(
parentEnv
,
shellLaunchConfig
,
this
.
initialCwd
,
locale
,
cols
,
rows
);
const
cwd
=
Uri
.
parse
(
require
.
toUrl
(
'
../node
'
)).
fsPath
;
const
options
=
{
env
,
cwd
};
this
.
_logService
.
debug
(
`Terminal process launching`
,
options
);
// Sanitize the environment, removing any undesirable VS Code and Electron environment
// variables
terminalEnvironment
.
sanitizeEnvironment
(
env
);
this
.
_process
=
cp
.
fork
(
Uri
.
parse
(
require
.
toUrl
(
'
bootstrap
'
)).
fsPath
,
[
'
--type=terminal
'
],
options
);
// Adding other env keys necessary to create the process
const
locale
=
this
.
_configHelper
.
config
.
setLocaleVariables
?
platform
.
locale
:
undefined
;
terminalEnvironment
.
addTerminalEnvironmentKeys
(
env
,
locale
);
this
.
_logService
.
debug
(
`Terminal process launching`
,
shellLaunchConfig
,
this
.
initialCwd
,
cols
,
rows
,
env
);
this
.
_process
=
new
TerminalProcess
(
shellLaunchConfig
,
this
.
initialCwd
,
cols
,
rows
,
env
);
}
this
.
processState
=
ProcessState
.
LAUNCHING
;
this
.
_process
.
on
(
'
message
'
,
message
=>
this
.
_onMessage
(
message
));
this
.
_process
.
on
(
'
exit
'
,
exitCode
=>
this
.
_onExit
(
exitCode
));
this
.
_process
.
onProcessData
(
data
=>
{
this
.
_onProcessData
.
fire
(
data
);
});
this
.
_process
.
onProcessIdReady
(
pid
=>
{
this
.
shellProcessId
=
pid
;
this
.
_onProcessReady
.
fire
();
// Send any queued data that's waiting
if
(
this
.
_preLaunchInputQueue
.
length
>
0
)
{
this
.
_process
.
input
(
this
.
_preLaunchInputQueue
.
join
(
''
));
this
.
_preLaunchInputQueue
.
length
=
0
;
}
});
this
.
_process
.
onProcessTitleChanged
(
title
=>
this
.
_onProcessTitle
.
fire
(
title
));
this
.
_process
.
onProcessExit
(
exitCode
=>
this
.
_onExit
(
exitCode
));
setTimeout
(()
=>
{
if
(
this
.
processState
===
ProcessState
.
LAUNCHING
)
{
...
...
@@ -135,10 +149,13 @@ export class TerminalProcessManager implements ITerminalProcessManager {
}
public
setDimensions
(
cols
:
number
,
rows
:
number
):
void
{
if
(
this
.
_process
&&
this
.
_process
.
connected
)
{
// The child process could aready be terminated
if
(
!
this
.
_process
)
{
return
;
}
// The child process could already be terminated
try
{
this
.
_process
.
send
({
event
:
'
resize
'
,
cols
,
rows
}
);
this
.
_process
.
resize
(
cols
,
rows
);
}
catch
(
error
)
{
// We tried to write to a closed pipe / channel.
if
(
error
.
code
!==
'
EPIPE
'
&&
error
.
code
!==
'
ERR_IPC_CHANNEL_CLOSED
'
)
{
...
...
@@ -146,16 +163,12 @@ export class TerminalProcessManager implements ITerminalProcessManager {
}
}
}
}
public
write
(
data
:
string
):
void
{
if
(
this
.
shellProcessId
)
{
if
(
this
.
_process
)
{
// Send data if the pty is ready
this
.
_process
.
send
({
event
:
'
input
'
,
data
});
this
.
_process
.
input
(
data
);
}
}
else
{
// If the pty is not ready, queue the data received to send later
...
...
@@ -163,31 +176,6 @@ export class TerminalProcessManager implements ITerminalProcessManager {
}
}
private
_onMessage
(
message
:
IMessageFromTerminalProcess
):
void
{
this
.
_logService
.
trace
(
`terminalProcessManager#_onMessage (shellProcessId:
${
this
.
shellProcessId
}
`
,
message
);
switch
(
message
.
type
)
{
case
'
data
'
:
this
.
_onProcessData
.
fire
(
<
string
>
message
.
content
);
break
;
case
'
pid
'
:
this
.
shellProcessId
=
<
number
>
message
.
content
;
this
.
_onProcessReady
.
fire
();
// Send any queued data that's waiting
if
(
this
.
_preLaunchInputQueue
.
length
>
0
)
{
this
.
_process
.
send
({
event
:
'
input
'
,
data
:
this
.
_preLaunchInputQueue
.
join
(
''
)
});
this
.
_preLaunchInputQueue
.
length
=
0
;
}
break
;
case
'
title
'
:
this
.
_onProcessTitle
.
fire
(
<
string
>
message
.
content
);
break
;
}
}
private
_onExit
(
exitCode
:
number
):
void
{
this
.
_process
=
null
;
...
...
src/vs/workbench/parts/terminal/node/terminal.ts
浏览文件 @
4986a041
...
...
@@ -7,30 +7,21 @@ import * as os from 'os';
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
*
as
processes
from
'
vs/base/node/processes
'
;
import
{
readFile
,
fileExists
}
from
'
vs/base/node/pfs
'
;
export
interface
IMessageFromTerminalProcess
{
type
:
'
pid
'
|
'
data
'
|
'
title
'
;
content
:
number
|
string
;
}
export
interface
IMessageToTerminalProcess
{
event
:
'
resize
'
|
'
input
'
|
'
shutdown
'
;
data
?:
string
;
cols
?:
number
;
rows
?:
number
;
}
import
{
Event
}
from
'
vs/base/common/event
'
;
/**
* An interface representing a raw terminal child process, this is a subset of the
* child_process.ChildProcess node.js interface.
*/
export
interface
ITerminalChildProcess
{
readonly
connected
:
boolean
;
send
(
message
:
IMessageToTerminalProcess
):
boolean
;
onProcessData
:
Event
<
string
>
;
onProcessExit
:
Event
<
number
>
;
onProcessIdReady
:
Event
<
number
>
;
onProcessTitleChanged
:
Event
<
string
>
;
on
(
event
:
'
exit
'
,
listener
:
(
code
:
number
)
=>
void
):
this
;
on
(
event
:
'
message
'
,
listener
:
(
message
:
IMessageFromTerminalProcess
)
=>
void
):
this
;
shutdown
():
void
;
input
(
data
:
string
):
void
;
resize
(
cols
:
number
,
rows
:
number
):
void
;
}
let
_TERMINAL_DEFAULT_SHELL_UNIX_LIKE
:
string
=
null
;
...
...
src/vs/workbench/parts/terminal/node/terminalEnvironment.ts
浏览文件 @
4986a041
...
...
@@ -8,7 +8,6 @@ import * as paths from 'vs/base/common/paths';
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
pkg
from
'
vs/platform/node/package
'
;
import
Uri
from
'
vs/base/common/uri
'
;
import
{
IStringDictionary
}
from
'
vs/base/common/collections
'
;
import
{
IWorkspaceFolder
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
IShellLaunchConfig
,
ITerminalConfigHelper
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
IConfigurationResolverService
}
from
'
vs/workbench/services/configurationResolver/common/configurationResolver
'
;
...
...
@@ -17,7 +16,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati
* This module contains utility functions related to the environment, cwd and paths.
*/
export
function
mergeEnvironments
(
parent
:
IStringDictionary
<
string
>
,
other
:
IStringDictionary
<
string
>
)
{
export
function
mergeEnvironments
(
parent
:
platform
.
IProcessEnvironment
,
other
:
platform
.
IProcessEnvironment
):
void
{
if
(
!
other
)
{
return
;
}
...
...
@@ -44,7 +43,7 @@ export function mergeEnvironments(parent: IStringDictionary<string>, other: IStr
}
}
function
_mergeEnvironmentValue
(
env
:
IStringDictionary
<
string
>
,
key
:
string
,
value
:
string
|
null
)
{
function
_mergeEnvironmentValue
(
env
:
platform
.
IProcessEnvironment
,
key
:
string
,
value
:
string
|
null
):
void
{
if
(
typeof
value
===
'
string
'
)
{
env
[
key
]
=
value
;
}
else
{
...
...
@@ -52,34 +51,44 @@ function _mergeEnvironmentValue(env: IStringDictionary<string>, key: string, val
}
}
export
function
createTerminalEnv
(
parentEnv
:
IStringDictionary
<
string
>
,
shell
:
IShellLaunchConfig
,
cwd
:
string
,
locale
:
string
,
cols
?:
number
,
rows
?:
number
):
IStringDictionary
<
string
>
{
const
env
=
{
...
parentEnv
};
if
(
shell
.
env
)
{
mergeEnvironments
(
env
,
shell
.
env
);
export
function
sanitizeEnvironment
(
env
:
platform
.
IProcessEnvironment
):
void
{
// Remove keys based on strings
const
keysToRemove
=
[
'
ELECTRON_ENABLE_STACK_DUMPING
'
,
'
ELECTRON_ENABLE_LOGGING
'
,
'
ELECTRON_NO_ASAR
'
,
'
ELECTRON_NO_ATTACH_CONSOLE
'
,
'
ELECTRON_RUN_AS_NODE
'
,
'
GOOGLE_API_KEY
'
,
'
VSCODE_CLI
'
,
'
VSCODE_DEV
'
,
'
VSCODE_IPC_HOOK
'
,
'
VSCODE_LOGS
'
,
'
VSCODE_NLS_CONFIG
'
,
'
VSCODE_PORTABLE
'
,
'
VSCODE_PID
'
,
];
keysToRemove
.
forEach
((
key
)
=>
{
if
(
env
[
key
])
{
delete
env
[
key
];
}
});
env
[
'
PTYPID
'
]
=
process
.
pid
.
toString
();
env
[
'
PTYSHELL
'
]
=
shell
.
executable
;
// Remove keys based on regexp
Object
.
keys
(
env
).
forEach
(
key
=>
{
if
(
key
.
search
(
/^VSCODE_NODE_CACHED_DATA_DIR_
\d
+$/
)
===
0
)
{
delete
env
[
key
];
}
});
}
export
function
addTerminalEnvironmentKeys
(
env
:
platform
.
IProcessEnvironment
,
locale
:
string
|
undefined
):
void
{
env
[
'
TERM_PROGRAM
'
]
=
'
vscode
'
;
env
[
'
TERM_PROGRAM_VERSION
'
]
=
pkg
.
version
;
if
(
shell
.
args
)
{
if
(
typeof
shell
.
args
===
'
string
'
)
{
env
[
`PTYSHELLCMDLINE`
]
=
shell
.
args
;
}
else
{
shell
.
args
.
forEach
((
arg
,
i
)
=>
env
[
`PTYSHELLARG
${
i
}
`
]
=
arg
);
}
}
env
[
'
PTYCWD
'
]
=
cwd
;
env
[
'
LANG
'
]
=
_getLangEnvVariable
(
locale
);
if
(
cols
&&
rows
)
{
env
[
'
PTYCOLS
'
]
=
cols
.
toString
();
env
[
'
PTYROWS
'
]
=
rows
.
toString
();
}
env
[
'
AMD_ENTRYPOINT
'
]
=
'
vs/workbench/parts/terminal/node/terminalProcess
'
;
return
env
;
}
export
function
resolveConfigurationVariables
(
configurationResolverService
:
IConfigurationResolverService
,
env
:
IStringDictionary
<
string
>
,
lastActiveWorkspaceRoot
:
IWorkspaceFolder
):
IStringDictionary
<
string
>
{
export
function
resolveConfigurationVariables
(
configurationResolverService
:
IConfigurationResolverService
,
env
:
platform
.
IProcessEnvironment
,
lastActiveWorkspaceRoot
:
IWorkspaceFolder
):
platform
.
IProcessEnvironment
{
Object
.
keys
(
env
).
forEach
((
key
)
=>
{
if
(
typeof
env
[
key
]
===
'
string
'
)
{
env
[
key
]
=
configurationResolverService
.
resolve
(
lastActiveWorkspaceRoot
,
env
[
key
]);
...
...
src/vs/workbench/parts/terminal/node/terminalProcess.ts
浏览文件 @
4986a041
...
...
@@ -5,163 +5,121 @@
import
*
as
os
from
'
os
'
;
import
*
as
path
from
'
path
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
*
as
pty
from
'
node-pty
'
;
// The pty process needs to be run in its own child process to get around maxing out CPU on Mac,
// see https://github.com/electron/electron/issues/38
let
shellName
:
string
;
if
(
os
.
platform
()
===
'
win32
'
)
{
shellName
=
path
.
basename
(
process
.
env
.
PTYSHELL
);
}
else
{
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
ITerminalChildProcess
}
from
'
vs/workbench/parts/terminal/node/terminal
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IShellLaunchConfig
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
export
class
TerminalProcess
implements
ITerminalChildProcess
,
IDisposable
{
private
_exitCode
:
number
;
private
_closeTimeout
:
number
;
private
_ptyProcess
:
pty
.
IPty
;
private
_currentTitle
:
string
=
''
;
private
readonly
_onProcessData
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onProcessData
():
Event
<
string
>
{
return
this
.
_onProcessData
.
event
;
}
private
readonly
_onProcessExit
:
Emitter
<
number
>
=
new
Emitter
<
number
>
();
public
get
onProcessExit
():
Event
<
number
>
{
return
this
.
_onProcessExit
.
event
;
}
private
readonly
_onProcessIdReady
:
Emitter
<
number
>
=
new
Emitter
<
number
>
();
public
get
onProcessIdReady
():
Event
<
number
>
{
return
this
.
_onProcessIdReady
.
event
;
}
private
readonly
_onProcessTitleChanged
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onProcessTitleChanged
():
Event
<
string
>
{
return
this
.
_onProcessTitleChanged
.
event
;
}
constructor
(
shellLaunchConfig
:
IShellLaunchConfig
,
cwd
:
string
,
cols
:
number
,
rows
:
number
,
env
:
platform
.
IProcessEnvironment
)
{
let
shellName
:
string
;
if
(
os
.
platform
()
===
'
win32
'
)
{
shellName
=
path
.
basename
(
shellLaunchConfig
.
executable
);
}
else
{
// Using 'xterm-256color' here helps ensure that the majority of Linux distributions will use a
// color prompt as defined in the default ~/.bashrc file.
shellName
=
'
xterm-256color
'
;
}
const
shell
=
process
.
env
.
PTYSHELL
;
const
args
=
getArgs
();
const
cwd
=
process
.
env
.
PTYCWD
;
const
cols
=
process
.
env
.
PTYCOLS
;
const
rows
=
process
.
env
.
PTYROWS
;
let
currentTitle
=
''
;
setupPlanB
(
Number
(
process
.
env
.
PTYPID
));
cleanEnv
();
interface
IOptions
{
name
:
string
;
cwd
:
string
;
cols
?:
number
;
rows
?:
number
;
}
}
const
options
:
I
Options
=
{
const
options
:
pty
.
IPtyFork
Options
=
{
name
:
shellName
,
cwd
};
if
(
cols
&&
rows
)
{
options
.
cols
=
parseInt
(
cols
,
10
);
options
.
rows
=
parseInt
(
rows
,
10
);
}
const
ptyProcess
=
pty
.
spawn
(
shell
,
args
,
options
);
let
closeTimeout
:
number
;
let
exitCode
:
number
;
// Allow any trailing data events to be sent before the exit event is sent.
// See https://github.com/Tyriar/node-pty/issues/72
function
queueProcessExit
()
{
if
(
closeTimeout
)
{
clearTimeout
(
closeTimeout
);
cwd
,
env
,
cols
,
rows
};
this
.
_ptyProcess
=
pty
.
spawn
(
shellLaunchConfig
.
executable
,
shellLaunchConfig
.
args
,
options
);
this
.
_ptyProcess
.
on
(
'
data
'
,
(
data
)
=>
{
this
.
_onProcessData
.
fire
(
data
);
if
(
this
.
_closeTimeout
)
{
clearTimeout
(
this
.
_closeTimeout
);
this
.
_queueProcessExit
();
}
closeTimeout
=
setTimeout
(
function
()
{
ptyProcess
.
kill
();
process
.
exit
(
exitCode
);
},
250
);
}
ptyProcess
.
on
(
'
data
'
,
function
(
data
)
{
process
.
send
({
type
:
'
data
'
,
content
:
data
});
if
(
closeTimeout
)
{
clearTimeout
(
closeTimeout
);
queueProcessExit
();
}
});
ptyProcess
.
on
(
'
exit
'
,
function
(
code
)
{
exitCode
=
code
;
queueProcessExit
();
});
this
.
_ptyProcess
.
on
(
'
exit
'
,
(
code
)
=>
{
this
.
_exitCode
=
code
;
this
.
_queueProcessExit
();
});
process
.
on
(
'
message
'
,
function
(
message
)
{
if
(
message
.
event
===
'
input
'
)
{
ptyProcess
.
write
(
message
.
data
);
}
else
if
(
message
.
event
===
'
resize
'
)
{
// Ensure that cols and rows are always >= 1, this prevents a native
// exception in winpty.
ptyProcess
.
resize
(
Math
.
max
(
message
.
cols
,
1
),
Math
.
max
(
message
.
rows
,
1
));
}
else
if
(
message
.
event
===
'
shutdown
'
)
{
queueProcessExit
();
// TODO: We should no longer need to delay this since pty.spawn is sync
setTimeout
(()
=>
{
this
.
_sendProcessId
();
},
500
);
this
.
_setupTitlePolling
();
}
});
sendProcessId
();
setupTitlePolling
();
public
dispose
():
void
{
this
.
_onProcessData
.
dispose
();
this
.
_onProcessExit
.
dispose
();
this
.
_onProcessIdReady
.
dispose
();
this
.
_onProcessTitleChanged
.
dispose
();
}
function
getArgs
():
string
|
string
[]
{
if
(
process
.
env
[
'
PTYSHELLCMDLINE
'
])
{
return
process
.
env
[
'
PTYSHELLCMDLINE
'
];
private
_setupTitlePolling
()
{
this
.
_sendProcessTitle
();
setInterval
(()
=>
{
if
(
this
.
_currentTitle
!==
this
.
_ptyProcess
.
process
)
{
this
.
_sendProcessTitle
();
}
const
args
=
[];
let
i
=
0
;
while
(
process
.
env
[
'
PTYSHELLARG
'
+
i
])
{
args
.
push
(
process
.
env
[
'
PTYSHELLARG
'
+
i
]);
i
++
;
},
200
);
}
return
args
;
}
function
cleanEnv
()
{
const
keys
=
[
'
AMD_ENTRYPOINT
'
,
'
ELECTRON_NO_ASAR
'
,
'
ELECTRON_RUN_AS_NODE
'
,
'
GOOGLE_API_KEY
'
,
'
PTYCWD
'
,
'
PTYPID
'
,
'
PTYSHELL
'
,
'
PTYCOLS
'
,
'
PTYROWS
'
,
'
PTYSHELLCMDLINE
'
,
'
VSCODE_LOGS
'
,
'
VSCODE_PORTABLE
'
,
'
VSCODE_PID
'
,
];
keys
.
forEach
(
function
(
key
)
{
if
(
process
.
env
[
key
])
{
delete
process
.
env
[
key
];
// Allow any trailing data events to be sent before the exit event is sent.
// See https://github.com/Tyriar/node-pty/issues/72
private
_queueProcessExit
()
{
if
(
this
.
_closeTimeout
)
{
clearTimeout
(
this
.
_closeTimeout
);
}
});
let
i
=
0
;
while
(
process
.
env
[
'
PTYSHELLARG
'
+
i
])
{
delete
process
.
env
[
'
PTYSHELLARG
'
+
i
]
;
i
++
;
this
.
_closeTimeout
=
setTimeout
(()
=>
{
this
.
_ptyProcess
.
kill
()
;
this
.
_onProcessExit
.
fire
(
this
.
_exitCode
);
this
.
dispose
()
;
},
250
)
;
}
}
function
setupPlanB
(
parentPid
:
number
)
{
setInterval
(
function
()
{
try
{
process
.
kill
(
parentPid
,
0
);
// throws an exception if the main process doesn't exist anymore.
}
catch
(
e
)
{
process
.
exit
();
private
_sendProcessId
()
{
this
.
_onProcessIdReady
.
fire
(
this
.
_ptyProcess
.
pid
);
}
},
5000
);
}
function
sendProcessId
()
{
process
.
send
({
type
:
'
pid
'
,
content
:
ptyProcess
.
pid
});
}
private
_sendProcessTitle
():
void
{
this
.
_currentTitle
=
this
.
_ptyProcess
.
process
;
this
.
_onProcessTitleChanged
.
fire
(
this
.
_currentTitle
);
}
function
setupTitlePolling
()
{
sendProcessTitle
();
setInterval
(
function
()
{
if
(
currentTitle
!==
ptyProcess
.
process
)
{
sendProcessTitle
();
public
shutdown
():
void
{
this
.
_queueProcessExit
();
}
},
200
);
}
function
sendProcessTitle
()
{
process
.
send
({
type
:
'
title
'
,
content
:
ptyProcess
.
process
});
currentTitle
=
ptyProcess
.
process
;
public
input
(
data
:
string
):
void
{
this
.
_ptyProcess
.
write
(
data
);
}
public
resize
(
cols
:
number
,
rows
:
number
):
void
{
// Ensure that cols and rows are always >= 1, this prevents a native
// exception in winpty.
this
.
_ptyProcess
.
resize
(
Math
.
max
(
cols
,
1
),
Math
.
max
(
rows
,
1
));
}
}
src/vs/workbench/parts/terminal/node/terminalProcessExtHostProxy.ts
浏览文件 @
4986a041
...
...
@@ -3,17 +3,30 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
ITerminalChildProcess
,
IMessageToTerminalProcess
,
IMessageFromTerminalProcess
}
from
'
vs/workbench/parts/terminal/node/terminal
'
;
import
{
Event
Emitter
}
from
'
events
'
;
import
{
ITerminalChildProcess
}
from
'
vs/workbench/parts/terminal/node/terminal
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
ITerminalService
,
ITerminalProcessExtHostProxy
,
IShellLaunchConfig
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
IDisposable
,
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
export
class
TerminalProcessExtHostProxy
extends
EventEmitter
implements
ITerminalChildProcess
,
ITerminalProcessExtHostProxy
{
// For ext host processes connected checks happen on the ext host
public
connected
:
boolean
=
true
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
export
class
TerminalProcessExtHostProxy
implements
ITerminalChildProcess
,
ITerminalProcessExtHostProxy
{
private
_disposables
:
IDisposable
[]
=
[];
private
readonly
_onProcessData
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onProcessData
():
Event
<
string
>
{
return
this
.
_onProcessData
.
event
;
}
private
readonly
_onProcessExit
:
Emitter
<
number
>
=
new
Emitter
<
number
>
();
public
get
onProcessExit
():
Event
<
number
>
{
return
this
.
_onProcessExit
.
event
;
}
private
readonly
_onProcessIdReady
:
Emitter
<
number
>
=
new
Emitter
<
number
>
();
public
get
onProcessIdReady
():
Event
<
number
>
{
return
this
.
_onProcessIdReady
.
event
;
}
private
readonly
_onProcessTitleChanged
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onProcessTitleChanged
():
Event
<
string
>
{
return
this
.
_onProcessTitleChanged
.
event
;
}
private
readonly
_onInput
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onInput
():
Event
<
string
>
{
return
this
.
_onInput
.
event
;
}
private
readonly
_onResize
:
Emitter
<
{
cols
:
number
,
rows
:
number
}
>
=
new
Emitter
<
{
cols
:
number
,
rows
:
number
}
>
();
public
get
onResize
():
Event
<
{
cols
:
number
,
rows
:
number
}
>
{
return
this
.
_onResize
.
event
;
}
private
readonly
_onShutdown
:
Emitter
<
void
>
=
new
Emitter
<
void
>
();
public
get
onShutdown
():
Event
<
void
>
{
return
this
.
_onShutdown
.
event
;
}
constructor
(
public
terminalId
:
number
,
shellLaunchConfig
:
IShellLaunchConfig
,
...
...
@@ -21,8 +34,6 @@ export class TerminalProcessExtHostProxy extends EventEmitter implements ITermin
rows
:
number
,
@
ITerminalService
private
_terminalService
:
ITerminalService
)
{
super
();
// TODO: Return TPromise<boolean> indicating success? Teardown if failure?
this
.
_terminalService
.
requestExtHostProcess
(
this
,
shellLaunchConfig
,
cols
,
rows
);
}
...
...
@@ -33,46 +44,30 @@ export class TerminalProcessExtHostProxy extends EventEmitter implements ITermin
}
public
emitData
(
data
:
string
):
void
{
this
.
emit
(
'
message
'
,
{
type
:
'
data
'
,
content
:
data
}
as
IMessageFromTerminalProcess
);
this
.
_onProcessData
.
fire
(
data
);
}
public
emitTitle
(
title
:
string
):
void
{
this
.
emit
(
'
message
'
,
{
type
:
'
title
'
,
content
:
title
}
as
IMessageFromTerminalProcess
);
this
.
_onProcessTitleChanged
.
fire
(
title
);
}
public
emitPid
(
pid
:
number
):
void
{
this
.
emit
(
'
message
'
,
{
type
:
'
pid
'
,
content
:
pid
}
as
IMessageFromTerminalProcess
);
this
.
_onProcessIdReady
.
fire
(
pid
);
}
public
emitExit
(
exitCode
:
number
):
void
{
this
.
emit
(
'
exit
'
,
exitCode
);
this
.
_onProcessExit
.
fire
(
exitCode
);
this
.
dispose
();
}
public
send
(
message
:
IMessageToTerminalProcess
):
boolean
{
switch
(
message
.
event
)
{
case
'
input
'
:
this
.
emit
(
'
input
'
,
message
.
data
);
break
;
case
'
resize
'
:
this
.
emit
(
'
resize
'
,
message
.
cols
,
message
.
rows
);
break
;
case
'
shutdown
'
:
this
.
emit
(
'
shutdown
'
);
break
;
}
return
true
;
}
public
onInput
(
listener
:
(
data
:
string
)
=>
void
):
void
{
const
outerListener
=
(
data
)
=>
listener
(
data
);
this
.
on
(
'
input
'
,
outerListener
);
this
.
_disposables
.
push
(
toDisposable
(()
=>
this
.
removeListener
(
'
input
'
,
outerListener
)));
public
shutdown
():
void
{
this
.
_onShutdown
.
fire
();
}
public
onResize
(
listener
:
(
cols
:
number
,
rows
:
number
)
=>
void
):
void
{
const
outerListener
=
(
cols
,
rows
)
=>
listener
(
cols
,
rows
);
this
.
on
(
'
resize
'
,
outerListener
);
this
.
_disposables
.
push
(
toDisposable
(()
=>
this
.
removeListener
(
'
resize
'
,
outerListener
)));
public
input
(
data
:
string
):
void
{
this
.
_onInput
.
fire
(
data
);
}
public
onShutdown
(
listener
:
()
=>
void
):
void
{
const
outerListener
=
()
=>
listener
();
this
.
on
(
'
shutdown
'
,
outerListener
);
this
.
_disposables
.
push
(
toDisposable
(()
=>
this
.
removeListener
(
'
shutdown
'
,
outerListener
)));
public
resize
(
cols
:
number
,
rows
:
number
):
void
{
this
.
_onResize
.
fire
({
cols
,
rows
});
}
}
\ No newline at end of file
src/vs/workbench/parts/terminal/test/node/terminalEnvironment.test.ts
浏览文件 @
4986a041
...
...
@@ -9,45 +9,47 @@ import * as platform from 'vs/base/common/platform';
import
*
as
terminalEnvironment
from
'
vs/workbench/parts/terminal/node/terminalEnvironment
'
;
import
Uri
from
'
vs/base/common/uri
'
;
import
{
IStringDictionary
}
from
'
vs/base/common/collections
'
;
import
{
I
ShellLaunchConfig
,
I
TerminalConfigHelper
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
ITerminalConfigHelper
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
suite
(
'
Workbench - TerminalEnvironment
'
,
()
=>
{
test
(
'
createTerminalEnv
'
,
function
()
{
const
shell1
=
{
executable
:
'
/bin/foosh
'
,
args
:
[
'
-bar
'
,
'
baz
'
]
test
(
'
addTerminalEnvironmentKeys
'
,
()
=>
{
const
env
=
{
FOO
:
'
bar
'
};
const
locale
=
'
en-au
'
;
terminalEnvironment
.
addTerminalEnvironmentKeys
(
env
,
locale
);
assert
.
equal
(
env
[
'
TERM_PROGRAM
'
],
'
vscode
'
);
assert
.
equal
(
env
[
'
TERM_PROGRAM_VERSION
'
].
search
(
/^
\d
+
\.\d
+
\.\d
+$/
),
0
);
assert
.
equal
(
env
[
'
LANG
'
],
'
en_AU.UTF-8
'
,
'
LANG is equal to the requested locale with UTF-8
'
);
const
env2
=
{
FOO
:
'
bar
'
};
terminalEnvironment
.
addTerminalEnvironmentKeys
(
env2
,
null
);
assert
.
equal
(
env2
[
'
LANG
'
],
'
en_US.UTF-8
'
,
'
LANG is equal to en_US.UTF-8 as fallback.
'
);
// More info on issue #14586
const
env3
=
{
LANG
:
'
en_US.UTF-8
'
};
terminalEnvironment
.
addTerminalEnvironmentKeys
(
env3
,
null
);
assert
.
equal
(
env3
[
'
LANG
'
],
'
en_US.UTF-8
'
,
'
LANG is equal to the parent environment
\'
s LANG
'
);
});
test
(
'
sanitizeEnvironment
'
,
()
=>
{
let
env
=
{
FOO
:
'
bar
'
,
ELECTRON_ENABLE_STACK_DUMPING
:
'
x
'
,
ELECTRON_ENABLE_LOGGING
:
'
x
'
,
ELECTRON_NO_ASAR
:
'
x
'
,
ELECTRON_NO_ATTACH_CONSOLE
:
'
x
'
,
ELECTRON_RUN_AS_NODE
:
'
x
'
,
GOOGLE_API_KEY
:
'
x
'
,
VSCODE_CLI
:
'
x
'
,
VSCODE_DEV
:
'
x
'
,
VSCODE_IPC_HOOK
:
'
x
'
,
VSCODE_LOGS
:
'
x
'
,
VSCODE_NLS_CONFIG
:
'
x
'
,
VSCODE_PORTABLE
:
'
x
'
,
VSCODE_PID
:
'
x
'
,
VSCODE_NODE_CACHED_DATA_DIR_12345
:
'
x
'
};
const
parentEnv1
:
IStringDictionary
<
string
>
=
{
ok
:
true
}
as
any
;
const
env1
=
terminalEnvironment
.
createTerminalEnv
(
parentEnv1
,
shell1
,
'
/foo
'
,
'
en-au
'
);
assert
.
ok
(
env1
[
'
ok
'
],
'
Parent environment is copied
'
);
assert
.
deepStrictEqual
(
parentEnv1
,
{
ok
:
true
},
'
Parent environment is unchanged
'
);
assert
.
equal
(
env1
[
'
PTYPID
'
],
process
.
pid
.
toString
(),
'
PTYPID is equal to the current PID
'
);
assert
.
equal
(
env1
[
'
PTYSHELL
'
],
'
/bin/foosh
'
,
'
PTYSHELL is equal to the provided shell
'
);
assert
.
equal
(
env1
[
'
PTYSHELLARG0
'
],
'
-bar
'
,
'
PTYSHELLARG0 is equal to the first shell argument
'
);
assert
.
equal
(
env1
[
'
PTYSHELLARG1
'
],
'
baz
'
,
'
PTYSHELLARG1 is equal to the first shell argument
'
);
assert
.
ok
(
!
(
'
PTYSHELLARG2
'
in
env1
),
'
PTYSHELLARG2 is unset
'
);
assert
.
equal
(
env1
[
'
PTYCWD
'
],
'
/foo
'
,
'
PTYCWD is equal to requested cwd
'
);
assert
.
equal
(
env1
[
'
LANG
'
],
'
en_AU.UTF-8
'
,
'
LANG is equal to the requested locale with UTF-8
'
);
const
shell2
:
IShellLaunchConfig
=
{
executable
:
'
/bin/foosh
'
,
args
:
[]
};
const
parentEnv2
:
IStringDictionary
<
string
>
=
{
LANG
:
'
en_US.UTF-8
'
};
const
env2
=
terminalEnvironment
.
createTerminalEnv
(
parentEnv2
,
shell2
,
'
/foo
'
,
'
en-au
'
);
assert
.
ok
(
!
(
'
PTYSHELLARG0
'
in
env2
),
'
PTYSHELLARG0 is unset
'
);
assert
.
equal
(
env2
[
'
PTYCWD
'
],
'
/foo
'
,
'
PTYCWD is equal to /foo
'
);
assert
.
equal
(
env2
[
'
LANG
'
],
'
en_AU.UTF-8
'
,
'
LANG is equal to the requested locale with UTF-8
'
);
const
env3
=
terminalEnvironment
.
createTerminalEnv
(
parentEnv1
,
shell1
,
'
/
'
,
null
);
assert
.
equal
(
env3
[
'
LANG
'
],
'
en_US.UTF-8
'
,
'
LANG is equal to en_US.UTF-8 as fallback.
'
);
// More info on issue #14586
const
env4
=
terminalEnvironment
.
createTerminalEnv
(
parentEnv2
,
shell1
,
'
/
'
,
null
);
assert
.
equal
(
env4
[
'
LANG
'
],
'
en_US.UTF-8
'
,
'
LANG is equal to the parent environment
\'
s LANG
'
);
terminalEnvironment
.
sanitizeEnvironment
(
env
);
assert
.
equal
(
env
[
'
FOO
'
],
'
bar
'
);
assert
.
equal
(
Object
.
keys
(
env
).
length
,
1
);
});
suite
(
'
mergeEnvironments
'
,
()
=>
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录