Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
394b7ece
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,发现更多精彩内容 >>
提交
394b7ece
编写于
4月 13, 2018
作者:
D
Daniel Imms
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Move more create process over, remove node dep on terminal instance
上级
c9e02ff7
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
434 addition
and
400 deletion
+434
-400
src/vs/workbench/parts/terminal/common/terminal.ts
src/vs/workbench/parts/terminal/common/terminal.ts
+2
-1
src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts
...bench/parts/terminal/electron-browser/terminalInstance.ts
+32
-185
src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts
...parts/terminal/electron-browser/terminalProcessManager.ts
+190
-4
src/vs/workbench/parts/terminal/test/electron-browser/terminalInstance.test.ts
...s/terminal/test/electron-browser/terminalInstance.test.ts
+210
-210
未找到文件。
src/vs/workbench/parts/terminal/common/terminal.ts
浏览文件 @
394b7ece
...
...
@@ -470,10 +470,11 @@ export interface ITerminalProcessManager extends IDisposable {
ptyProcessReady
:
TPromise
<
void
>
;
shellProcessId
:
number
;
onShellProcessIdReady
:
Event
<
number
>
;
initialCwd
:
string
;
acceptProcessMessage
(
message
):
void
;
addDisposable
(
disposable
:
IDisposable
);
createProcess
(
l
aunchConfig
:
IShellLaunchConfig
);
createProcess
(
shellL
aunchConfig
:
IShellLaunchConfig
);
write
(
data
:
string
):
void
;
}
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts
浏览文件 @
394b7ece
...
...
@@ -3,21 +3,17 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
cp
from
'
child_process
'
;
import
*
as
os
from
'
os
'
;
import
*
as
path
from
'
path
'
;
import
*
as
lifecycle
from
'
vs/base/common/lifecycle
'
;
import
*
as
nls
from
'
vs/nls
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
*
as
paths
from
'
vs/base/common/paths
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
Uri
from
'
vs/base/common/uri
'
;
import
{
WindowsShellHelper
}
from
'
vs/workbench/parts/terminal/electron-browser/windowsShellHelper
'
;
import
{
Terminal
as
XTermTerminal
}
from
'
vscode-xterm
'
;
import
{
IContextKeyService
,
IContextKey
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
IKeybindingService
}
from
'
vs/platform/keybinding/common/keybinding
'
;
import
{
IPanelService
}
from
'
vs/workbench/services/panel/common/panelService
'
;
import
{
IStringDictionary
}
from
'
vs/base/common/collections
'
;
import
{
ITerminalInstance
,
KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED
,
TERMINAL_PANEL_ID
,
IShellLaunchConfig
,
ITerminalProcessManager
,
ITerminalProcessMessage
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
StandardKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
...
...
@@ -29,12 +25,8 @@ import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService }
import
{
scrollbarSliderBackground
,
scrollbarSliderHoverBackground
,
scrollbarSliderActiveBackground
,
activeContrastBorder
}
from
'
vs/platform/theme/common/colorRegistry
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IClipboardService
}
from
'
vs/platform/clipboard/common/clipboardService
'
;
import
{
IHistoryService
}
from
'
vs/workbench/services/history/common/history
'
;
import
pkg
from
'
vs/platform/node/package
'
;
import
{
ansiColorIdentifiers
,
TERMINAL_BACKGROUND_COLOR
,
TERMINAL_FOREGROUND_COLOR
,
TERMINAL_CURSOR_FOREGROUND_COLOR
,
TERMINAL_CURSOR_BACKGROUND_COLOR
,
TERMINAL_SELECTION_BACKGROUND_COLOR
}
from
'
vs/workbench/parts/terminal/electron-browser/terminalColorRegistry
'
;
import
{
PANEL_BACKGROUND
}
from
'
vs/workbench/common/theme
'
;
import
{
IConfigurationResolverService
}
from
'
vs/workbench/services/configurationResolver/common/configurationResolver
'
;
import
{
IWorkspaceContextService
,
IWorkspaceFolder
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
IEditorOptions
}
from
'
vs/editor/common/config/editorOptions
'
;
import
{
INotificationService
}
from
'
vs/platform/notification/common/notification
'
;
...
...
@@ -100,7 +92,7 @@ export class TerminalInstance implements ITerminalInstance {
private
_rows
:
number
;
private
_messageTitleListener
:
(
message
:
{
type
:
string
,
content
:
string
})
=>
void
;
// private _preLaunchInputQueue: string;
private
_initialCwd
:
string
;
//
private _initialCwd: string;
private
_windowsShellHelper
:
WindowsShellHelper
;
private
_onLineDataListeners
:
((
lineData
:
string
)
=>
void
)[];
private
_xtermReadyPromise
:
TPromise
<
void
>
;
...
...
@@ -136,10 +128,7 @@ export class TerminalInstance implements ITerminalInstance {
@
IPanelService
private
readonly
_panelService
:
IPanelService
,
@
IInstantiationService
private
readonly
_instantiationService
:
IInstantiationService
,
@
IClipboardService
private
readonly
_clipboardService
:
IClipboardService
,
@
IHistoryService
private
readonly
_historyService
:
IHistoryService
,
@
IThemeService
private
readonly
_themeService
:
IThemeService
,
@
IConfigurationResolverService
private
readonly
_configurationResolverService
:
IConfigurationResolverService
,
@
IWorkspaceContextService
private
readonly
_workspaceContextService
:
IWorkspaceContextService
,
@
IConfigurationService
private
readonly
_configurationService
:
IConfigurationService
,
@
ILogService
private
_logService
:
ILogService
)
{
...
...
@@ -315,7 +304,7 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_xterm
.
on
(
'
linefeed
'
,
()
=>
this
.
_onLineFeed
());
this
.
_processManager
.
process
.
on
(
'
message
'
,
(
message
)
=>
this
.
_sendPtyDataToXterm
(
message
));
this
.
_xterm
.
on
(
'
data
'
,
data
=>
this
.
_processManager
.
write
(
data
));
this
.
_linkHandler
=
this
.
_instantiationService
.
createInstance
(
TerminalLinkHandler
,
this
.
_xterm
,
platform
.
platform
,
this
.
_initialCwd
);
this
.
_linkHandler
=
this
.
_instantiationService
.
createInstance
(
TerminalLinkHandler
,
this
.
_xterm
,
platform
.
platform
,
this
.
_
processManager
.
initialCwd
);
this
.
_commandTracker
=
new
TerminalCommandTracker
(
this
.
_xterm
);
this
.
_instanceDisposables
.
push
(
this
.
_themeService
.
onThemeChange
(
theme
=>
this
.
_updateTheme
(
theme
)));
}
...
...
@@ -636,67 +625,39 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_terminalHasTextContextKey
.
set
(
isActive
&&
this
.
hasSelection
());
}
protected
_getCwd
(
shell
:
IShellLaunchConfig
,
root
:
Uri
):
string
{
if
(
shell
.
cwd
)
{
return
shell
.
cwd
;
}
let
cwd
:
string
;
// TODO: Handle non-existent customCwd
if
(
!
shell
.
ignoreConfigurationCwd
)
{
// Evaluate custom cwd first
const
customCwd
=
this
.
_configHelper
.
config
.
cwd
;
if
(
customCwd
)
{
if
(
path
.
isAbsolute
(
customCwd
))
{
cwd
=
customCwd
;
}
else
if
(
root
)
{
cwd
=
path
.
normalize
(
path
.
join
(
root
.
fsPath
,
customCwd
));
}
}
}
// If there was no custom cwd or it was relative with no workspace
if
(
!
cwd
)
{
cwd
=
root
?
root
.
fsPath
:
os
.
homedir
();
}
return
TerminalInstance
.
_sanitizeCwd
(
cwd
);
}
protected
_createProcess
():
void
{
// TODO: This should be injected in to the terminal instance (from service?)
this
.
_processManager
=
this
.
_instantiationService
.
createInstance
(
TerminalProcessManager
);
this
.
_processManager
=
this
.
_instantiationService
.
createInstance
(
TerminalProcessManager
,
this
.
_configHelper
,
this
.
_cols
,
this
.
_rows
);
this
.
_processManager
.
onShellProcessIdReady
(()
=>
this
.
_onProcessIdReady
.
fire
(
this
));
this
.
_processManager
.
createProcess
(
this
.
_shellLaunchConfig
);
const
locale
=
this
.
_configHelper
.
config
.
setLocaleVariables
?
platform
.
locale
:
undefined
;
if
(
!
this
.
_shellLaunchConfig
.
executable
)
{
this
.
_configHelper
.
mergeDefaultShellPathAndArgs
(
this
.
_shellLaunchConfig
);
}
const
lastActiveWorkspaceRootUri
=
this
.
_historyService
.
getLastActiveWorkspaceRoot
(
'
file
'
);
this
.
_initialCwd
=
this
.
_getCwd
(
this
.
_shellLaunchConfig
,
lastActiveWorkspaceRootUri
);
// Resolve env vars from config and shell
const
lastActiveWorkspaceRoot
=
this
.
_workspaceContextService
.
getWorkspaceFolder
(
lastActiveWorkspaceRootUri
);
const
platformKey
=
platform
.
isWindows
?
'
windows
'
:
(
platform
.
isMacintosh
?
'
osx
'
:
'
linux
'
);
const
envFromConfig
=
TerminalInstance
.
resolveConfigurationVariables
(
this
.
_configurationResolverService
,
{
...
this
.
_configHelper
.
config
.
env
[
platformKey
]
},
lastActiveWorkspaceRoot
);
const
envFromShell
=
TerminalInstance
.
resolveConfigurationVariables
(
this
.
_configurationResolverService
,
{
...
this
.
_shellLaunchConfig
.
env
},
lastActiveWorkspaceRoot
);
this
.
_shellLaunchConfig
.
env
=
envFromShell
;
// Merge process env with the env from config
const
parentEnv
=
{
...
process
.
env
};
TerminalInstance
.
mergeEnvironments
(
parentEnv
,
envFromConfig
);
// Continue env initialization, merging in the env from the launch
// config and adding keys that are needed to create the process
const
env
=
TerminalInstance
.
createTerminalEnv
(
parentEnv
,
this
.
_shellLaunchConfig
,
this
.
_initialCwd
,
locale
,
this
.
_cols
,
this
.
_rows
);
const
cwd
=
Uri
.
parse
(
path
.
dirname
(
require
.
toUrl
(
'
../node/terminalProcess
'
))).
fsPath
;
const
options
=
{
env
,
cwd
};
this
.
_logService
.
debug
(
`Terminal process launching (id:
${
this
.
id
}
)`
,
options
);
this
.
_processManager
.
process
=
cp
.
fork
(
Uri
.
parse
(
require
.
toUrl
(
'
bootstrap
'
)).
fsPath
,
[
'
--type=terminal
'
],
options
);
this
.
_processManager
.
processState
=
ProcessState
.
LAUNCHING
;
//
const locale = this._configHelper.config.setLocaleVariables ? platform.locale : undefined;
//
if (!this._shellLaunchConfig.executable) {
//
this._configHelper.mergeDefaultShellPathAndArgs(this._shellLaunchConfig);
//
}
//
const lastActiveWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot('file');
//
this._initialCwd = this._getCwd(this._shellLaunchConfig, lastActiveWorkspaceRootUri);
//
//
Resolve env vars from config and shell
//
const lastActiveWorkspaceRoot = this._workspaceContextService.getWorkspaceFolder(lastActiveWorkspaceRootUri);
//
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
//
const envFromConfig = TerminalInstance.resolveConfigurationVariables(this._configurationResolverService, { ...this._configHelper.config.env[platformKey] }, lastActiveWorkspaceRoot);
//
const envFromShell = TerminalInstance.resolveConfigurationVariables(this._configurationResolverService, { ...this._shellLaunchConfig.env }, lastActiveWorkspaceRoot);
//
this._shellLaunchConfig.env = envFromShell;
//
//
Merge process env with the env from config
//
const parentEnv = { ...process.env };
//
TerminalInstance.mergeEnvironments(parentEnv, envFromConfig);
//
//
Continue env initialization, merging in the env from the launch
//
//
config and adding keys that are needed to create the process
//
const env = TerminalInstance.createTerminalEnv(parentEnv, this._shellLaunchConfig, this._initialCwd, locale, this._cols, this._rows);
//
const cwd = Uri.parse(path.dirname(require.toUrl('../node/terminalProcess'))).fsPath;
//
const options = { env, cwd };
//
this._logService.debug(`Terminal process launching (id: ${this.id})`, options);
//
this._processManager.process = cp.fork(Uri.parse(require.toUrl('bootstrap')).fsPath, ['--type=terminal'], options);
//
this._processManager.processState = ProcessState.LAUNCHING;
if
(
this
.
_shellLaunchConfig
.
name
)
{
this
.
setTitle
(
this
.
_shellLaunchConfig
.
name
,
false
);
...
...
@@ -722,16 +683,6 @@ export class TerminalInstance implements ITerminalInstance {
},
LAUNCHING_DURATION
);
}
// TODO: Should be protected
private
static
resolveConfigurationVariables
(
configurationResolverService
:
IConfigurationResolverService
,
env
:
IStringDictionary
<
string
>
,
lastActiveWorkspaceRoot
:
IWorkspaceFolder
):
IStringDictionary
<
string
>
{
Object
.
keys
(
env
).
forEach
((
key
)
=>
{
if
(
typeof
env
[
key
]
===
'
string
'
)
{
env
[
key
]
=
configurationResolverService
.
resolve
(
lastActiveWorkspaceRoot
,
env
[
key
]);
}
});
return
env
;
}
private
_sendPtyDataToXterm
(
message
:
{
type
:
string
,
content
:
string
}):
void
{
this
.
_logService
.
debug
(
`Terminal process message (id:
${
this
.
id
}
)`
,
message
);
if
(
message
.
type
===
'
data
'
)
{
...
...
@@ -868,69 +819,6 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_shellLaunchConfig
=
shell
;
}
public
static
mergeEnvironments
(
parent
:
IStringDictionary
<
string
>
,
other
:
IStringDictionary
<
string
>
)
{
if
(
!
other
)
{
return
;
}
// On Windows apply the new values ignoring case, while still retaining
// the case of the original key.
if
(
platform
.
isWindows
)
{
for
(
let
configKey
in
other
)
{
let
actualKey
=
configKey
;
for
(
let
envKey
in
parent
)
{
if
(
configKey
.
toLowerCase
()
===
envKey
.
toLowerCase
())
{
actualKey
=
envKey
;
break
;
}
}
const
value
=
other
[
configKey
];
TerminalInstance
.
_mergeEnvironmentValue
(
parent
,
actualKey
,
value
);
}
}
else
{
Object
.
keys
(
other
).
forEach
((
key
)
=>
{
const
value
=
other
[
key
];
TerminalInstance
.
_mergeEnvironmentValue
(
parent
,
key
,
value
);
});
}
}
private
static
_mergeEnvironmentValue
(
env
:
IStringDictionary
<
string
>
,
key
:
string
,
value
:
string
|
null
)
{
if
(
typeof
value
===
'
string
'
)
{
env
[
key
]
=
value
;
}
else
{
delete
env
[
key
];
}
}
// TODO: This should be private/protected
public
static
createTerminalEnv
(
parentEnv
:
IStringDictionary
<
string
>
,
shell
:
IShellLaunchConfig
,
cwd
:
string
,
locale
:
string
,
cols
?:
number
,
rows
?:
number
):
IStringDictionary
<
string
>
{
const
env
=
{
...
parentEnv
};
if
(
shell
.
env
)
{
TerminalInstance
.
mergeEnvironments
(
env
,
shell
.
env
);
}
env
[
'
PTYPID
'
]
=
process
.
pid
.
toString
();
env
[
'
PTYSHELL
'
]
=
shell
.
executable
;
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
'
]
=
TerminalInstance
.
_getLangEnvVariable
(
locale
);
if
(
cols
&&
rows
)
{
env
[
'
PTYCOLS
'
]
=
cols
.
toString
();
env
[
'
PTYROWS
'
]
=
rows
.
toString
();
}
env
[
'
AMD_ENTRYPOINT
'
]
=
'
vs/workbench/parts/terminal/node/terminalProcess
'
;
return
env
;
}
public
onLineData
(
listener
:
(
lineData
:
string
)
=>
void
):
lifecycle
.
IDisposable
{
this
.
_onLineDataListeners
.
push
(
listener
);
return
{
...
...
@@ -981,47 +869,6 @@ export class TerminalInstance implements ITerminalInstance {
};
}
private
static
_sanitizeCwd
(
cwd
:
string
)
{
// Make the drive letter uppercase on Windows (see #9448)
if
(
platform
.
platform
===
platform
.
Platform
.
Windows
&&
cwd
&&
cwd
[
1
]
===
'
:
'
)
{
return
cwd
[
0
].
toUpperCase
()
+
cwd
.
substr
(
1
);
}
return
cwd
;
}
private
static
_getLangEnvVariable
(
locale
?:
string
)
{
const
parts
=
locale
?
locale
.
split
(
'
-
'
)
:
[];
const
n
=
parts
.
length
;
if
(
n
===
0
)
{
// Fallback to en_US to prevent possible encoding issues.
return
'
en_US.UTF-8
'
;
}
if
(
n
===
1
)
{
// app.getLocale can return just a language without a variant, fill in the variant for
// supported languages as many shells expect a 2-part locale.
const
languageVariants
=
{
de
:
'
DE
'
,
en
:
'
US
'
,
es
:
'
ES
'
,
fi
:
'
FI
'
,
fr
:
'
FR
'
,
it
:
'
IT
'
,
ja
:
'
JP
'
,
ko
:
'
KR
'
,
pl
:
'
PL
'
,
ru
:
'
RU
'
,
zh
:
'
CN
'
};
if
(
parts
[
0
]
in
languageVariants
)
{
parts
.
push
(
languageVariants
[
parts
[
0
]]);
}
}
else
{
// Ensure the variant is uppercase
parts
[
1
]
=
parts
[
1
].
toUpperCase
();
}
return
parts
.
join
(
'
_
'
)
+
'
.UTF-8
'
;
}
public
updateConfig
():
void
{
this
.
_setCursorBlink
(
this
.
_configHelper
.
config
.
cursorBlinking
);
this
.
_setCursorStyle
(
this
.
_configHelper
.
config
.
cursorStyle
);
...
...
@@ -1156,7 +1003,7 @@ export class TerminalInstance implements ITerminalInstance {
return
;
}
if
(
eventFromProcess
)
{
title
=
path
.
basename
(
title
);
title
=
path
s
.
basename
(
title
);
if
(
platform
.
isWindows
)
{
// Remove the .exe extension
title
=
title
.
split
(
'
.exe
'
)[
0
];
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts
浏览文件 @
394b7ece
...
...
@@ -3,12 +3,21 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
ChildProcess
}
from
'
child_process
'
;
import
*
as
cp
from
'
child_process
'
;
import
*
as
os
from
'
os
'
;
import
*
as
path
from
'
path
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
Uri
from
'
vs/base/common/uri
'
;
import
pkg
from
'
vs/platform/node/package
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
ProcessState
,
ITerminalProcessManager
,
ITerminalProcessMessage
,
IShellLaunchConfig
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
ProcessState
,
ITerminalProcessManager
,
ITerminalProcessMessage
,
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
{
IStringDictionary
}
from
'
vs/base/common/collections
'
;
import
{
IConfigurationResolverService
}
from
'
vs/workbench/services/configurationResolver/common/configurationResolver
'
;
import
{
IWorkspaceFolder
,
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
IHistoryService
}
from
'
vs/workbench/services/history/common/history
'
;
/**
* Holds all state related to the creation and management of terminal processes.
...
...
@@ -21,9 +30,10 @@ import { Emitter, Event } from 'vs/base/common/event';
export
class
TerminalProcessManager
implements
ITerminalProcessManager
{
public
processState
:
ProcessState
=
ProcessState
.
UNINITIALIZED
;
// _process
public
process
:
ChildProcess
;
public
process
:
cp
.
ChildProcess
;
public
ptyProcessReady
:
TPromise
<
void
>
;
public
shellProcessId
:
number
;
public
initialCwd
:
string
;
private
_preLaunchInputQueue
:
string
[]
=
[];
private
_disposables
:
IDisposable
[]
=
[];
...
...
@@ -32,6 +42,12 @@ export class TerminalProcessManager implements ITerminalProcessManager {
public
get
onShellProcessIdReady
():
Event
<
number
>
{
return
this
.
_onShellProcessIdReady
.
event
;
}
constructor
(
private
_configHelper
:
ITerminalConfigHelper
,
private
_cols
:
number
,
private
_rows
:
number
,
@
IWorkspaceContextService
private
readonly
_workspaceContextService
:
IWorkspaceContextService
,
@
IHistoryService
private
readonly
_historyService
:
IHistoryService
,
@
IConfigurationResolverService
private
readonly
_configurationResolverService
:
IConfigurationResolverService
,
@
ILogService
private
_logService
:
ILogService
)
{
}
...
...
@@ -45,13 +61,69 @@ export class TerminalProcessManager implements ITerminalProcessManager {
this
.
_disposables
.
push
(
disposable
);
}
public
createProcess
(
l
aunchConfig
:
IShellLaunchConfig
):
void
{
public
createProcess
(
shellL
aunchConfig
:
IShellLaunchConfig
):
void
{
this
.
ptyProcessReady
=
new
TPromise
<
void
>
(
c
=>
{
this
.
onShellProcessIdReady
(()
=>
{
this
.
_logService
.
debug
(
`Terminal process ready (shellProcessId:
${
this
.
shellProcessId
}
)`
);
c
(
void
0
);
});
});
const
locale
=
this
.
_configHelper
.
config
.
setLocaleVariables
?
platform
.
locale
:
undefined
;
if
(
!
shellLaunchConfig
.
executable
)
{
this
.
_configHelper
.
mergeDefaultShellPathAndArgs
(
shellLaunchConfig
);
}
const
lastActiveWorkspaceRootUri
=
this
.
_historyService
.
getLastActiveWorkspaceRoot
(
'
file
'
);
this
.
initialCwd
=
this
.
_getCwd
(
shellLaunchConfig
,
lastActiveWorkspaceRootUri
);
// Resolve env vars from config and shell
const
lastActiveWorkspaceRoot
=
this
.
_workspaceContextService
.
getWorkspaceFolder
(
lastActiveWorkspaceRootUri
);
const
platformKey
=
platform
.
isWindows
?
'
windows
'
:
(
platform
.
isMacintosh
?
'
osx
'
:
'
linux
'
);
const
envFromConfig
=
TerminalProcessManager
.
resolveConfigurationVariables
(
this
.
_configurationResolverService
,
{
...
this
.
_configHelper
.
config
.
env
[
platformKey
]
},
lastActiveWorkspaceRoot
);
const
envFromShell
=
TerminalProcessManager
.
resolveConfigurationVariables
(
this
.
_configurationResolverService
,
{
...
shellLaunchConfig
.
env
},
lastActiveWorkspaceRoot
);
shellLaunchConfig
.
env
=
envFromShell
;
// Merge process env with the env from config
const
parentEnv
=
{
...
process
.
env
};
TerminalProcessManager
.
mergeEnvironments
(
parentEnv
,
envFromConfig
);
// Continue env initialization, merging in the env from the launch
// config and adding keys that are needed to create the process
const
env
=
TerminalProcessManager
.
createTerminalEnv
(
parentEnv
,
shellLaunchConfig
,
this
.
initialCwd
,
locale
,
this
.
_cols
,
this
.
_rows
);
const
cwd
=
Uri
.
parse
(
path
.
dirname
(
require
.
toUrl
(
'
../node/terminalProcess
'
))).
fsPath
;
const
options
=
{
env
,
cwd
};
this
.
_logService
.
debug
(
`Terminal process launching`
,
options
);
this
.
process
=
cp
.
fork
(
Uri
.
parse
(
require
.
toUrl
(
'
bootstrap
'
)).
fsPath
,
[
'
--type=terminal
'
],
options
);
this
.
processState
=
ProcessState
.
LAUNCHING
;
}
protected
_getCwd
(
shell
:
IShellLaunchConfig
,
root
:
Uri
):
string
{
if
(
shell
.
cwd
)
{
return
shell
.
cwd
;
}
let
cwd
:
string
;
// TODO: Handle non-existent customCwd
if
(
!
shell
.
ignoreConfigurationCwd
)
{
// Evaluate custom cwd first
const
customCwd
=
this
.
_configHelper
.
config
.
cwd
;
if
(
customCwd
)
{
if
(
path
.
isAbsolute
(
customCwd
))
{
cwd
=
customCwd
;
}
else
if
(
root
)
{
cwd
=
path
.
normalize
(
path
.
join
(
root
.
fsPath
,
customCwd
));
}
}
}
// If there was no custom cwd or it was relative with no workspace
if
(
!
cwd
)
{
cwd
=
root
?
root
.
fsPath
:
os
.
homedir
();
}
return
TerminalProcessManager
.
_sanitizeCwd
(
cwd
);
}
public
write
(
data
:
string
):
void
{
...
...
@@ -83,6 +155,120 @@ export class TerminalProcessManager implements ITerminalProcessManager {
}
}
public
static
mergeEnvironments
(
parent
:
IStringDictionary
<
string
>
,
other
:
IStringDictionary
<
string
>
)
{
if
(
!
other
)
{
return
;
}
// On Windows apply the new values ignoring case, while still retaining
// the case of the original key.
if
(
platform
.
isWindows
)
{
for
(
let
configKey
in
other
)
{
let
actualKey
=
configKey
;
for
(
let
envKey
in
parent
)
{
if
(
configKey
.
toLowerCase
()
===
envKey
.
toLowerCase
())
{
actualKey
=
envKey
;
break
;
}
}
const
value
=
other
[
configKey
];
TerminalProcessManager
.
_mergeEnvironmentValue
(
parent
,
actualKey
,
value
);
}
}
else
{
Object
.
keys
(
other
).
forEach
((
key
)
=>
{
const
value
=
other
[
key
];
TerminalProcessManager
.
_mergeEnvironmentValue
(
parent
,
key
,
value
);
});
}
}
private
static
_mergeEnvironmentValue
(
env
:
IStringDictionary
<
string
>
,
key
:
string
,
value
:
string
|
null
)
{
if
(
typeof
value
===
'
string
'
)
{
env
[
key
]
=
value
;
}
else
{
delete
env
[
key
];
}
}
// TODO: This should be private/protected
public
static
createTerminalEnv
(
parentEnv
:
IStringDictionary
<
string
>
,
shell
:
IShellLaunchConfig
,
cwd
:
string
,
locale
:
string
,
cols
?:
number
,
rows
?:
number
):
IStringDictionary
<
string
>
{
const
env
=
{
...
parentEnv
};
if
(
shell
.
env
)
{
TerminalProcessManager
.
mergeEnvironments
(
env
,
shell
.
env
);
}
env
[
'
PTYPID
'
]
=
process
.
pid
.
toString
();
env
[
'
PTYSHELL
'
]
=
shell
.
executable
;
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
'
]
=
TerminalProcessManager
.
_getLangEnvVariable
(
locale
);
if
(
cols
&&
rows
)
{
env
[
'
PTYCOLS
'
]
=
cols
.
toString
();
env
[
'
PTYROWS
'
]
=
rows
.
toString
();
}
env
[
'
AMD_ENTRYPOINT
'
]
=
'
vs/workbench/parts/terminal/node/terminalProcess
'
;
return
env
;
}
// TODO:should be protected/non-static
private
static
resolveConfigurationVariables
(
configurationResolverService
:
IConfigurationResolverService
,
env
:
IStringDictionary
<
string
>
,
lastActiveWorkspaceRoot
:
IWorkspaceFolder
):
IStringDictionary
<
string
>
{
Object
.
keys
(
env
).
forEach
((
key
)
=>
{
if
(
typeof
env
[
key
]
===
'
string
'
)
{
env
[
key
]
=
configurationResolverService
.
resolve
(
lastActiveWorkspaceRoot
,
env
[
key
]);
}
});
return
env
;
}
private
static
_sanitizeCwd
(
cwd
:
string
)
{
// Make the drive letter uppercase on Windows (see #9448)
if
(
platform
.
platform
===
platform
.
Platform
.
Windows
&&
cwd
&&
cwd
[
1
]
===
'
:
'
)
{
return
cwd
[
0
].
toUpperCase
()
+
cwd
.
substr
(
1
);
}
return
cwd
;
}
private
static
_getLangEnvVariable
(
locale
?:
string
)
{
const
parts
=
locale
?
locale
.
split
(
'
-
'
)
:
[];
const
n
=
parts
.
length
;
if
(
n
===
0
)
{
// Fallback to en_US to prevent possible encoding issues.
return
'
en_US.UTF-8
'
;
}
if
(
n
===
1
)
{
// app.getLocale can return just a language without a variant, fill in the variant for
// supported languages as many shells expect a 2-part locale.
const
languageVariants
=
{
de
:
'
DE
'
,
en
:
'
US
'
,
es
:
'
ES
'
,
fi
:
'
FI
'
,
fr
:
'
FR
'
,
it
:
'
IT
'
,
ja
:
'
JP
'
,
ko
:
'
KR
'
,
pl
:
'
PL
'
,
ru
:
'
RU
'
,
zh
:
'
CN
'
};
if
(
parts
[
0
]
in
languageVariants
)
{
parts
.
push
(
languageVariants
[
parts
[
0
]]);
}
}
else
{
// Ensure the variant is uppercase
parts
[
1
]
=
parts
[
1
].
toUpperCase
();
}
return
parts
.
join
(
'
_
'
)
+
'
.UTF-8
'
;
}
// Should this be here or in instance?
// private _isExiting: boolean;
...
...
src/vs/workbench/parts/terminal/test/electron-browser/terminalInstance.test.ts
浏览文件 @
394b7ece
...
...
@@ -3,213 +3,213 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
*
as
os
from
'
os
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
Uri
from
'
vs/base/common/uri
'
;
import
{
IStringDictionary
}
from
'
vs/base/common/collections
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
TerminalInstance
}
from
'
vs/workbench/parts/terminal/electron-browser/terminalInstance
'
;
import
{
IShellLaunchConfig
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
TestInstantiationService
}
from
'
vs/platform/instantiation/test/common/instantiationServiceMock
'
;
import
{
TestNotificationService
,
TestContextService
,
TestHistoryService
}
from
'
vs/workbench/test/workbenchTestServices
'
;
import
{
MockContextKeyService
,
MockKeybindingService
}
from
'
vs/platform/keybinding/test/common/mockKeybindingService
'
;
import
{
IKeybindingService
}
from
'
vs/platform/keybinding/common/keybinding
'
;
import
{
IContextKeyService
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
IHistoryService
}
from
'
vs/workbench/services/history/common/history
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
TestConfigurationService
}
from
'
vs/platform/configuration/test/common/testConfigurationService
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
INotificationService
}
from
'
vs/platform/notification/common/notification
'
;
import
{
ILogService
,
NullLogService
}
from
'
vs/platform/log/common/log
'
;
class
TestTerminalInstance
extends
TerminalInstance
{
public
_getCwd
(
shell
:
IShellLaunchConfig
,
root
:
Uri
):
string
{
return
super
.
_getCwd
(
shell
,
root
);
}
protected
_createProcess
():
void
{
}
protected
_createXterm
():
TPromise
<
void
>
{
return
TPromise
.
as
(
void
0
);
}
}
suite
(
'
Workbench - TerminalInstance
'
,
()
=>
{
let
instantiationService
:
TestInstantiationService
;
setup
(()
=>
{
instantiationService
=
new
TestInstantiationService
();
instantiationService
.
stub
(
INotificationService
,
new
TestNotificationService
());
instantiationService
.
stub
(
IHistoryService
,
new
TestHistoryService
());
});
test
(
'
createTerminalEnv
'
,
function
()
{
const
shell1
=
{
executable
:
'
/bin/foosh
'
,
args
:
[
'
-bar
'
,
'
baz
'
]
};
const
parentEnv1
:
IStringDictionary
<
string
>
=
{
ok
:
true
}
as
any
;
const
env1
=
TerminalInstance
.
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
=
TerminalInstance
.
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
=
TerminalInstance
.
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
=
TerminalInstance
.
createTerminalEnv
(
parentEnv2
,
shell1
,
'
/
'
,
null
);
assert
.
equal
(
env4
[
'
LANG
'
],
'
en_US.UTF-8
'
,
'
LANG is equal to the parent environment
\'
s LANG
'
);
});
suite
(
'
mergeEnvironments
'
,
()
=>
{
test
(
'
should add keys
'
,
()
=>
{
const
parent
=
{
a
:
'
b
'
};
const
other
=
{
c
:
'
d
'
};
TerminalInstance
.
mergeEnvironments
(
parent
,
other
);
assert
.
deepEqual
(
parent
,
{
a
:
'
b
'
,
c
:
'
d
'
});
});
test
(
'
should add keys ignoring case on Windows
'
,
()
=>
{
if
(
!
platform
.
isWindows
)
{
return
;
}
const
parent
=
{
a
:
'
b
'
};
const
other
=
{
A
:
'
c
'
};
TerminalInstance
.
mergeEnvironments
(
parent
,
other
);
assert
.
deepEqual
(
parent
,
{
a
:
'
c
'
});
});
test
(
'
null values should delete keys from the parent env
'
,
()
=>
{
const
parent
=
{
a
:
'
b
'
,
c
:
'
d
'
};
const
other
:
IStringDictionary
<
string
>
=
{
a
:
null
};
TerminalInstance
.
mergeEnvironments
(
parent
,
other
);
assert
.
deepEqual
(
parent
,
{
c
:
'
d
'
});
});
test
(
'
null values should delete keys from the parent env ignoring case on Windows
'
,
()
=>
{
if
(
!
platform
.
isWindows
)
{
return
;
}
const
parent
=
{
a
:
'
b
'
,
c
:
'
d
'
};
const
other
:
IStringDictionary
<
string
>
=
{
A
:
null
};
TerminalInstance
.
mergeEnvironments
(
parent
,
other
);
assert
.
deepEqual
(
parent
,
{
c
:
'
d
'
});
});
});
suite
(
'
_getCwd
'
,
()
=>
{
let
instance
:
TestTerminalInstance
;
let
instantiationService
:
TestInstantiationService
;
let
configHelper
:
{
config
:
{
cwd
:
string
}
};
setup
(()
=>
{
let
contextKeyService
=
new
MockContextKeyService
();
let
keybindingService
=
new
MockKeybindingService
();
let
terminalFocusContextKey
=
contextKeyService
.
createKey
(
'
test
'
,
false
);
instantiationService
=
new
TestInstantiationService
();
instantiationService
.
stub
(
IConfigurationService
,
new
TestConfigurationService
());
instantiationService
.
stub
(
INotificationService
,
new
TestNotificationService
());
instantiationService
.
stub
(
IWorkspaceContextService
,
new
TestContextService
());
instantiationService
.
stub
(
IKeybindingService
,
keybindingService
);
instantiationService
.
stub
(
IContextKeyService
,
contextKeyService
);
instantiationService
.
stub
(
IHistoryService
,
new
TestHistoryService
());
instantiationService
.
stub
(
ILogService
,
new
NullLogService
());
configHelper
=
{
config
:
{
cwd
:
null
}
};
instance
=
instantiationService
.
createInstance
(
TestTerminalInstance
,
terminalFocusContextKey
,
configHelper
,
null
,
null
);
});
// This helper checks the paths in a cross-platform friendly manner
function
assertPathsMatch
(
a
:
string
,
b
:
string
):
void
{
assert
.
equal
(
Uri
.
file
(
a
).
fsPath
,
Uri
.
file
(
b
).
fsPath
);
}
test
(
'
should default to os.homedir() for an empty workspace
'
,
()
=>
{
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
null
),
os
.
homedir
());
});
test
(
'
should use to the workspace if it exists
'
,
()
=>
{
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
Uri
.
file
(
'
/foo
'
)),
'
/foo
'
);
});
test
(
'
should use an absolute custom cwd as is
'
,
()
=>
{
configHelper
.
config
.
cwd
=
'
/foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
null
),
'
/foo
'
);
});
test
(
'
should normalize a relative custom cwd against the workspace path
'
,
()
=>
{
configHelper
.
config
.
cwd
=
'
foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
Uri
.
file
(
'
/bar
'
)),
'
/bar/foo
'
);
configHelper
.
config
.
cwd
=
'
./foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
Uri
.
file
(
'
/bar
'
)),
'
/bar/foo
'
);
configHelper
.
config
.
cwd
=
'
../foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
Uri
.
file
(
'
/bar
'
),
),
'
/foo
'
);
});
test
(
'
should fall back for relative a custom cwd that doesn
\'
t have a workspace
'
,
()
=>
{
configHelper
.
config
.
cwd
=
'
foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
null
),
os
.
homedir
());
configHelper
.
config
.
cwd
=
'
./foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
null
),
os
.
homedir
());
configHelper
.
config
.
cwd
=
'
../foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[]
},
null
),
os
.
homedir
());
});
test
(
'
should ignore custom cwd when told to ignore
'
,
()
=>
{
configHelper
.
config
.
cwd
=
'
/foo
'
;
assertPathsMatch
(
instance
.
_getCwd
({
executable
:
null
,
args
:
[],
ignoreConfigurationCwd
:
true
},
Uri
.
file
(
'
/bar
'
)),
'
/bar
'
);
});
});
});
\ No newline at end of file
// 'use strict';
// import * as assert from 'assert';
// import * as os from 'os';
// import * as platform from 'vs/base/common/platform';
// import Uri from 'vs/base/common/uri';
// import { IStringDictionary } from 'vs/base/common/collections';
// import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
// import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance';
// import { IShellLaunchConfig } from 'vs/workbench/parts/terminal/common/terminal';
// import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
// import { TestNotificationService, TestContextService, TestHistoryService } from 'vs/workbench/test/workbenchTestServices';
// import { MockContextKeyService, MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
// import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
// import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
// import { IHistoryService } from 'vs/workbench/services/history/common/history';
// import { TPromise } from 'vs/base/common/winjs.base';
// import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
// import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
// import { INotificationService } from 'vs/platform/notification/common/notification';
// import { ILogService, NullLogService } from 'vs/platform/log/common/log';
// class TestTerminalInstance extends TerminalInstance {
// public _getCwd(shell: IShellLaunchConfig, root: Uri): string {
// return super._getCwd(shell, root);
// }
// protected _createProcess(): void { }
// protected _createXterm(): TPromise<void> { return TPromise.as(void 0); }
// }
// suite('Workbench - TerminalInstance', () => {
// let instantiationService: TestInstantiationService;
// setup(() => {
// instantiationService = new TestInstantiationService();
// instantiationService.stub(INotificationService, new TestNotificationService());
// instantiationService.stub(IHistoryService, new TestHistoryService());
// });
// test('createTerminalEnv', function () {
// const shell1 = {
// executable: '/bin/foosh',
// args: ['-bar', 'baz']
// };
// const parentEnv1: IStringDictionary<string> = {
// ok: true
// } as any;
// const env1 = TerminalInstance.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 = TerminalInstance.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 = TerminalInstance.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 = TerminalInstance.createTerminalEnv(parentEnv2, shell1, '/', null);
// assert.equal(env4['LANG'], 'en_US.UTF-8', 'LANG is equal to the parent environment\'s LANG');
// });
// suite('mergeEnvironments', () => {
// test('should add keys', () => {
// const parent = {
// a: 'b'
// };
// const other = {
// c: 'd'
// };
// TerminalInstance.mergeEnvironments(parent, other);
// assert.deepEqual(parent, {
// a: 'b',
// c: 'd'
// });
// });
// test('should add keys ignoring case on Windows', () => {
// if (!platform.isWindows) {
// return;
// }
// const parent = {
// a: 'b'
// };
// const other = {
// A: 'c'
// };
// TerminalInstance.mergeEnvironments(parent, other);
// assert.deepEqual(parent, {
// a: 'c'
// });
// });
// test('null values should delete keys from the parent env', () => {
// const parent = {
// a: 'b',
// c: 'd'
// };
// const other: IStringDictionary<string> = {
// a: null
// };
// TerminalInstance.mergeEnvironments(parent, other);
// assert.deepEqual(parent, {
// c: 'd'
// });
// });
// test('null values should delete keys from the parent env ignoring case on Windows', () => {
// if (!platform.isWindows) {
// return;
// }
// const parent = {
// a: 'b',
// c: 'd'
// };
// const other: IStringDictionary<string> = {
// A: null
// };
// TerminalInstance.mergeEnvironments(parent, other);
// assert.deepEqual(parent, {
// c: 'd'
// });
// });
// });
// suite('_getCwd', () => {
// let instance: TestTerminalInstance;
// let instantiationService: TestInstantiationService;
// let configHelper: { config: { cwd: string } };
// setup(() => {
// let contextKeyService = new MockContextKeyService();
// let keybindingService = new MockKeybindingService();
// let terminalFocusContextKey = contextKeyService.createKey('test', false);
// instantiationService = new TestInstantiationService();
// instantiationService.stub(IConfigurationService, new TestConfigurationService());
// instantiationService.stub(INotificationService, new TestNotificationService());
// instantiationService.stub(IWorkspaceContextService, new TestContextService());
// instantiationService.stub(IKeybindingService, keybindingService);
// instantiationService.stub(IContextKeyService, contextKeyService);
// instantiationService.stub(IHistoryService, new TestHistoryService());
// instantiationService.stub(ILogService, new NullLogService());
// configHelper = {
// config: {
// cwd: null
// }
// };
// instance = instantiationService.createInstance(TestTerminalInstance, terminalFocusContextKey, configHelper, null, null);
// });
// // This helper checks the paths in a cross-platform friendly manner
// function assertPathsMatch(a: string, b: string): void {
// assert.equal(Uri.file(a).fsPath, Uri.file(b).fsPath);
// }
// test('should default to os.homedir() for an empty workspace', () => {
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, null), os.homedir());
// });
// test('should use to the workspace if it exists', () => {
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, Uri.file('/foo')), '/foo');
// });
// test('should use an absolute custom cwd as is', () => {
// configHelper.config.cwd = '/foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, null), '/foo');
// });
// test('should normalize a relative custom cwd against the workspace path', () => {
// configHelper.config.cwd = 'foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, Uri.file('/bar')), '/bar/foo');
// configHelper.config.cwd = './foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, Uri.file('/bar')), '/bar/foo');
// configHelper.config.cwd = '../foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, Uri.file('/bar'), ), '/foo');
// });
// test('should fall back for relative a custom cwd that doesn\'t have a workspace', () => {
// configHelper.config.cwd = 'foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, null), os.homedir());
// configHelper.config.cwd = './foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, null), os.homedir());
// configHelper.config.cwd = '../foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [] }, null), os.homedir());
// });
// test('should ignore custom cwd when told to ignore', () => {
// configHelper.config.cwd = '/foo';
// assertPathsMatch(instance._getCwd({ executable: null, args: [], ignoreConfigurationCwd: true }, Uri.file('/bar')), '/bar');
// });
// });
// });
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录