Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
8a1632a5
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,发现更多精彩内容 >>
未验证
提交
8a1632a5
编写于
2月 11, 2020
作者:
D
Daniel Imms
提交者:
GitHub
2月 11, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #90101 from microsoft/tyriar/75793
Improve promise usage in terminal
上级
39370d9c
2ee023fe
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
328 addition
and
400 deletion
+328
-400
src/vs/workbench/api/browser/mainThreadTerminalService.ts
src/vs/workbench/api/browser/mainThreadTerminalService.ts
+5
-4
src/vs/workbench/api/common/extHost.protocol.ts
src/vs/workbench/api/common/extHost.protocol.ts
+2
-2
src/vs/workbench/api/common/extHostTerminalService.ts
src/vs/workbench/api/common/extHostTerminalService.ts
+4
-4
src/vs/workbench/api/node/extHostTask.ts
src/vs/workbench/api/node/extHostTask.ts
+1
-1
src/vs/workbench/api/node/extHostTerminalService.ts
src/vs/workbench/api/node/extHostTerminalService.ts
+4
-4
src/vs/workbench/contrib/terminal/browser/terminal.ts
src/vs/workbench/contrib/terminal/browser/terminal.ts
+0
-6
src/vs/workbench/contrib/terminal/browser/terminalActions.ts
src/vs/workbench/contrib/terminal/browser/terminalActions.ts
+51
-66
src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts
...orkbench/contrib/terminal/browser/terminalConfigHelper.ts
+3
-4
src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
...vs/workbench/contrib/terminal/browser/terminalInstance.ts
+127
-133
src/vs/workbench/contrib/terminal/browser/terminalService.ts
src/vs/workbench/contrib/terminal/browser/terminalService.ts
+63
-110
src/vs/workbench/contrib/terminal/browser/terminalView.ts
src/vs/workbench/contrib/terminal/browser/terminalView.ts
+2
-3
src/vs/workbench/contrib/terminal/common/terminal.ts
src/vs/workbench/contrib/terminal/common/terminal.ts
+1
-1
src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts
...ontrib/terminal/electron-browser/terminalNativeService.ts
+7
-8
src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts
...h/contrib/terminal/electron-browser/windowsShellHelper.ts
+31
-26
src/vs/workbench/contrib/terminal/node/terminal.ts
src/vs/workbench/contrib/terminal/node/terminal.ts
+10
-11
src/vs/workbench/contrib/terminal/node/terminalProcess.ts
src/vs/workbench/contrib/terminal/node/terminalProcess.ts
+17
-17
未找到文件。
src/vs/workbench/api/browser/mainThreadTerminalService.ts
浏览文件 @
8a1632a5
...
...
@@ -309,15 +309,16 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
return
true
;
}
private
_onRequestAvailableShells
(
request
:
IAvailableShellsRequest
):
void
{
private
async
_onRequestAvailableShells
(
req
:
IAvailableShellsRequest
):
Promise
<
void
>
{
if
(
this
.
_isPrimaryExtHost
())
{
this
.
_proxy
.
$requestAvailableShells
().
then
(
e
=>
request
(
e
));
req
.
callback
(
await
this
.
_proxy
.
$getAvailableShells
(
));
}
}
private
_onRequestDefaultShellAndArgs
(
request
:
IDefaultShellAndArgsRequest
):
void
{
private
async
_onRequestDefaultShellAndArgs
(
req
:
IDefaultShellAndArgsRequest
):
Promise
<
void
>
{
if
(
this
.
_isPrimaryExtHost
())
{
this
.
_proxy
.
$requestDefaultShellAndArgs
(
request
.
useAutomationShell
).
then
(
e
=>
request
.
callback
(
e
.
shell
,
e
.
args
));
const
res
=
await
this
.
_proxy
.
$getDefaultShellAndArgs
(
req
.
useAutomationShell
);
req
.
callback
(
res
.
shell
,
res
.
args
);
}
}
...
...
src/vs/workbench/api/common/extHost.protocol.ts
浏览文件 @
8a1632a5
...
...
@@ -1288,8 +1288,8 @@ export interface ExtHostTerminalServiceShape {
$acceptProcessRequestCwd
(
id
:
number
):
void
;
$acceptProcessRequestLatency
(
id
:
number
):
number
;
$acceptWorkspacePermissionsChanged
(
isAllowed
:
boolean
):
void
;
$
reques
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
;
$
reques
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
;
$
ge
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
;
$
ge
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
;
}
export
interface
ExtHostSCMShape
{
...
...
src/vs/workbench/api/common/extHostTerminalService.ts
浏览文件 @
8a1632a5
...
...
@@ -325,8 +325,8 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
public
abstract
getDefaultShell
(
useAutomationShell
:
boolean
,
configProvider
:
ExtHostConfigProvider
):
string
;
public
abstract
getDefaultShellArgs
(
useAutomationShell
:
boolean
,
configProvider
:
ExtHostConfigProvider
):
string
[]
|
string
;
public
abstract
$spawnExtHostProcess
(
id
:
number
,
shellLaunchConfigDto
:
IShellLaunchConfigDto
,
activeWorkspaceRootUriComponents
:
UriComponents
,
cols
:
number
,
rows
:
number
,
isWorkspaceShellAllowed
:
boolean
):
Promise
<
void
>
;
public
abstract
$
reques
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
;
public
abstract
$
reques
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
;
public
abstract
$
ge
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
;
public
abstract
$
ge
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
;
public
abstract
$acceptWorkspacePermissionsChanged
(
isAllowed
:
boolean
):
void
;
public
createExtensionTerminal
(
options
:
vscode
.
ExtensionTerminalOptions
):
vscode
.
Terminal
{
...
...
@@ -606,11 +606,11 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
throw
new
Error
(
'
Not implemented
'
);
}
public
$
reques
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
{
public
$
ge
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
{
throw
new
Error
(
'
Not implemented
'
);
}
public
async
$
reques
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
{
public
async
$
ge
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
{
throw
new
Error
(
'
Not implemented
'
);
}
...
...
src/vs/workbench/api/node/extHostTask.ts
浏览文件 @
8a1632a5
...
...
@@ -179,7 +179,7 @@ export class ExtHostTask extends ExtHostTaskBase {
}
public
$getDefaultShellAndArgs
():
Promise
<
{
shell
:
string
,
args
:
string
[]
|
string
|
undefined
}
>
{
return
this
.
_terminalService
.
$
reques
tDefaultShellAndArgs
(
true
);
return
this
.
_terminalService
.
$
ge
tDefaultShellAndArgs
(
true
);
}
public
async
$jsonTasksSupported
():
Promise
<
boolean
>
{
...
...
src/vs/workbench/api/node/extHostTerminalService.ts
浏览文件 @
8a1632a5
...
...
@@ -200,16 +200,16 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
this
.
_setupExtHostProcessListeners
(
id
,
new
TerminalProcess
(
shellLaunchConfig
,
initialCwd
,
cols
,
rows
,
env
,
enableConpty
,
this
.
_logService
));
}
public
$
reques
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
{
public
$
ge
tAvailableShells
():
Promise
<
IShellDefinitionDto
[]
>
{
return
detectAvailableShells
();
}
public
async
$
reques
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
{
public
async
$
ge
tDefaultShellAndArgs
(
useAutomationShell
:
boolean
):
Promise
<
IShellAndArgsDto
>
{
const
configProvider
=
await
this
.
_extHostConfiguration
.
getConfigProvider
();
return
Promise
.
resolve
(
{
return
{
shell
:
this
.
getDefaultShell
(
useAutomationShell
,
configProvider
),
args
:
this
.
getDefaultShellArgs
(
useAutomationShell
,
configProvider
)
}
)
;
};
}
public
$acceptWorkspacePermissionsChanged
(
isAllowed
:
boolean
):
void
{
...
...
src/vs/workbench/contrib/terminal/browser/terminal.ts
浏览文件 @
8a1632a5
...
...
@@ -392,12 +392,6 @@ export interface ITerminalInstance {
*/
sendText
(
text
:
string
,
addNewLine
:
boolean
):
void
;
/**
* Write text directly to the terminal, skipping the process if it exists.
* @param text The text to write.
*/
write
(
text
:
string
):
void
;
/** Scroll the terminal buffer down 1 line. */
scrollDownLine
():
void
;
/** Scroll the terminal buffer down 1 page. */
...
...
src/vs/workbench/contrib/terminal/browser/terminalActions.ts
浏览文件 @
8a1632a5
...
...
@@ -38,28 +38,26 @@ import { Action2 } from 'vs/platform/actions/common/actions';
export
const
TERMINAL_PICKER_PREFIX
=
'
term
'
;
function
getCwdForSplit
(
configHelper
:
ITerminalConfigHelper
,
instance
:
ITerminalInstance
,
folders
?:
IWorkspaceFolder
[],
commandService
?:
ICommandService
):
Promise
<
string
|
URI
>
{
async
function
getCwdForSplit
(
configHelper
:
ITerminalConfigHelper
,
instance
:
ITerminalInstance
,
folders
?:
IWorkspaceFolder
[],
commandService
?:
ICommandService
):
Promise
<
string
|
URI
|
undefined
>
{
switch
(
configHelper
.
config
.
splitCwd
)
{
case
'
workspaceRoot
'
:
let
pathPromise
:
Promise
<
string
|
URI
>
=
Promise
.
resolve
(
''
);
if
(
folders
!==
undefined
&&
commandService
!==
undefined
)
{
if
(
folders
.
length
===
1
)
{
pathPromise
=
Promise
.
resolve
(
folders
[
0
].
uri
)
;
return
folders
[
0
].
uri
;
}
else
if
(
folders
.
length
>
1
)
{
// Only choose a path when there's more than 1 folder
const
options
:
IPickOptions
<
IQuickPickItem
>
=
{
placeHolder
:
nls
.
localize
(
'
workbench.action.terminal.newWorkspacePlaceholder
'
,
"
Select current working directory for new terminal
"
)
};
pathPromise
=
commandService
.
executeCommand
(
PICK_WORKSPACE_FOLDER_COMMAND_ID
,
[
options
]).
then
(
workspace
=>
{
if
(
!
workspace
)
{
// Don't split the instance if the workspace picker was canceled
return
undefined
;
}
return
Promise
.
resolve
(
workspace
.
uri
);
});
const
workspace
=
await
commandService
.
executeCommand
(
PICK_WORKSPACE_FOLDER_COMMAND_ID
,
[
options
]);
if
(
!
workspace
)
{
// Don't split the instance if the workspace picker was canceled
return
undefined
;
}
return
Promise
.
resolve
(
workspace
.
uri
);
}
}
return
pathPromise
;
return
''
;
case
'
initial
'
:
return
instance
.
getInitialCwd
();
case
'
inherited
'
:
...
...
@@ -133,12 +131,13 @@ export class QuickKillTerminalAction extends Action {
super
(
id
,
label
,
'
terminal-action kill
'
);
}
public
run
(
event
?:
any
):
Promise
<
any
>
{
public
async
run
(
event
?:
any
):
Promise
<
any
>
{
const
instance
=
this
.
terminalEntry
.
instance
;
if
(
instance
)
{
instance
.
dispose
(
true
);
}
return
Promise
.
resolve
(
timeout
(
50
)).
then
(
result
=>
this
.
quickOpenService
.
show
(
TERMINAL_PICKER_PREFIX
,
undefined
));
await
timeout
(
50
);
return
this
.
quickOpenService
.
show
(
TERMINAL_PICKER_PREFIX
,
undefined
);
}
}
...
...
@@ -329,43 +328,35 @@ export class CreateNewTerminalAction extends Action {
super
(
id
,
label
,
'
terminal-action codicon-add
'
);
}
public
run
(
event
?:
any
):
Promise
<
any
>
{
public
async
run
(
event
?:
any
):
Promise
<
any
>
{
const
folders
=
this
.
workspaceContextService
.
getWorkspace
().
folders
;
if
(
event
instanceof
MouseEvent
&&
(
event
.
altKey
||
event
.
ctrlKey
))
{
const
activeInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
activeInstance
)
{
return
getCwdForSplit
(
this
.
terminalService
.
configHelper
,
activeInstance
).
then
(
cwd
=>
{
this
.
terminalService
.
splitInstance
(
activeInstance
,
{
cwd
});
return
Promise
.
resolve
(
null
);
});
const
cwd
=
await
getCwdForSplit
(
this
.
terminalService
.
configHelper
,
activeInstance
);
this
.
terminalService
.
splitInstance
(
activeInstance
,
{
cwd
});
return
undefined
;
}
}
let
instance
Promise
:
Promise
<
ITerminalInstance
|
null
>
;
let
instance
:
ITerminalInstance
|
undefined
;
if
(
folders
.
length
<=
1
)
{
// Allow terminal service to handle the path when there is only a
// single root
instance
Promise
=
Promise
.
resolve
(
this
.
terminalService
.
createTerminal
(
undefined
)
);
instance
=
this
.
terminalService
.
createTerminal
(
undefined
);
}
else
{
const
options
:
IPickOptions
<
IQuickPickItem
>
=
{
placeHolder
:
nls
.
localize
(
'
workbench.action.terminal.newWorkspacePlaceholder
'
,
"
Select current working directory for new terminal
"
)
};
instancePromise
=
this
.
commandService
.
executeCommand
(
PICK_WORKSPACE_FOLDER_COMMAND_ID
,
[
options
]).
then
(
workspace
=>
{
if
(
!
workspace
)
{
// Don't create the instance if the workspace picker was canceled
return
null
;
}
return
this
.
terminalService
.
createTerminal
({
cwd
:
workspace
.
uri
});
});
}
return
instancePromise
.
then
(
instance
=>
{
if
(
!
instance
)
{
return
Promise
.
resolve
(
undefined
);
const
workspace
=
await
this
.
commandService
.
executeCommand
(
PICK_WORKSPACE_FOLDER_COMMAND_ID
,
[
options
]);
if
(
!
workspace
)
{
// Don't create the instance if the workspace picker was canceled
return
undefined
;
}
this
.
terminalService
.
setActiveInstance
(
instance
);
return
this
.
terminalService
.
showPanel
(
true
);
});
instance
=
this
.
terminalService
.
createTerminal
({
cwd
:
workspace
.
uri
});
}
this
.
terminalService
.
setActiveInstance
(
instance
);
return
this
.
terminalService
.
showPanel
(
true
);
}
}
...
...
@@ -405,19 +396,17 @@ export class SplitTerminalAction extends Action {
super
(
id
,
label
,
'
terminal-action codicon-split-horizontal
'
);
}
public
run
(
event
?:
any
):
Promise
<
any
>
{
public
async
run
(
event
?:
any
):
Promise
<
any
>
{
const
instance
=
this
.
_terminalService
.
getActiveInstance
();
if
(
!
instance
)
{
return
Promise
.
resolve
(
undefined
);
}
return
getCwdForSplit
(
this
.
_terminalService
.
configHelper
,
instance
,
this
.
workspaceContextService
.
getWorkspace
().
folders
,
this
.
commandService
).
then
(
cwd
=>
{
if
(
cwd
||
(
cwd
===
''
))
{
this
.
_terminalService
.
splitInstance
(
instance
,
{
cwd
});
return
this
.
_terminalService
.
showPanel
(
true
);
}
else
{
return
undefined
;
}
});
const
cwd
=
await
getCwdForSplit
(
this
.
_terminalService
.
configHelper
,
instance
,
this
.
workspaceContextService
.
getWorkspace
().
folders
,
this
.
commandService
);
if
(
cwd
===
undefined
)
{
return
undefined
;
}
this
.
_terminalService
.
splitInstance
(
instance
,
{
cwd
});
return
this
.
_terminalService
.
showPanel
(
true
);
}
}
...
...
@@ -432,15 +421,14 @@ export class SplitInActiveWorkspaceTerminalAction extends Action {
super
(
id
,
label
);
}
public
run
(
event
?:
any
):
Promise
<
any
>
{
public
async
run
(
event
?:
any
):
Promise
<
any
>
{
const
instance
=
this
.
_terminalService
.
getActiveInstance
();
if
(
!
instance
)
{
return
Promise
.
resolve
(
undefined
);
}
return
getCwdForSplit
(
this
.
_terminalService
.
configHelper
,
instance
).
then
(
cwd
=>
{
this
.
_terminalService
.
splitInstance
(
instance
,
{
cwd
});
return
this
.
_terminalService
.
showPanel
(
true
);
});
const
cwd
=
await
getCwdForSplit
(
this
.
_terminalService
.
configHelper
,
instance
);
this
.
_terminalService
.
splitInstance
(
instance
,
{
cwd
});
return
this
.
_terminalService
.
showPanel
(
true
);
}
}
...
...
@@ -697,7 +685,7 @@ export class RunActiveFileInTerminalAction extends Action {
super
(
id
,
label
);
}
public
run
(
event
?:
any
):
Promise
<
any
>
{
public
async
run
(
event
?:
any
):
Promise
<
any
>
{
const
instance
=
this
.
terminalService
.
getActiveOrCreateInstance
();
if
(
!
instance
)
{
return
Promise
.
resolve
(
undefined
);
...
...
@@ -712,10 +700,9 @@ export class RunActiveFileInTerminalAction extends Action {
return
Promise
.
resolve
(
undefined
);
}
return
this
.
terminalService
.
preparePathForTerminalAsync
(
uri
.
fsPath
,
instance
.
shellLaunchConfig
.
executable
,
instance
.
title
,
instance
.
shellType
).
then
(
path
=>
{
instance
.
sendText
(
path
,
true
);
return
this
.
terminalService
.
showPanel
();
});
const
path
=
await
this
.
terminalService
.
preparePathForTerminalAsync
(
uri
.
fsPath
,
instance
.
shellLaunchConfig
.
executable
,
instance
.
title
,
instance
.
shellType
);
instance
.
sendText
(
path
,
true
);
return
this
.
terminalService
.
showPanel
();
}
}
...
...
@@ -1040,19 +1027,18 @@ export class RenameTerminalAction extends Action {
super
(
id
,
label
);
}
public
run
(
entry
?:
TerminalEntry
):
Promise
<
any
>
{
public
async
run
(
entry
?:
TerminalEntry
):
Promise
<
any
>
{
const
terminalInstance
=
entry
?
entry
.
instance
:
this
.
terminalService
.
getActiveInstance
();
if
(
!
terminalInstance
)
{
return
Promise
.
resolve
(
undefined
);
}
return
this
.
quickInputService
.
input
({
const
name
=
await
this
.
quickInputService
.
input
({
value
:
terminalInstance
.
title
,
prompt
:
nls
.
localize
(
'
workbench.action.terminal.rename.prompt
'
,
"
Enter terminal name
"
),
}).
then
(
name
=>
{
if
(
name
)
{
terminalInstance
.
setTitle
(
name
,
TitleEventSource
.
Api
);
}
});
if
(
name
)
{
terminalInstance
.
setTitle
(
name
,
TitleEventSource
.
Api
);
}
}
}
export
class
RenameWithArgTerminalAction
extends
Action2
{
...
...
@@ -1168,12 +1154,11 @@ export class RenameTerminalQuickOpenAction extends RenameTerminalAction {
this
.
class
=
'
codicon codicon-gear
'
;
}
public
run
():
Promise
<
any
>
{
super
.
run
(
this
.
terminal
)
// This timeout is needed to make sure the previous quickOpen has time to close before we show the next one
.
then
(()
=>
timeout
(
50
))
.
then
(
result
=>
this
.
quickOpenService
.
show
(
TERMINAL_PICKER_PREFIX
,
undefined
));
return
Promise
.
resolve
(
null
);
public
async
run
():
Promise
<
any
>
{
await
super
.
run
(
this
.
terminal
);
// This timeout is needed to make sure the previous quickOpen has time to close before we show the next one
await
timeout
(
50
);
await
this
.
quickOpenService
.
show
(
TERMINAL_PICKER_PREFIX
,
undefined
);
}
}
...
...
src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts
浏览文件 @
8a1632a5
...
...
@@ -312,9 +312,8 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
}
}
private
isExtensionInstalled
(
id
:
string
):
Promise
<
boolean
>
{
return
this
.
_extensionManagementService
.
getInstalled
(
ExtensionType
.
User
).
then
(
extensions
=>
{
return
extensions
.
some
(
e
=>
e
.
identifier
.
id
===
id
);
});
private
async
isExtensionInstalled
(
id
:
string
):
Promise
<
boolean
>
{
const
extensions
=
await
this
.
_extensionManagementService
.
getInstalled
(
ExtensionType
.
User
);
return
extensions
.
some
(
e
=>
e
.
identifier
.
id
===
id
);
}
}
src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
浏览文件 @
8a1632a5
...
...
@@ -560,136 +560,136 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this
.
_container
.
appendChild
(
this
.
_wrapperElement
);
}
public
_attachToElement
(
container
:
HTMLElement
):
void
{
this
.
_xtermReadyPromise
.
then
(
xterm
=>
{
if
(
this
.
_wrapperElement
)
{
throw
new
Error
(
'
The terminal instance has already been attached to a container
'
);
}
public
async
_attachToElement
(
container
:
HTMLElement
):
Promise
<
void
>
{
const
xterm
=
await
this
.
_xtermReadyPromise
;
this
.
_container
=
container
;
this
.
_wrapperElement
=
document
.
createElement
(
'
div
'
);
dom
.
addClass
(
this
.
_wrapperElement
,
'
terminal-wrapper
'
);
this
.
_xtermElement
=
document
.
createElement
(
'
div
'
);
if
(
this
.
_wrapperElement
)
{
throw
new
Error
(
'
The terminal instance has already been attached to a container
'
);
}
// Attach the xterm object to the DOM, exposing it to the smoke tests
this
.
_wrapperElement
.
xterm
=
this
.
_xterm
;
this
.
_container
=
container
;
this
.
_wrapperElement
=
document
.
createElement
(
'
div
'
);
dom
.
addClass
(
this
.
_wrapperElement
,
'
terminal-wrapper
'
);
this
.
_xtermElement
=
document
.
createElement
(
'
div
'
);
this
.
_wrapperElement
.
appendChild
(
this
.
_xtermElement
);
this
.
_container
.
appendChild
(
this
.
_wrapperElement
);
xterm
.
open
(
this
.
_xtermElement
);
if
(
this
.
_configHelper
.
config
.
rendererType
===
'
experimentalWebgl
'
)
{
this
.
_terminalInstanceService
.
getXtermWebglConstructor
().
then
(
Addon
=>
{
xterm
.
loadAddon
(
new
Addon
());
});
}
// Attach the xterm object to the DOM, exposing it to the smoke tests
this
.
_wrapperElement
.
xterm
=
this
.
_xterm
;
if
(
!
xterm
.
element
||
!
xterm
.
textarea
)
{
throw
new
Error
(
'
xterm elements not set after open
'
);
}
this
.
_wrapperElement
.
appendChild
(
this
.
_xtermElement
);
this
.
_container
.
appendChild
(
this
.
_wrapperElement
);
xterm
.
open
(
this
.
_xtermElement
);
if
(
this
.
_configHelper
.
config
.
rendererType
===
'
experimentalWebgl
'
)
{
this
.
_terminalInstanceService
.
getXtermWebglConstructor
().
then
(
Addon
=>
{
xterm
.
loadAddon
(
new
Addon
());
});
}
xterm
.
textarea
.
addEventListener
(
'
focus
'
,
()
=>
this
.
_onFocus
.
fire
(
this
));
xterm
.
attachCustomKeyEventHandler
((
event
:
KeyboardEvent
):
boolean
=>
{
// Disable all input if the terminal is exiting
if
(
this
.
_isExiting
)
{
return
false
;
}
if
(
!
xterm
.
element
||
!
xterm
.
textarea
)
{
throw
new
Error
(
'
xterm elements not set after open
'
);
}
// Skip processing by xterm.js of keyboard events that resolve to commands described
// within commandsToSkipShell
const
standardKeyboardEvent
=
new
StandardKeyboardEvent
(
event
);
const
resolveResult
=
this
.
_keybindingService
.
softDispatch
(
standardKeyboardEvent
,
standardKeyboardEvent
.
target
);
// Respect chords if the allowChords setting is set and it's not Escape. Escape is
// handled specially for Zen Mode's Escape, Escape chord, plus it's important in
// terminals generally
const
allowChords
=
resolveResult
&&
resolveResult
.
enterChord
&&
this
.
_configHelper
.
config
.
allowChords
&&
event
.
key
!==
'
Escape
'
;
if
(
allowChords
||
resolveResult
&&
this
.
_skipTerminalCommands
.
some
(
k
=>
k
===
resolveResult
.
commandId
))
{
event
.
preventDefault
();
return
false
;
}
xterm
.
textarea
.
addEventListener
(
'
focus
'
,
()
=>
this
.
_onFocus
.
fire
(
this
));
xterm
.
attachCustomKeyEventHandler
((
event
:
KeyboardEvent
):
boolean
=>
{
// Disable all input if the terminal is exiting
if
(
this
.
_isExiting
)
{
return
false
;
}
// If tab focus mode is on, tab is not passed to the terminal
if
(
TabFocus
.
getTabFocusMode
()
&&
event
.
keyCode
===
9
)
{
return
false
;
}
// Skip processing by xterm.js of keyboard events that resolve to commands described
// within commandsToSkipShell
const
standardKeyboardEvent
=
new
StandardKeyboardEvent
(
event
);
const
resolveResult
=
this
.
_keybindingService
.
softDispatch
(
standardKeyboardEvent
,
standardKeyboardEvent
.
target
);
// Respect chords if the allowChords setting is set and it's not Escape. Escape is
// handled specially for Zen Mode's Escape, Escape chord, plus it's important in
// terminals generally
const
allowChords
=
resolveResult
&&
resolveResult
.
enterChord
&&
this
.
_configHelper
.
config
.
allowChords
&&
event
.
key
!==
'
Escape
'
;
if
(
allowChords
||
resolveResult
&&
this
.
_skipTerminalCommands
.
some
(
k
=>
k
===
resolveResult
.
commandId
))
{
event
.
preventDefault
();
return
false
;
}
// Always have alt+F4 skip the terminal on Windows and allow it to be handled by the
// system
if
(
platform
.
isWindows
&&
event
.
altKey
&&
event
.
key
===
'
F4
'
&&
!
event
.
ctrlKey
)
{
return
false
;
}
// If tab focus mode is on, tab is not passed to the terminal
if
(
TabFocus
.
getTabFocusMode
()
&&
event
.
keyCode
===
9
)
{
return
false
;
}
return
true
;
});
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
mousedown
'
,
()
=>
{
// We need to listen to the mouseup event on the document since the user may release
// the mouse button anywhere outside of _xterm.element.
const
listener
=
dom
.
addDisposableListener
(
document
,
'
mouseup
'
,
()
=>
{
// Delay with a setTimeout to allow the mouseup to propagate through the DOM
// before evaluating the new selection state.
setTimeout
(()
=>
this
.
_refreshSelectionContextKey
(),
0
);
listener
.
dispose
();
});
}));
// Always have alt+F4 skip the terminal on Windows and allow it to be handled by the
// system
if
(
platform
.
isWindows
&&
event
.
altKey
&&
event
.
key
===
'
F4
'
&&
!
event
.
ctrlKey
)
{
return
false
;
}
// xterm.js currently drops selection on keyup as we need to handle this case.
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
keyup
'
,
()
=>
{
// Wait until keyup has propagated through the DOM before evaluating
// the new selection state.
return
true
;
});
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
mousedown
'
,
()
=>
{
// We need to listen to the mouseup event on the document since the user may release
// the mouse button anywhere outside of _xterm.element.
const
listener
=
dom
.
addDisposableListener
(
document
,
'
mouseup
'
,
()
=>
{
// Delay with a setTimeout to allow the mouseup to propagate through the DOM
// before evaluating the new selection state.
setTimeout
(()
=>
this
.
_refreshSelectionContextKey
(),
0
);
}));
const
xtermHelper
:
HTMLElement
=
<
HTMLElement
>
xterm
.
element
.
querySelector
(
'
.xterm-helpers
'
);
const
focusTrap
:
HTMLElement
=
document
.
createElement
(
'
div
'
);
focusTrap
.
setAttribute
(
'
tabindex
'
,
'
0
'
);
dom
.
addClass
(
focusTrap
,
'
focus-trap
'
);
this
.
_register
(
dom
.
addDisposableListener
(
focusTrap
,
'
focus
'
,
()
=>
{
let
currentElement
=
focusTrap
;
while
(
!
dom
.
hasClass
(
currentElement
,
'
part
'
))
{
currentElement
=
currentElement
.
parentElement
!
;
}
const
hidePanelElement
=
<
HTMLElement
>
currentElement
.
querySelector
(
'
.hide-panel-action
'
);
hidePanelElement
.
focus
();
}));
xtermHelper
.
insertBefore
(
focusTrap
,
xterm
.
textarea
);
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
textarea
,
'
focus
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
set
(
true
);
this
.
_onFocused
.
fire
(
this
);
}));
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
textarea
,
'
blur
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
reset
();
this
.
_refreshSelectionContextKey
();
}));
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
focus
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
set
(
true
);
}));
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
blur
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
reset
();
this
.
_refreshSelectionContextKey
();
}));
const
widgetManager
=
new
TerminalWidgetManager
(
this
.
_wrapperElement
,
this
.
_openerService
);
this
.
_widgetManager
=
widgetManager
;
this
.
_processManager
.
onProcessReady
(()
=>
this
.
_linkHandler
?.
setWidgetManager
(
widgetManager
));
const
computedStyle
=
window
.
getComputedStyle
(
this
.
_container
);
const
width
=
parseInt
(
computedStyle
.
getPropertyValue
(
'
width
'
).
replace
(
'
px
'
,
''
),
10
);
const
height
=
parseInt
(
computedStyle
.
getPropertyValue
(
'
height
'
).
replace
(
'
px
'
,
''
),
10
);
this
.
layout
(
new
dom
.
Dimension
(
width
,
height
));
this
.
setVisible
(
this
.
_isVisible
);
this
.
updateConfig
();
// If IShellLaunchConfig.waitOnExit was true and the process finished before the terminal
// panel was initialized.
if
(
xterm
.
getOption
(
'
disableStdin
'
))
{
this
.
_attachPressAnyKeyToCloseListener
(
xterm
);
}
listener
.
dispose
();
});
}));
const
neverMeasureRenderTime
=
this
.
_storageService
.
getBoolean
(
NEVER_MEASURE_RENDER_TIME_STORAGE_KEY
,
StorageScope
.
GLOBAL
,
false
);
if
(
!
neverMeasureRenderTime
&&
this
.
_configHelper
.
config
.
rendererType
===
'
auto
'
)
{
this
.
_measureRenderTime
();
// xterm.js currently drops selection on keyup as we need to handle this case.
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
keyup
'
,
()
=>
{
// Wait until keyup has propagated through the DOM before evaluating
// the new selection state.
setTimeout
(()
=>
this
.
_refreshSelectionContextKey
(),
0
);
}));
const
xtermHelper
:
HTMLElement
=
<
HTMLElement
>
xterm
.
element
.
querySelector
(
'
.xterm-helpers
'
);
const
focusTrap
:
HTMLElement
=
document
.
createElement
(
'
div
'
);
focusTrap
.
setAttribute
(
'
tabindex
'
,
'
0
'
);
dom
.
addClass
(
focusTrap
,
'
focus-trap
'
);
this
.
_register
(
dom
.
addDisposableListener
(
focusTrap
,
'
focus
'
,
()
=>
{
let
currentElement
=
focusTrap
;
while
(
!
dom
.
hasClass
(
currentElement
,
'
part
'
))
{
currentElement
=
currentElement
.
parentElement
!
;
}
});
const
hidePanelElement
=
<
HTMLElement
>
currentElement
.
querySelector
(
'
.hide-panel-action
'
);
hidePanelElement
.
focus
();
}));
xtermHelper
.
insertBefore
(
focusTrap
,
xterm
.
textarea
);
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
textarea
,
'
focus
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
set
(
true
);
this
.
_onFocused
.
fire
(
this
);
}));
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
textarea
,
'
blur
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
reset
();
this
.
_refreshSelectionContextKey
();
}));
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
focus
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
set
(
true
);
}));
this
.
_register
(
dom
.
addDisposableListener
(
xterm
.
element
,
'
blur
'
,
()
=>
{
this
.
_terminalFocusContextKey
.
reset
();
this
.
_refreshSelectionContextKey
();
}));
const
widgetManager
=
new
TerminalWidgetManager
(
this
.
_wrapperElement
,
this
.
_openerService
);
this
.
_widgetManager
=
widgetManager
;
this
.
_processManager
.
onProcessReady
(()
=>
this
.
_linkHandler
?.
setWidgetManager
(
widgetManager
));
const
computedStyle
=
window
.
getComputedStyle
(
this
.
_container
);
const
width
=
parseInt
(
computedStyle
.
getPropertyValue
(
'
width
'
).
replace
(
'
px
'
,
''
),
10
);
const
height
=
parseInt
(
computedStyle
.
getPropertyValue
(
'
height
'
).
replace
(
'
px
'
,
''
),
10
);
this
.
layout
(
new
dom
.
Dimension
(
width
,
height
));
this
.
setVisible
(
this
.
_isVisible
);
this
.
updateConfig
();
// If IShellLaunchConfig.waitOnExit was true and the process finished before the terminal
// panel was initialized.
if
(
xterm
.
getOption
(
'
disableStdin
'
))
{
this
.
_attachPressAnyKeyToCloseListener
(
xterm
);
}
const
neverMeasureRenderTime
=
this
.
_storageService
.
getBoolean
(
NEVER_MEASURE_RENDER_TIME_STORAGE_KEY
,
StorageScope
.
GLOBAL
,
false
);
if
(
!
neverMeasureRenderTime
&&
this
.
_configHelper
.
config
.
rendererType
===
'
auto
'
)
{
this
.
_measureRenderTime
();
}
}
private
async
_measureRenderTime
():
Promise
<
void
>
{
...
...
@@ -744,6 +744,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
public
deregisterLinkMatcher
(
linkMatcherId
:
number
):
void
{
// TODO: Move this into TerminalLinkHandler to avoid the promise check
this
.
_xtermReadyPromise
.
then
(
xterm
=>
xterm
.
deregisterLinkMatcher
(
linkMatcherId
));
}
...
...
@@ -872,8 +873,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
}
public
focusWhenReady
(
force
?:
boolean
):
Promise
<
void
>
{
return
this
.
_xtermReadyPromise
.
then
(()
=>
this
.
focus
(
force
));
public
async
focusWhenReady
(
force
?:
boolean
):
Promise
<
void
>
{
await
this
.
_xtermReadyPromise
;
this
.
focus
(
force
);
}
public
async
paste
():
Promise
<
void
>
{
...
...
@@ -883,17 +885,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this
.
focus
();
this
.
_xterm
.
paste
(
await
this
.
_clipboardService
.
readText
());
}
public
write
(
text
:
string
):
void
{
this
.
_xtermReadyPromise
.
then
(()
=>
{
if
(
!
this
.
_xterm
)
{
return
;
}
this
.
_xterm
.
write
(
text
);
});
}
public
sendText
(
text
:
string
,
addNewLine
:
boolean
):
void
{
public
async
sendText
(
text
:
string
,
addNewLine
:
boolean
):
Promise
<
void
>
{
// Normalize line endings to 'enter' press.
text
=
text
.
replace
(
TerminalInstance
.
EOL_REGEX
,
'
\r
'
);
if
(
addNewLine
&&
text
.
substr
(
text
.
length
-
1
)
!==
'
\r
'
)
{
...
...
@@ -901,7 +893,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
// Send it to the process
this
.
_processManager
.
ptyProcessReady
.
then
(()
=>
this
.
_processManager
.
write
(
text
));
await
this
.
_processManager
.
ptyProcessReady
;
this
.
_processManager
.
write
(
text
);
}
public
setVisible
(
visible
:
boolean
):
void
{
...
...
@@ -1341,7 +1334,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
@
debounce
(
50
)
private
_resize
():
void
{
private
async
_resize
():
Promise
<
void
>
{
let
cols
=
this
.
cols
;
let
rows
=
this
.
rows
;
...
...
@@ -1391,7 +1384,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
}
this
.
_processManager
.
ptyProcessReady
.
then
(()
=>
this
.
_processManager
.
setDimensions
(
cols
,
rows
));
await
this
.
_processManager
.
ptyProcessReady
;
this
.
_processManager
.
setDimensions
(
cols
,
rows
);
}
public
setShellType
(
shellType
:
TerminalShellType
)
{
...
...
src/vs/workbench/contrib/terminal/browser/terminalService.ts
浏览文件 @
8a1632a5
...
...
@@ -14,7 +14,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import
{
TerminalTab
}
from
'
vs/workbench/contrib/terminal/browser/terminalTab
'
;
import
{
IInstantiationService
,
optional
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IExtensionService
}
from
'
vs/workbench/services/extensions/common/extensions
'
;
import
{
IFileService
}
from
'
vs/platform/files/common/files
'
;
import
{
TerminalInstance
}
from
'
vs/workbench/contrib/terminal/browser/terminalInstance
'
;
import
{
ITerminalService
,
ITerminalInstance
,
ITerminalTab
,
TerminalShellType
,
WindowsShellType
}
from
'
vs/workbench/contrib/terminal/browser/terminal
'
;
import
{
IRemoteAgentService
}
from
'
vs/workbench/services/remote/common/remoteAgentService
'
;
...
...
@@ -29,6 +28,7 @@ import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform
import
{
basename
}
from
'
vs/base/common/path
'
;
import
{
IOpenFileRequest
}
from
'
vs/platform/windows/common/windows
'
;
import
{
find
}
from
'
vs/base/common/arrays
'
;
import
{
timeout
}
from
'
vs/base/common/async
'
;
import
{
IViewsService
}
from
'
vs/workbench/common/views
'
;
interface
IExtHostReadyEntry
{
...
...
@@ -97,7 +97,6 @@ export class TerminalService implements ITerminalService {
@
IDialogService
private
_dialogService
:
IDialogService
,
@
IInstantiationService
private
_instantiationService
:
IInstantiationService
,
@
IExtensionService
private
_extensionService
:
IExtensionService
,
@
IFileService
private
_fileService
:
IFileService
,
@
IRemoteAgentService
private
_remoteAgentService
:
IRemoteAgentService
,
@
IQuickInputService
private
_quickInputService
:
IQuickInputService
,
@
IConfigurationService
private
_configurationService
:
IConfigurationService
,
...
...
@@ -110,7 +109,7 @@ export class TerminalService implements ITerminalService {
this
.
_activeTabIndex
=
0
;
this
.
_isShuttingDown
=
false
;
this
.
_findState
=
new
FindReplaceState
();
lifecycleService
.
onBeforeShutdown
(
event
=>
event
.
veto
(
this
.
_onBeforeShutdown
()));
lifecycleService
.
onBeforeShutdown
(
async
event
=>
event
.
veto
(
await
this
.
_onBeforeShutdown
()));
lifecycleService
.
onShutdown
(()
=>
this
.
_onShutdown
());
if
(
this
.
_terminalNativeService
)
{
this
.
_terminalNativeService
.
onOpenFileRequest
(
e
=>
this
.
_onOpenFileRequest
(
e
));
...
...
@@ -143,15 +142,14 @@ export class TerminalService implements ITerminalService {
return
activeInstance
?
activeInstance
:
this
.
createTerminal
(
undefined
);
}
public
requestSpawnExtHostProcess
(
proxy
:
ITerminalProcessExtHostProxy
,
shellLaunchConfig
:
IShellLaunchConfig
,
activeWorkspaceRootUri
:
URI
|
undefined
,
cols
:
number
,
rows
:
number
,
isWorkspaceShellAllowed
:
boolean
):
void
{
this
.
_extensionService
.
whenInstalledExtensionsRegistered
().
then
(
async
()
=>
{
// Wait for the remoteAuthority to be ready (and listening for events) before firing
// the event to spawn the ext host process
const
conn
=
this
.
_remoteAgentService
.
getConnection
();
const
remoteAuthority
=
conn
?
conn
.
remoteAuthority
:
'
null
'
;
await
this
.
_whenExtHostReady
(
remoteAuthority
);
this
.
_onInstanceRequestSpawnExtHostProcess
.
fire
({
proxy
,
shellLaunchConfig
,
activeWorkspaceRootUri
,
cols
,
rows
,
isWorkspaceShellAllowed
});
});
public
async
requestSpawnExtHostProcess
(
proxy
:
ITerminalProcessExtHostProxy
,
shellLaunchConfig
:
IShellLaunchConfig
,
activeWorkspaceRootUri
:
URI
|
undefined
,
cols
:
number
,
rows
:
number
,
isWorkspaceShellAllowed
:
boolean
):
Promise
<
void
>
{
await
this
.
_extensionService
.
whenInstalledExtensionsRegistered
();
// Wait for the remoteAuthority to be ready (and listening for events) before firing
// the event to spawn the ext host process
const
conn
=
this
.
_remoteAgentService
.
getConnection
();
const
remoteAuthority
=
conn
?
conn
.
remoteAuthority
:
'
null
'
;
await
this
.
_whenExtHostReady
(
remoteAuthority
);
this
.
_onInstanceRequestSpawnExtHostProcess
.
fire
({
proxy
,
shellLaunchConfig
,
activeWorkspaceRootUri
,
cols
,
rows
,
isWorkspaceShellAllowed
});
}
public
requestStartExtensionTerminal
(
proxy
:
ITerminalProcessExtHostProxy
,
cols
:
number
,
rows
:
number
):
void
{
...
...
@@ -178,7 +176,7 @@ export class TerminalService implements ITerminalService {
this
.
_extHostsReady
[
remoteAuthority
]
=
{
promise
,
resolve
};
}
private
_onBeforeShutdown
():
boolean
|
Promise
<
boolean
>
{
private
async
_onBeforeShutdown
():
Promise
<
boolean
>
{
if
(
this
.
terminalInstances
.
length
===
0
)
{
// No terminal instances, don't veto
return
false
;
...
...
@@ -186,12 +184,11 @@ export class TerminalService implements ITerminalService {
if
(
this
.
configHelper
.
config
.
confirmOnExit
)
{
// veto if configured to show confirmation and the user choosed not to exit
return
this
.
_showTerminalCloseConfirmation
().
then
(
veto
=>
{
if
(
!
veto
)
{
this
.
_isShuttingDown
=
true
;
}
return
veto
;
});
const
veto
=
await
this
.
_showTerminalCloseConfirmation
();
if
(
!
veto
)
{
this
.
_isShuttingDown
=
true
;
}
return
veto
;
}
this
.
_isShuttingDown
=
true
;
...
...
@@ -204,20 +201,19 @@ export class TerminalService implements ITerminalService {
this
.
terminalInstances
.
forEach
(
instance
=>
instance
.
dispose
(
true
));
}
private
_onOpenFileRequest
(
request
:
IOpenFileRequest
):
void
{
private
async
_onOpenFileRequest
(
request
:
IOpenFileRequest
):
Promise
<
void
>
{
// if the request to open files is coming in from the integrated terminal (identified though
// the termProgram variable) and we are instructed to wait for editors close, wait for the
// marker file to get deleted and then focus back to the integrated terminal.
if
(
request
.
termProgram
===
'
vscode
'
&&
request
.
filesToWait
)
{
if
(
request
.
termProgram
===
'
vscode
'
&&
request
.
filesToWait
&&
this
.
_terminalNativeService
)
{
const
waitMarkerFileUri
=
URI
.
revive
(
request
.
filesToWait
.
waitMarkerFileUri
);
this
.
_terminalNativeService
?.
whenFileDeleted
(
waitMarkerFileUri
).
then
(()
=>
{
if
(
this
.
terminalInstances
.
length
>
0
)
{
const
terminal
=
this
.
getActiveInstance
();
if
(
terminal
)
{
terminal
.
focus
();
}
await
this
.
_terminalNativeService
.
whenFileDeleted
(
waitMarkerFileUri
);
if
(
this
.
terminalInstances
.
length
>
0
)
{
const
terminal
=
this
.
getActiveInstance
();
if
(
terminal
)
{
terminal
.
focus
();
}
}
);
}
}
}
...
...
@@ -421,43 +417,20 @@ export class TerminalService implements ITerminalService {
return
find
(
this
.
_terminalTabs
,
tab
=>
tab
.
terminalInstances
.
indexOf
(
instance
)
!==
-
1
);
}
public
showPanel
(
focus
?:
boolean
):
Promise
<
void
>
{
return
new
Promise
<
void
>
(
async
(
complete
)
=>
{
const
pane
=
this
.
_viewsService
.
getActiveViewWithId
(
TERMINAL_VIEW_ID
)
as
TerminalViewPane
;
if
(
!
pane
)
{
await
this
.
_panelService
.
openPanel
(
TERMINAL_VIEW_ID
,
focus
);
if
(
focus
)
{
// Do the focus call asynchronously as going through the
// command palette will force editor focus
setTimeout
(()
=>
{
const
instance
=
this
.
getActiveInstance
();
if
(
instance
)
{
instance
.
focusWhenReady
(
true
).
then
(()
=>
complete
(
undefined
));
}
else
{
complete
(
undefined
);
}
},
0
);
}
else
{
complete
(
undefined
);
}
}
else
{
if
(
focus
)
{
// Do the focus call asynchronously as going through the
// command palette will force editor focus
setTimeout
(()
=>
{
const
instance
=
this
.
getActiveInstance
();
if
(
instance
)
{
instance
.
focusWhenReady
(
true
).
then
(()
=>
complete
(
undefined
));
}
else
{
complete
(
undefined
);
}
},
0
);
}
else
{
complete
(
undefined
);
}
public
async
showPanel
(
focus
?:
boolean
):
Promise
<
void
>
{
const
pane
=
this
.
_viewsService
.
getActiveViewWithId
(
TERMINAL_VIEW_ID
)
as
TerminalViewPane
;
if
(
!
pane
)
{
await
this
.
_panelService
.
openPanel
(
TERMINAL_VIEW_ID
,
focus
);
}
if
(
focus
)
{
// Do the focus call asynchronously as going through the
// command palette will force editor focus
await
timeout
(
0
);
const
instance
=
this
.
getActiveInstance
();
if
(
instance
)
{
await
instance
.
focusWhenReady
(
true
);
}
return
undefined
;
});
}
}
private
_getIndexFromId
(
terminalId
:
number
):
number
{
...
...
@@ -497,22 +470,6 @@ export class TerminalService implements ITerminalService {
return
!
res
.
confirmed
;
}
protected
_validateShellPaths
(
label
:
string
,
potentialPaths
:
string
[]):
Promise
<
[
string
,
string
]
|
null
>
{
if
(
potentialPaths
.
length
===
0
)
{
return
Promise
.
resolve
(
null
);
}
const
current
=
potentialPaths
.
shift
();
if
(
current
!
===
''
)
{
return
this
.
_validateShellPaths
(
label
,
potentialPaths
);
}
return
this
.
_fileService
.
exists
(
URI
.
file
(
current
!
)).
then
(
exists
=>
{
if
(
!
exists
)
{
return
this
.
_validateShellPaths
(
label
,
potentialPaths
);
}
return
[
label
,
current
]
as
[
string
,
string
];
});
}
public
preparePathForTerminalAsync
(
originalPath
:
string
,
executable
:
string
,
title
:
string
,
shellType
:
TerminalShellType
):
Promise
<
string
>
{
return
new
Promise
<
string
>
(
c
=>
{
if
(
!
executable
)
{
...
...
@@ -575,34 +532,31 @@ export class TerminalService implements ITerminalService {
});
}
public
selectDefaultWindowsShell
():
Promise
<
void
>
{
return
this
.
_detectWindowsShells
().
then
(
shells
=>
{
const
options
:
IPickOptions
<
IQuickPickItem
>
=
{
placeHolder
:
nls
.
localize
(
'
terminal.integrated.chooseWindowsShell
'
,
"
Select your preferred terminal shell, you can change this later in your settings
"
)
};
const
quickPickItems
=
shells
.
map
((
s
):
IQuickPickItem
=>
{
return
{
label
:
s
.
label
,
description
:
s
.
path
};
});
return
this
.
_quickInputService
.
pick
(
quickPickItems
,
options
).
then
(
async
value
=>
{
if
(
!
value
)
{
return
undefined
;
}
const
shell
=
value
.
description
;
const
env
=
await
this
.
_remoteAgentService
.
getEnvironment
();
let
platformKey
:
string
;
if
(
env
)
{
platformKey
=
env
.
os
===
OperatingSystem
.
Windows
?
'
windows
'
:
(
env
.
os
===
OperatingSystem
.
Macintosh
?
'
osx
'
:
'
linux
'
);
}
else
{
platformKey
=
isWindows
?
'
windows
'
:
(
isMacintosh
?
'
osx
'
:
'
linux
'
);
}
await
this
.
_configurationService
.
updateValue
(
`terminal.integrated.shell.
${
platformKey
}
`
,
shell
,
ConfigurationTarget
.
USER
).
then
(()
=>
shell
);
return
Promise
.
resolve
();
});
public
async
selectDefaultWindowsShell
():
Promise
<
void
>
{
const
shells
=
await
this
.
_detectWindowsShells
();
const
options
:
IPickOptions
<
IQuickPickItem
>
=
{
placeHolder
:
nls
.
localize
(
'
terminal.integrated.chooseWindowsShell
'
,
"
Select your preferred terminal shell, you can change this later in your settings
"
)
};
const
quickPickItems
=
shells
.
map
((
s
):
IQuickPickItem
=>
{
return
{
label
:
s
.
label
,
description
:
s
.
path
};
});
const
value
=
await
this
.
_quickInputService
.
pick
(
quickPickItems
,
options
);
if
(
!
value
)
{
return
undefined
;
}
const
shell
=
value
.
description
;
const
env
=
await
this
.
_remoteAgentService
.
getEnvironment
();
let
platformKey
:
string
;
if
(
env
)
{
platformKey
=
env
.
os
===
OperatingSystem
.
Windows
?
'
windows
'
:
(
env
.
os
===
OperatingSystem
.
Macintosh
?
'
osx
'
:
'
linux
'
);
}
else
{
platformKey
=
isWindows
?
'
windows
'
:
(
isMacintosh
?
'
osx
'
:
'
linux
'
);
}
await
this
.
_configurationService
.
updateValue
(
`terminal.integrated.shell.
${
platformKey
}
`
,
shell
,
ConfigurationTarget
.
USER
);
}
private
_detectWindowsShells
():
Promise
<
IShellDefinition
[]
>
{
return
new
Promise
(
r
=>
this
.
_onRequestAvailableShells
.
fire
(
r
));
return
new
Promise
(
r
=>
this
.
_onRequestAvailableShells
.
fire
(
{
callback
:
r
}
));
}
...
...
@@ -655,12 +609,11 @@ export class TerminalService implements ITerminalService {
this
.
_onInstancesChanged
.
fire
();
}
public
focusFindWidget
():
Promise
<
void
>
{
return
this
.
showPanel
(
false
).
then
(()
=>
{
const
pane
=
this
.
_viewsService
.
getActiveViewWithId
(
TERMINAL_VIEW_ID
)
as
TerminalViewPane
;
pane
.
focusFindWidget
();
this
.
_findWidgetVisible
.
set
(
true
);
});
public
async
focusFindWidget
():
Promise
<
void
>
{
await
this
.
showPanel
(
false
);
const
pane
=
this
.
_viewsService
.
getActiveViewWithId
(
TERMINAL_VIEW_ID
)
as
TerminalViewPane
;
pane
.
focusFindWidget
();
this
.
_findWidgetVisible
.
set
(
true
);
}
public
hideFindWidget
():
void
{
...
...
src/vs/workbench/contrib/terminal/browser/terminalView.ts
浏览文件 @
8a1632a5
...
...
@@ -296,9 +296,8 @@ export class TerminalViewPane extends ViewPane {
const
terminal
=
this
.
_terminalService
.
getActiveInstance
();
if
(
terminal
)
{
return
this
.
_terminalService
.
preparePathForTerminalAsync
(
path
,
terminal
.
shellLaunchConfig
.
executable
,
terminal
.
title
,
terminal
.
shellType
).
then
(
preparedPath
=>
{
terminal
.
sendText
(
preparedPath
,
false
);
});
const
preparedPath
=
await
this
.
_terminalService
.
preparePathForTerminalAsync
(
path
,
terminal
.
shellLaunchConfig
.
executable
,
terminal
.
title
,
terminal
.
shellType
);
terminal
.
sendText
(
preparedPath
,
false
);
}
}
}));
...
...
src/vs/workbench/contrib/terminal/common/terminal.ts
浏览文件 @
8a1632a5
...
...
@@ -360,7 +360,7 @@ export interface IStartExtensionTerminalRequest {
}
export
interface
IAvailableShellsRequest
{
(
shells
:
IShellDefinition
[]):
void
;
callback
:
(
shells
:
IShellDefinition
[])
=>
void
;
}
export
interface
IDefaultShellAndArgsRequest
{
...
...
src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts
浏览文件 @
8a1632a5
...
...
@@ -44,17 +44,16 @@ export class TerminalNativeService implements ITerminalNativeService {
// Complete when wait marker file is deleted
return
new
Promise
<
void
>
(
resolve
=>
{
let
running
=
false
;
const
interval
=
setInterval
(()
=>
{
const
interval
=
setInterval
(
async
()
=>
{
if
(
!
running
)
{
running
=
true
;
this
.
_fileService
.
exists
(
path
).
then
(
exists
=>
{
running
=
false
;
const
exists
=
await
this
.
_fileService
.
exists
(
path
);
running
=
false
;
if
(
!
exists
)
{
clearInterval
(
interval
);
resolve
(
undefined
);
}
});
if
(
!
exists
)
{
clearInterval
(
interval
);
resolve
(
undefined
);
}
}
},
1000
);
});
...
...
src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts
浏览文件 @
8a1632a5
...
...
@@ -10,6 +10,7 @@ import { Terminal as XTermTerminal } from 'xterm';
import
*
as
WindowsProcessTreeType
from
'
windows-process-tree
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
ITerminalInstance
,
TerminalShellType
,
WindowsShellType
}
from
'
vs/workbench/contrib/terminal/browser/terminal
'
;
import
{
timeout
}
from
'
vs/base/common/async
'
;
const
SHELL_EXECUTABLES
=
[
'
cmd.exe
'
,
...
...
@@ -46,36 +47,40 @@ export class WindowsShellHelper extends Disposable implements IWindowsShellHelpe
this
.
_isDisposed
=
false
;
(
import
(
'
windows-process-tree
'
)).
then
(
mod
=>
{
if
(
this
.
_isDisposed
)
{
return
;
}
this
.
_startMonitoringShell
();
}
windowsProcessTree
=
mod
;
// The debounce is necessary to prevent multiple processes from spawning when
// the enter key or output is spammed
Event
.
debounce
(
this
.
_onCheckShell
.
event
,
(
l
,
e
)
=>
e
,
150
,
true
)(()
=>
{
setTimeout
(()
=>
{
this
.
checkShell
();
},
50
);
});
private
async
_startMonitoringShell
():
Promise
<
void
>
{
if
(
!
windowsProcessTree
)
{
windowsProcessTree
=
await
import
(
'
windows-process-tree
'
);
}
// We want to fire a new check for the shell on a linefeed, but only
// when parsing has finished which is indicated by the cursormove event.
// If this is done on every linefeed, parsing ends up taking
// significantly longer due to resetting timers. Note that this is
// private API.
this
.
_xterm
.
onLineFeed
(()
=>
this
.
_newLineFeed
=
true
);
this
.
_xterm
.
onCursorMove
(()
=>
{
if
(
this
.
_newLineFeed
)
{
this
.
_onCheckShell
.
fire
(
undefined
);
this
.
_newLineFeed
=
false
;
}
});
if
(
this
.
_isDisposed
)
{
return
;
}
// The debounce is necessary to prevent multiple processes from spawning when
// the enter key or output is spammed
Event
.
debounce
(
this
.
_onCheckShell
.
event
,
(
l
,
e
)
=>
e
,
150
,
true
)(
async
()
=>
{
await
timeout
(
50
);
this
.
checkShell
();
});
// Fire a new check for the shell when any key is pressed.
this
.
_xterm
.
onKey
(()
=>
this
.
_onCheckShell
.
fire
(
undefined
));
// We want to fire a new check for the shell on a linefeed, but only
// when parsing has finished which is indicated by the cursormove event.
// If this is done on every linefeed, parsing ends up taking
// significantly longer due to resetting timers. Note that this is
// private API.
this
.
_xterm
.
onLineFeed
(()
=>
this
.
_newLineFeed
=
true
);
this
.
_xterm
.
onCursorMove
(()
=>
{
if
(
this
.
_newLineFeed
)
{
this
.
_onCheckShell
.
fire
(
undefined
);
this
.
_newLineFeed
=
false
;
}
});
// Fire a new check for the shell when any key is pressed.
this
.
_xterm
.
onKey
(()
=>
this
.
_onCheckShell
.
fire
(
undefined
));
}
private
checkShell
():
void
{
...
...
src/vs/workbench/contrib/terminal/node/terminal.ts
浏览文件 @
8a1632a5
...
...
@@ -64,18 +64,17 @@ function getSystemShellWindows(): string {
let
detectedDistro
=
LinuxDistro
.
Unknown
;
if
(
platform
.
isLinux
)
{
const
file
=
'
/etc/os-release
'
;
fileExists
(
file
).
then
(
exists
=>
{
fileExists
(
file
).
then
(
async
exists
=>
{
if
(
!
exists
)
{
return
;
}
readFile
(
file
).
then
(
b
=>
{
const
contents
=
b
.
toString
();
if
(
/NAME="
?
Fedora"
?
/
.
test
(
contents
))
{
detectedDistro
=
LinuxDistro
.
Fedora
;
}
else
if
(
/NAME="
?
Ubuntu"
?
/
.
test
(
contents
))
{
detectedDistro
=
LinuxDistro
.
Ubuntu
;
}
});
const
buffer
=
await
readFile
(
file
);
const
contents
=
buffer
.
toString
();
if
(
/NAME="
?
Fedora"
?
/
.
test
(
contents
))
{
detectedDistro
=
LinuxDistro
.
Fedora
;
}
else
if
(
/NAME="
?
Ubuntu"
?
/
.
test
(
contents
))
{
detectedDistro
=
LinuxDistro
.
Ubuntu
;
}
});
}
...
...
@@ -128,8 +127,8 @@ async function detectAvailableWindowsShells(): Promise<IShellDefinition[]> {
};
const
promises
:
PromiseLike
<
IShellDefinition
|
undefined
>
[]
=
[];
Object
.
keys
(
expectedLocations
).
forEach
(
key
=>
promises
.
push
(
validateShellPaths
(
key
,
expectedLocations
[
key
])));
return
Promise
.
all
(
promises
).
then
(
coalesce
);
const
shells
=
await
Promise
.
all
(
promises
);
return
coalesce
(
shells
);
}
async
function
detectAvailableUnixShells
():
Promise
<
IShellDefinition
[]
>
{
...
...
src/vs/workbench/contrib/terminal/node/terminalProcess.ts
浏览文件 @
8a1632a5
...
...
@@ -70,6 +70,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
conptyInheritCursor
:
useConpty
&&
!!
shellLaunchConfig
.
initialText
};
// TODO: Pull verification out into its own function
const
cwdVerification
=
stat
(
cwd
).
then
(
async
stat
=>
{
if
(
!
stat
.
isDirectory
())
{
return
Promise
.
reject
(
SHELL_CWD_INVALID_EXIT_CODE
);
...
...
@@ -178,26 +179,25 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
this
.
_closeTimeout
=
setTimeout
(()
=>
this
.
_kill
(),
250
);
}
private
_kill
():
void
{
private
async
_kill
():
Promise
<
void
>
{
// Wait to kill to process until the start up code has run. This prevents us from firing a process exit before a
// process start.
this
.
_processStartupComplete
!
.
then
(()
=>
{
if
(
this
.
_isDisposed
)
{
return
;
}
// Attempt to kill the pty, it may have already been killed at this
// point but we want to make sure
try
{
if
(
this
.
_ptyProcess
)
{
this
.
_logService
.
trace
(
'
IPty#kill
'
);
this
.
_ptyProcess
.
kill
();
}
}
catch
(
ex
)
{
// Swallow, the pty has already been killed
await
this
.
_processStartupComplete
;
if
(
this
.
_isDisposed
)
{
return
;
}
// Attempt to kill the pty, it may have already been killed at this
// point but we want to make sure
try
{
if
(
this
.
_ptyProcess
)
{
this
.
_logService
.
trace
(
'
IPty#kill
'
);
this
.
_ptyProcess
.
kill
();
}
this
.
_onProcessExit
.
fire
(
this
.
_exitCode
||
0
);
this
.
dispose
();
});
}
catch
(
ex
)
{
// Swallow, the pty has already been killed
}
this
.
_onProcessExit
.
fire
(
this
.
_exitCode
||
0
);
this
.
dispose
();
}
private
_sendProcessId
(
ptyProcess
:
pty
.
IPty
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录