Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
a5c2f2ef
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,发现更多精彩内容 >>
未验证
提交
a5c2f2ef
编写于
10月 14, 2020
作者:
A
Alexandru Dima
提交者:
GitHub
10月 14, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #108684 from microsoft/remoteTerminals
Introduce Remote Terminals
上级
59f4562c
35368d6c
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
576 addition
and
25 deletion
+576
-25
src/vs/base/node/processes.ts
src/vs/base/node/processes.ts
+2
-2
src/vs/workbench/api/node/extHostCLIServer.ts
src/vs/workbench/api/node/extHostCLIServer.ts
+19
-6
src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts
...rkbench/contrib/terminal/browser/remoteTerminalService.ts
+209
-0
src/vs/workbench/contrib/terminal/browser/terminal.ts
src/vs/workbench/contrib/terminal/browser/terminal.ts
+13
-0
src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts
...kbench/contrib/terminal/browser/terminalProcessManager.ts
+8
-2
src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts
...orkbench/contrib/terminal/common/remoteTerminalChannel.ts
+309
-0
src/vs/workbench/contrib/terminal/node/terminal.ts
src/vs/workbench/contrib/terminal/node/terminal.ts
+11
-11
src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts
...vs/workbench/contrib/terminal/node/terminalEnvironment.ts
+4
-4
src/vs/workbench/workbench.common.main.ts
src/vs/workbench/workbench.common.main.ts
+1
-0
未找到文件。
src/vs/base/node/processes.ts
浏览文件 @
a5c2f2ef
...
...
@@ -86,8 +86,8 @@ function terminateProcess(process: cp.ChildProcess, cwd?: string): Promise<Termi
return
Promise
.
resolve
({
success
:
true
});
}
export
function
getWindowsShell
():
string
{
return
process
.
env
[
'
comspec
'
]
||
'
cmd.exe
'
;
export
function
getWindowsShell
(
environment
:
Platform
.
IProcessEnvironment
=
process
.
env
as
Platform
.
IProcessEnvironment
):
string
{
return
environment
[
'
comspec
'
]
||
'
cmd.exe
'
;
}
export
abstract
class
AbstractProcess
<
TProgressData
>
{
...
...
src/vs/workbench/api/node/extHostCLIServer.ts
浏览文件 @
a5c2f2ef
...
...
@@ -34,12 +34,18 @@ export interface RunCommandPipeArgs {
args
:
any
[];
}
export
class
CLIServer
{
export
interface
ICommandsExecuter
{
executeCommand
<
T
>
(
id
:
string
,
...
args
:
any
[]):
Promise
<
T
>
;
}
private
_server
:
http
.
Server
;
private
_ipcHandlePath
:
string
|
undefined
;
export
class
CLIServerBase
{
private
readonly
_server
:
http
.
Server
;
constructor
(@
IExtHostCommands
private
_commands
:
IExtHostCommands
,
@
ILogService
private
logService
:
ILogService
)
{
constructor
(
private
readonly
_commands
:
ICommandsExecuter
,
private
readonly
logService
:
ILogService
,
private
readonly
_ipcHandlePath
:
string
,
)
{
this
.
_server
=
http
.
createServer
((
req
,
res
)
=>
this
.
onRequest
(
req
,
res
));
this
.
setup
().
catch
(
err
=>
{
logService
.
error
(
err
);
...
...
@@ -52,8 +58,6 @@ export class CLIServer {
}
private
async
setup
():
Promise
<
string
>
{
this
.
_ipcHandlePath
=
createRandomIPCHandle
();
try
{
this
.
_server
.
listen
(
this
.
ipcHandlePath
);
this
.
_server
.
on
(
'
error
'
,
err
=>
this
.
logService
.
error
(
err
));
...
...
@@ -176,3 +180,12 @@ export class CLIServer {
}
}
}
export
class
CLIServer
extends
CLIServerBase
{
constructor
(
@
IExtHostCommands
commands
:
IExtHostCommands
,
@
ILogService
logService
:
ILogService
)
{
super
(
commands
,
logService
,
createRandomIPCHandle
());
}
}
src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts
0 → 100644
浏览文件 @
a5c2f2ef
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Barrier
}
from
'
vs/base/common/async
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
revive
}
from
'
vs/base/common/marshalling
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
*
as
nls
from
'
vs/nls
'
;
import
{
ICommandService
}
from
'
vs/platform/commands/common/commands
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
IRemoteTerminalService
,
ITerminalInstanceService
,
ITerminalService
}
from
'
vs/workbench/contrib/terminal/browser/terminal
'
;
import
{
IRemoteTerminalProcessExecCommandEvent
,
IShellLaunchConfigDto
,
RemoteTerminalChannelClient
,
REMOTE_TERMINAL_CHANNEL_NAME
}
from
'
vs/workbench/contrib/terminal/common/remoteTerminalChannel
'
;
import
{
IShellLaunchConfig
,
ITerminalChildProcess
,
ITerminalConfigHelper
,
ITerminalLaunchError
}
from
'
vs/workbench/contrib/terminal/common/terminal
'
;
import
{
IRemoteAgentService
}
from
'
vs/workbench/services/remote/common/remoteAgentService
'
;
export
class
RemoteTerminalService
extends
Disposable
implements
IRemoteTerminalService
{
public
_serviceBrand
:
undefined
;
private
readonly
_remoteTerminalChannel
:
RemoteTerminalChannelClient
|
null
;
constructor
(
@
ITerminalService
_terminalService
:
ITerminalService
,
@
ITerminalInstanceService
readonly
terminalInstanceService
:
ITerminalInstanceService
,
@
IRemoteAgentService
private
readonly
_remoteAgentService
:
IRemoteAgentService
,
@
ILogService
private
readonly
_logService
:
ILogService
,
@
IInstantiationService
private
readonly
_instantiationService
:
IInstantiationService
,
@
ICommandService
private
readonly
_commandService
:
ICommandService
,
)
{
super
();
const
connection
=
this
.
_remoteAgentService
.
getConnection
();
if
(
connection
)
{
this
.
_remoteTerminalChannel
=
this
.
_instantiationService
.
createInstance
(
RemoteTerminalChannelClient
,
connection
.
remoteAuthority
,
connection
.
getChannel
(
REMOTE_TERMINAL_CHANNEL_NAME
));
}
else
{
this
.
_remoteTerminalChannel
=
null
;
}
}
public
async
createRemoteTerminalProcess
(
terminalId
:
number
,
shellLaunchConfig
:
IShellLaunchConfig
,
activeWorkspaceRootUri
:
URI
|
undefined
,
cols
:
number
,
rows
:
number
,
configHelper
:
ITerminalConfigHelper
,):
Promise
<
ITerminalChildProcess
>
{
if
(
!
this
.
_remoteTerminalChannel
)
{
throw
new
Error
(
`Cannot create remote terminal when there is no remote!`
);
}
return
new
RemoteTerminalProcess
(
terminalId
,
shellLaunchConfig
,
activeWorkspaceRootUri
,
cols
,
rows
,
configHelper
,
this
.
_remoteTerminalChannel
,
this
.
_remoteAgentService
,
this
.
_logService
,
this
.
_commandService
);
}
}
export
class
RemoteTerminalProcess
extends
Disposable
implements
ITerminalChildProcess
{
public
readonly
_onProcessData
=
this
.
_register
(
new
Emitter
<
string
>
());
public
readonly
onProcessData
:
Event
<
string
>
=
this
.
_onProcessData
.
event
;
private
readonly
_onProcessExit
=
this
.
_register
(
new
Emitter
<
number
|
undefined
>
());
public
readonly
onProcessExit
:
Event
<
number
|
undefined
>
=
this
.
_onProcessExit
.
event
;
public
readonly
_onProcessReady
=
this
.
_register
(
new
Emitter
<
{
pid
:
number
,
cwd
:
string
}
>
());
public
get
onProcessReady
():
Event
<
{
pid
:
number
,
cwd
:
string
}
>
{
return
this
.
_onProcessReady
.
event
;
}
private
readonly
_onProcessTitleChanged
=
this
.
_register
(
new
Emitter
<
string
>
());
public
readonly
onProcessTitleChanged
:
Event
<
string
>
=
this
.
_onProcessTitleChanged
.
event
;
private
readonly
_onProcessResolvedShellLaunchConfig
=
this
.
_register
(
new
Emitter
<
IShellLaunchConfig
>
());
public
get
onProcessResolvedShellLaunchConfig
():
Event
<
IShellLaunchConfig
>
{
return
this
.
_onProcessResolvedShellLaunchConfig
.
event
;
}
private
_startBarrier
:
Barrier
;
private
_remoteTerminalId
:
number
;
constructor
(
private
readonly
_terminalId
:
number
,
private
readonly
_shellLaunchConfig
:
IShellLaunchConfig
,
private
readonly
_activeWorkspaceRootUri
:
URI
|
undefined
,
private
readonly
_cols
:
number
,
private
readonly
_rows
:
number
,
private
readonly
_configHelper
:
ITerminalConfigHelper
,
private
readonly
_remoteTerminalChannel
:
RemoteTerminalChannelClient
,
private
readonly
_remoteAgentService
:
IRemoteAgentService
,
private
readonly
_logService
:
ILogService
,
private
readonly
_commandService
:
ICommandService
,
)
{
super
();
this
.
_startBarrier
=
new
Barrier
();
this
.
_remoteTerminalId
=
0
;
}
public
async
start
():
Promise
<
ITerminalLaunchError
|
undefined
>
{
// TODO@remoteAgentTerminals: Add a loading title only if this terminal is
// instantiated before a connection is up and running
setTimeout
(()
=>
this
.
_onProcessTitleChanged
.
fire
(
nls
.
localize
(
'
terminal.integrated.starting
'
,
"
Starting...
"
)),
0
);
// Fetch the environment to check shell permissions
const
env
=
await
this
.
_remoteAgentService
.
getEnvironment
();
if
(
!
env
)
{
// Extension host processes are only allowed in remote extension hosts currently
throw
new
Error
(
'
Could not fetch remote environment
'
);
}
const
isWorkspaceShellAllowed
=
this
.
_configHelper
.
checkWorkspaceShellPermissions
(
env
.
os
);
const
shellLaunchConfigDto
:
IShellLaunchConfigDto
=
{
name
:
this
.
_shellLaunchConfig
.
name
,
executable
:
this
.
_shellLaunchConfig
.
executable
,
args
:
this
.
_shellLaunchConfig
.
args
,
cwd
:
this
.
_shellLaunchConfig
.
cwd
,
env
:
this
.
_shellLaunchConfig
.
env
};
this
.
_logService
.
trace
(
'
Spawning remote agent process
'
,
{
terminalId
:
this
.
_terminalId
,
shellLaunchConfigDto
});
const
result
=
await
this
.
_remoteTerminalChannel
.
createTerminalProcess
(
shellLaunchConfigDto
,
this
.
_activeWorkspaceRootUri
,
this
.
_cols
,
this
.
_rows
,
isWorkspaceShellAllowed
,
);
this
.
_remoteTerminalId
=
result
.
terminalId
;
this
.
_register
(
this
.
_remoteTerminalChannel
.
onTerminalProcessEvent
(
this
.
_remoteTerminalId
)(
event
=>
{
switch
(
event
.
type
)
{
case
'
ready
'
:
return
this
.
_onProcessReady
.
fire
({
pid
:
event
.
pid
,
cwd
:
event
.
cwd
});
case
'
titleChanged
'
:
return
this
.
_onProcessTitleChanged
.
fire
(
event
.
title
);
case
'
data
'
:
return
this
.
_onProcessData
.
fire
(
event
.
data
);
case
'
exit
'
:
return
this
.
_onProcessExit
.
fire
(
event
.
exitCode
);
case
'
execCommand
'
:
return
this
.
_execCommand
(
event
);
}
}));
this
.
_onProcessResolvedShellLaunchConfig
.
fire
(
reviveIShellLaunchConfig
(
result
.
resolvedShellLaunchConfig
));
const
startResult
=
await
this
.
_remoteTerminalChannel
.
startTerminalProcess
(
this
.
_remoteTerminalId
);
if
(
typeof
startResult
!==
'
undefined
'
)
{
// An error occurred
return
startResult
;
}
this
.
_startBarrier
.
open
();
return
undefined
;
}
public
shutdown
(
immediate
:
boolean
):
void
{
this
.
_startBarrier
.
wait
().
then
(
_
=>
{
this
.
_remoteTerminalChannel
.
shutdownTerminalProcess
(
this
.
_remoteTerminalId
,
immediate
);
});
}
public
input
(
data
:
string
):
void
{
this
.
_startBarrier
.
wait
().
then
(
_
=>
{
this
.
_remoteTerminalChannel
.
sendInputToTerminalProcess
(
this
.
_remoteTerminalId
,
data
);
});
}
public
resize
(
cols
:
number
,
rows
:
number
):
void
{
this
.
_startBarrier
.
wait
().
then
(
_
=>
{
this
.
_remoteTerminalChannel
.
resizeTerminalProcess
(
this
.
_remoteTerminalId
,
cols
,
rows
);
});
}
public
async
getInitialCwd
():
Promise
<
string
>
{
await
this
.
_startBarrier
.
wait
();
return
this
.
_remoteTerminalChannel
.
getTerminalInitialCwd
(
this
.
_remoteTerminalId
);
}
public
async
getCwd
():
Promise
<
string
>
{
await
this
.
_startBarrier
.
wait
();
return
this
.
_remoteTerminalChannel
.
getTerminalCwd
(
this
.
_remoteTerminalId
);
}
/**
* TODO@roblourens I don't think this does anything useful in the EH and the value isn't used
*/
public
async
getLatency
():
Promise
<
number
>
{
return
0
;
}
private
async
_execCommand
(
event
:
IRemoteTerminalProcessExecCommandEvent
):
Promise
<
void
>
{
const
reqId
=
event
.
reqId
;
const
commandArgs
=
event
.
commandArgs
.
map
(
arg
=>
revive
(
arg
));
try
{
const
result
=
await
this
.
_commandService
.
executeCommand
(
event
.
commandId
,
...
commandArgs
);
this
.
_remoteTerminalChannel
.
sendCommandResultToTerminalProcess
(
this
.
_remoteTerminalId
,
reqId
,
false
,
result
);
}
catch
(
err
)
{
this
.
_remoteTerminalChannel
.
sendCommandResultToTerminalProcess
(
this
.
_remoteTerminalId
,
reqId
,
true
,
err
);
}
}
}
function
reviveIShellLaunchConfig
(
dto
:
IShellLaunchConfigDto
):
IShellLaunchConfig
{
return
{
name
:
dto
.
name
,
executable
:
dto
.
executable
,
args
:
dto
.
args
,
cwd
:
(
(
typeof
dto
.
cwd
===
'
string
'
||
typeof
dto
.
cwd
===
'
undefined
'
)
?
dto
.
cwd
:
URI
.
revive
(
dto
.
cwd
)
),
env
:
dto
.
env
,
hideFromUser
:
dto
.
hideFromUser
};
}
registerSingleton
(
IRemoteTerminalService
,
RemoteTerminalService
);
src/vs/workbench/contrib/terminal/browser/terminal.ts
浏览文件 @
a5c2f2ef
...
...
@@ -17,6 +17,7 @@ import { URI } from 'vs/base/common/uri';
export
const
ITerminalService
=
createDecorator
<
ITerminalService
>
(
'
terminalService
'
);
export
const
ITerminalInstanceService
=
createDecorator
<
ITerminalInstanceService
>
(
'
terminalInstanceService
'
);
export
const
IRemoteTerminalService
=
createDecorator
<
IRemoteTerminalService
>
(
'
remoteTerminalService
'
);
/**
* A service used by TerminalInstance (and components owned by it) that allows it to break its
...
...
@@ -174,6 +175,18 @@ export interface ITerminalService {
requestStartExtensionTerminal
(
proxy
:
ITerminalProcessExtHostProxy
,
cols
:
number
,
rows
:
number
):
Promise
<
ITerminalLaunchError
|
undefined
>
;
}
export
interface
IRemoteExtHostEnvProvider
{
getEnvironment
():
Promise
<
IProcessEnvironment
>
;
}
export
interface
IRemoteTerminalService
{
readonly
_serviceBrand
:
undefined
;
dispose
():
void
;
createRemoteTerminalProcess
(
terminalId
:
number
,
shellLaunchConfig
:
IShellLaunchConfig
,
activeWorkspaceRootUri
:
URI
|
undefined
,
cols
:
number
,
rows
:
number
,
configHelper
:
ITerminalConfigHelper
,):
Promise
<
ITerminalChildProcess
>
;
}
/**
* Similar to xterm.js' ILinkProvider but using promises and hides xterm.js internals (like buffer
* positions, decorations, etc.) from the rest of vscode. This is the interface to use for
...
...
src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts
浏览文件 @
a5c2f2ef
...
...
@@ -18,7 +18,7 @@ import { Schemas } from 'vs/base/common/network';
import
{
getRemoteAuthority
}
from
'
vs/platform/remote/common/remoteHosts
'
;
import
{
IWorkbenchEnvironmentService
}
from
'
vs/workbench/services/environment/common/environmentService
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/productService
'
;
import
{
ITerminalInstanceService
}
from
'
vs/workbench/contrib/terminal/browser/terminal
'
;
import
{
I
RemoteTerminalService
,
I
TerminalInstanceService
}
from
'
vs/workbench/contrib/terminal/browser/terminal
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
IRemoteAgentService
}
from
'
vs/workbench/services/remote/common/remoteAgentService
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
...
...
@@ -99,6 +99,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
@
IRemoteAgentService
private
readonly
_remoteAgentService
:
IRemoteAgentService
,
@
IPathService
private
readonly
_pathService
:
IPathService
,
@
IEnvironmentVariableService
private
readonly
_environmentVariableService
:
IEnvironmentVariableService
,
@
IRemoteTerminalService
private
readonly
_remoteTerminalService
:
IRemoteTerminalService
,
)
{
super
();
this
.
ptyProcessReady
=
new
Promise
<
void
>
(
c
=>
{
...
...
@@ -157,7 +158,12 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
}
const
activeWorkspaceRootUri
=
this
.
_historyService
.
getLastActiveWorkspaceRoot
();
this
.
_process
=
this
.
_instantiationService
.
createInstance
(
TerminalProcessExtHostProxy
,
this
.
_terminalId
,
shellLaunchConfig
,
activeWorkspaceRootUri
,
cols
,
rows
,
this
.
_configHelper
);
const
enableRemoteAgentTerminals
=
this
.
_workspaceConfigurationService
.
getValue
(
'
terminal.integrated.serverSpawn
'
);
if
(
enableRemoteAgentTerminals
)
{
this
.
_process
=
await
this
.
_remoteTerminalService
.
createRemoteTerminalProcess
(
this
.
_terminalId
,
shellLaunchConfig
,
activeWorkspaceRootUri
,
cols
,
rows
,
this
.
_configHelper
);
}
else
{
this
.
_process
=
this
.
_instantiationService
.
createInstance
(
TerminalProcessExtHostProxy
,
this
.
_terminalId
,
shellLaunchConfig
,
activeWorkspaceRootUri
,
cols
,
rows
,
this
.
_configHelper
);
}
}
else
{
this
.
_process
=
await
this
.
_launchProcess
(
shellLaunchConfig
,
cols
,
rows
,
this
.
userHome
,
isScreenReaderModeEnabled
);
}
...
...
src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts
0 → 100644
浏览文件 @
a5c2f2ef
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
withNullAsUndefined
}
from
'
vs/base/common/types
'
;
import
{
URI
,
UriComponents
}
from
'
vs/base/common/uri
'
;
import
{
IChannel
}
from
'
vs/base/parts/ipc/common/ipc
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
IRemoteAuthorityResolverService
}
from
'
vs/platform/remote/common/remoteAuthorityResolver
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
IEnvironmentVariableService
,
ISerializableEnvironmentVariableCollection
}
from
'
vs/workbench/contrib/terminal/common/environmentVariable
'
;
import
{
serializeEnvironmentVariableCollection
}
from
'
vs/workbench/contrib/terminal/common/environmentVariableShared
'
;
import
{
ITerminalConfiguration
,
ITerminalEnvironment
,
ITerminalLaunchError
,
TERMINAL_CONFIG_SECTION
}
from
'
vs/workbench/contrib/terminal/common/terminal
'
;
import
{
IConfigurationResolverService
}
from
'
vs/workbench/services/configurationResolver/common/configurationResolver
'
;
import
{
SideBySideEditor
,
EditorResourceAccessor
}
from
'
vs/workbench/common/editor
'
;
import
{
IEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
Schemas
}
from
'
vs/base/common/network
'
;
export
const
REMOTE_TERMINAL_CHANNEL_NAME
=
'
remoteterminal
'
;
export
interface
IShellLaunchConfigDto
{
name
?:
string
;
executable
?:
string
;
args
?:
string
[]
|
string
;
cwd
?:
string
|
UriComponents
;
env
?:
{
[
key
:
string
]:
string
|
null
;
};
hideFromUser
?:
boolean
;
}
export
interface
ISingleTerminalConfiguration
<
T
>
{
userValue
:
T
|
undefined
;
value
:
T
|
undefined
;
defaultValue
:
T
|
undefined
;
}
export
interface
ICompleteTerminalConfiguration
{
'
terminal.integrated.automationShell.windows
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.automationShell.osx
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.automationShell.linux
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.shell.windows
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.shell.osx
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.shell.linux
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.shellArgs.windows
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.shellArgs.osx
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.shellArgs.linux
'
:
ISingleTerminalConfiguration
<
string
|
string
[]
>
;
'
terminal.integrated.env.windows
'
:
ISingleTerminalConfiguration
<
ITerminalEnvironment
>
;
'
terminal.integrated.env.osx
'
:
ISingleTerminalConfiguration
<
ITerminalEnvironment
>
;
'
terminal.integrated.env.linux
'
:
ISingleTerminalConfiguration
<
ITerminalEnvironment
>
;
'
terminal.integrated.inheritEnv
'
:
boolean
;
'
terminal.integrated.cwd
'
:
string
;
'
terminal.integrated.detectLocale
'
:
'
auto
'
|
'
off
'
|
'
on
'
;
}
export
type
ITerminalEnvironmentVariableCollections
=
[
string
,
ISerializableEnvironmentVariableCollection
][];
export
interface
IWorkspaceFolderData
{
uri
:
UriComponents
;
name
:
string
;
index
:
number
;
}
export
interface
ICreateTerminalProcessArguments
{
configuration
:
ICompleteTerminalConfiguration
;
resolvedVariables
:
{
[
name
:
string
]:
string
;
};
envVariableCollections
:
ITerminalEnvironmentVariableCollections
;
shellLaunchConfig
:
IShellLaunchConfigDto
;
workspaceFolders
:
IWorkspaceFolderData
[];
activeWorkspaceFolder
:
IWorkspaceFolderData
|
null
;
activeFileResource
:
UriComponents
|
undefined
;
cols
:
number
;
rows
:
number
;
isWorkspaceShellAllowed
:
boolean
;
resolverEnv
:
{
[
key
:
string
]:
string
|
null
;
}
|
undefined
}
export
interface
ICreateTerminalProcessResult
{
terminalId
:
number
;
resolvedShellLaunchConfig
:
IShellLaunchConfigDto
;
}
export
interface
IStartTerminalProcessArguments
{
id
:
number
;
}
export
interface
ISendInputToTerminalProcessArguments
{
id
:
number
;
data
:
string
;
}
export
interface
IShutdownTerminalProcessArguments
{
id
:
number
;
immediate
:
boolean
;
}
export
interface
IResizeTerminalProcessArguments
{
id
:
number
;
cols
:
number
;
rows
:
number
;
}
export
interface
IGetTerminalInitialCwdArguments
{
id
:
number
;
}
export
interface
IGetTerminalCwdArguments
{
id
:
number
;
}
export
interface
ISendCommandResultToTerminalProcessArguments
{
id
:
number
;
reqId
:
number
;
isError
:
boolean
;
payload
:
any
;
}
export
interface
IRemoteTerminalProcessReadyEvent
{
type
:
'
ready
'
;
pid
:
number
;
cwd
:
string
;
}
export
interface
IRemoteTerminalProcessTitleChangedEvent
{
type
:
'
titleChanged
'
;
title
:
string
;
}
export
interface
IRemoteTerminalProcessDataEvent
{
type
:
'
data
'
data
:
string
;
}
export
interface
IRemoteTerminalProcessExitEvent
{
type
:
'
exit
'
exitCode
:
number
|
undefined
;
}
export
interface
IRemoteTerminalProcessExecCommandEvent
{
type
:
'
execCommand
'
;
reqId
:
number
;
commandId
:
string
;
commandArgs
:
any
[];
}
export
type
IRemoteTerminalProcessEvent
=
(
IRemoteTerminalProcessReadyEvent
|
IRemoteTerminalProcessTitleChangedEvent
|
IRemoteTerminalProcessDataEvent
|
IRemoteTerminalProcessExitEvent
|
IRemoteTerminalProcessExecCommandEvent
);
export
interface
IOnTerminalProcessEventArguments
{
id
:
number
;
}
export
class
RemoteTerminalChannelClient
{
constructor
(
private
readonly
_remoteAuthority
:
string
,
private
readonly
_channel
:
IChannel
,
@
IConfigurationService
private
readonly
_configurationService
:
IConfigurationService
,
@
IWorkspaceContextService
private
readonly
_workspaceContextService
:
IWorkspaceContextService
,
@
IConfigurationResolverService
private
readonly
_resolverService
:
IConfigurationResolverService
,
@
IEnvironmentVariableService
private
readonly
_environmentVariableService
:
IEnvironmentVariableService
,
@
IRemoteAuthorityResolverService
private
readonly
_remoteAuthorityResolverService
:
IRemoteAuthorityResolverService
,
@
ILogService
private
readonly
_logService
:
ILogService
,
@
IEditorService
private
readonly
_editorService
:
IEditorService
,
)
{
}
private
_readSingleTemrinalConfiguration
<
T
>
(
key
:
string
):
ISingleTerminalConfiguration
<
T
>
{
const
result
=
this
.
_configurationService
.
inspect
<
T
>
(
key
);
return
{
userValue
:
result
.
userValue
,
value
:
result
.
value
,
defaultValue
:
result
.
defaultValue
,
};
}
public
async
createTerminalProcess
(
shellLaunchConfig
:
IShellLaunchConfigDto
,
activeWorkspaceRootUri
:
URI
|
undefined
,
cols
:
number
,
rows
:
number
,
isWorkspaceShellAllowed
:
boolean
):
Promise
<
ICreateTerminalProcessResult
>
{
const
terminalConfig
=
this
.
_configurationService
.
getValue
<
ITerminalConfiguration
>
(
TERMINAL_CONFIG_SECTION
);
const
configuration
:
ICompleteTerminalConfiguration
=
{
'
terminal.integrated.automationShell.windows
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.automationShell.windows
'
),
'
terminal.integrated.automationShell.osx
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.automationShell.osx
'
),
'
terminal.integrated.automationShell.linux
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.automationShell.linux
'
),
'
terminal.integrated.shell.windows
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.shell.windows
'
),
'
terminal.integrated.shell.osx
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.shell.osx
'
),
'
terminal.integrated.shell.linux
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.shell.linux
'
),
'
terminal.integrated.shellArgs.windows
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.shellArgs.windows
'
),
'
terminal.integrated.shellArgs.osx
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.shellArgs.osx
'
),
'
terminal.integrated.shellArgs.linux
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.shellArgs.linux
'
),
'
terminal.integrated.env.windows
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.env.windows
'
),
'
terminal.integrated.env.osx
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.env.osx
'
),
'
terminal.integrated.env.linux
'
:
this
.
_readSingleTemrinalConfiguration
(
'
terminal.integrated.env.linux
'
),
'
terminal.integrated.inheritEnv
'
:
terminalConfig
.
inheritEnv
,
'
terminal.integrated.cwd
'
:
terminalConfig
.
cwd
,
'
terminal.integrated.detectLocale
'
:
terminalConfig
.
detectLocale
,
};
// We will use the resolver service to resolve all the variables in the config / launch config
// But then we will keep only some variables, since the rest need to be resolved on the remote side
const
resolvedVariables
=
Object
.
create
(
null
);
const
lastActiveWorkspace
=
activeWorkspaceRootUri
?
withNullAsUndefined
(
this
.
_workspaceContextService
.
getWorkspaceFolder
(
activeWorkspaceRootUri
))
:
undefined
;
let
allResolvedVariables
:
Map
<
string
,
string
>
|
undefined
=
undefined
;
try
{
allResolvedVariables
=
await
this
.
_resolverService
.
resolveWithInteraction
(
lastActiveWorkspace
,
{
shellLaunchConfig
,
configuration
});
}
catch
(
err
)
{
this
.
_logService
.
error
(
err
);
}
if
(
allResolvedVariables
)
{
for
(
const
[
name
,
value
]
of
allResolvedVariables
.
entries
())
{
if
(
/^config:/
.
test
(
name
)
||
name
===
'
selectedText
'
||
name
===
'
lineNumber
'
)
{
resolvedVariables
[
name
]
=
value
;
}
}
}
const
envVariableCollections
:
ITerminalEnvironmentVariableCollections
=
[];
for
(
const
[
k
,
v
]
of
this
.
_environmentVariableService
.
collections
.
entries
())
{
envVariableCollections
.
push
([
k
,
serializeEnvironmentVariableCollection
(
v
.
map
)]);
}
const
resolverResult
=
await
this
.
_remoteAuthorityResolverService
.
resolveAuthority
(
this
.
_remoteAuthority
);
const
resolverEnv
=
resolverResult
.
options
&&
resolverResult
.
options
.
extensionHostEnv
;
const
workspaceFolders
=
this
.
_workspaceContextService
.
getWorkspace
().
folders
;
const
activeWorkspaceFolder
=
activeWorkspaceRootUri
?
this
.
_workspaceContextService
.
getWorkspaceFolder
(
activeWorkspaceRootUri
)
:
null
;
const
activeFileResource
=
EditorResourceAccessor
.
getOriginalUri
(
this
.
_editorService
.
activeEditor
,
{
supportSideBySide
:
SideBySideEditor
.
PRIMARY
,
filterByScheme
:
[
Schemas
.
file
,
Schemas
.
userData
,
Schemas
.
vscodeRemote
]
});
const
args
:
ICreateTerminalProcessArguments
=
{
configuration
,
resolvedVariables
,
envVariableCollections
,
shellLaunchConfig
,
workspaceFolders
,
activeWorkspaceFolder
,
activeFileResource
,
cols
,
rows
,
isWorkspaceShellAllowed
,
resolverEnv
};
return
await
this
.
_channel
.
call
<
ICreateTerminalProcessResult
>
(
'
$createTerminalProcess
'
,
args
);
}
public
async
startTerminalProcess
(
terminalId
:
number
):
Promise
<
ITerminalLaunchError
|
void
>
{
const
args
:
IStartTerminalProcessArguments
=
{
id
:
terminalId
};
return
this
.
_channel
.
call
<
ITerminalLaunchError
|
void
>
(
'
$startTerminalProcess
'
,
args
);
}
public
onTerminalProcessEvent
(
terminalId
:
number
):
Event
<
IRemoteTerminalProcessEvent
>
{
const
args
:
IOnTerminalProcessEventArguments
=
{
id
:
terminalId
};
return
this
.
_channel
.
listen
<
IRemoteTerminalProcessEvent
>
(
'
$onTerminalProcessEvent
'
,
args
);
}
public
sendInputToTerminalProcess
(
id
:
number
,
data
:
string
):
Promise
<
void
>
{
const
args
:
ISendInputToTerminalProcessArguments
=
{
id
,
data
};
return
this
.
_channel
.
call
<
void
>
(
'
$sendInputToTerminalProcess
'
,
args
);
}
public
shutdownTerminalProcess
(
id
:
number
,
immediate
:
boolean
):
Promise
<
void
>
{
const
args
:
IShutdownTerminalProcessArguments
=
{
id
,
immediate
};
return
this
.
_channel
.
call
<
void
>
(
'
$shutdownTerminalProcess
'
,
args
);
}
public
resizeTerminalProcess
(
id
:
number
,
cols
:
number
,
rows
:
number
):
Promise
<
void
>
{
const
args
:
IResizeTerminalProcessArguments
=
{
id
,
cols
,
rows
};
return
this
.
_channel
.
call
<
void
>
(
'
$resizeTerminalProcess
'
,
args
);
}
public
getTerminalInitialCwd
(
id
:
number
):
Promise
<
string
>
{
const
args
:
IGetTerminalInitialCwdArguments
=
{
id
};
return
this
.
_channel
.
call
<
string
>
(
'
$getTerminalInitialCwd
'
,
args
);
}
public
getTerminalCwd
(
id
:
number
):
Promise
<
string
>
{
const
args
:
IGetTerminalCwdArguments
=
{
id
};
return
this
.
_channel
.
call
<
string
>
(
'
$getTerminalCwd
'
,
args
);
}
public
sendCommandResultToTerminalProcess
(
id
:
number
,
reqId
:
number
,
isError
:
boolean
,
payload
:
any
):
Promise
<
void
>
{
const
args
:
ISendCommandResultToTerminalProcessArguments
=
{
id
,
reqId
,
isError
,
payload
};
return
this
.
_channel
.
call
<
void
>
(
'
$sendCommandResultToTerminalProcess
'
,
args
);
}
}
src/vs/workbench/contrib/terminal/node/terminal.ts
浏览文件 @
a5c2f2ef
...
...
@@ -16,27 +16,27 @@ import { normalize, basename } from 'vs/base/common/path';
* shell that the terminal uses by default.
* @param p The platform to detect the shell of.
*/
export
function
getSystemShell
(
p
:
platform
.
Platform
):
string
{
export
function
getSystemShell
(
p
:
platform
.
Platform
,
environment
:
platform
.
IProcessEnvironment
=
process
.
env
as
platform
.
IProcessEnvironment
):
string
{
if
(
p
===
platform
.
Platform
.
Windows
)
{
if
(
platform
.
isWindows
)
{
return
getSystemShellWindows
();
return
getSystemShellWindows
(
environment
);
}
// Don't detect Windows shell when not on Windows
return
processes
.
getWindowsShell
();
return
processes
.
getWindowsShell
(
environment
);
}
// Only use $SHELL for the current OS
if
(
platform
.
isLinux
&&
p
===
platform
.
Platform
.
Mac
||
platform
.
isMacintosh
&&
p
===
platform
.
Platform
.
Linux
)
{
return
'
/bin/bash
'
;
}
return
getSystemShellUnixLike
();
return
getSystemShellUnixLike
(
environment
);
}
let
_TERMINAL_DEFAULT_SHELL_UNIX_LIKE
:
string
|
null
=
null
;
function
getSystemShellUnixLike
():
string
{
function
getSystemShellUnixLike
(
environment
:
platform
.
IProcessEnvironment
):
string
{
if
(
!
_TERMINAL_DEFAULT_SHELL_UNIX_LIKE
)
{
let
unixLikeTerminal
=
'
sh
'
;
if
(
!
platform
.
isWindows
&&
process
.
env
.
SHELL
)
{
unixLikeTerminal
=
process
.
env
.
SHELL
;
if
(
!
platform
.
isWindows
&&
environment
.
SHELL
)
{
unixLikeTerminal
=
environment
.
SHELL
;
// Some systems have $SHELL set to /bin/false which breaks the terminal
if
(
unixLikeTerminal
===
'
/bin/false
'
)
{
unixLikeTerminal
=
'
/bin/bash
'
;
...
...
@@ -51,12 +51,12 @@ function getSystemShellUnixLike(): string {
}
let
_TERMINAL_DEFAULT_SHELL_WINDOWS
:
string
|
null
=
null
;
function
getSystemShellWindows
():
string
{
function
getSystemShellWindows
(
environment
:
platform
.
IProcessEnvironment
):
string
{
if
(
!
_TERMINAL_DEFAULT_SHELL_WINDOWS
)
{
const
isAtLeastWindows10
=
platform
.
isWindows
&&
parseFloat
(
os
.
release
())
>=
10
;
const
is32ProcessOn64Windows
=
process
.
env
.
hasOwnProperty
(
'
PROCESSOR_ARCHITEW6432
'
);
const
powerShellPath
=
`
${
process
.
env
.
windir
}
\
\$
{is32ProcessOn64Windows ? 'Sysnative' : 'System32'}\\WindowsPowerShell\\v1.0\\powershell.exe`
;
_TERMINAL_DEFAULT_SHELL_WINDOWS
=
isAtLeastWindows10
?
powerShellPath
:
processes
.
getWindowsShell
();
const
is32ProcessOn64Windows
=
environment
.
hasOwnProperty
(
'
PROCESSOR_ARCHITEW6432
'
);
const
powerShellPath
=
`
${
environment
.
windir
}
\
\$
{is32ProcessOn64Windows ? 'Sysnative' : 'System32'}\\WindowsPowerShell\\v1.0\\powershell.exe`
;
_TERMINAL_DEFAULT_SHELL_WINDOWS
=
isAtLeastWindows10
?
powerShellPath
:
processes
.
getWindowsShell
(
environment
);
}
return
_TERMINAL_DEFAULT_SHELL_WINDOWS
;
}
...
...
src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts
浏览文件 @
a5c2f2ef
...
...
@@ -10,7 +10,7 @@ import { isString } from 'vs/base/common/types';
let
mainProcessParentEnv
:
IProcessEnvironment
|
undefined
;
export
async
function
getMainProcessParentEnv
():
Promise
<
IProcessEnvironment
>
{
export
async
function
getMainProcessParentEnv
(
baseEnvironment
:
IProcessEnvironment
=
process
.
env
as
IProcessEnvironment
):
Promise
<
IProcessEnvironment
>
{
if
(
mainProcessParentEnv
)
{
return
mainProcessParentEnv
;
}
...
...
@@ -65,15 +65,15 @@ export async function getMainProcessParentEnv(): Promise<IProcessEnvironment> {
'
TMPDIR
'
];
rootEnvVars
.
forEach
(
k
=>
{
if
(
process
.
env
[
k
])
{
mainProcessParentEnv
!
[
k
]
=
process
.
env
[
k
]
!
;
if
(
baseEnvironment
[
k
])
{
mainProcessParentEnv
!
[
k
]
=
baseEnvironment
[
k
]
!
;
}
});
}
// TODO: Windows should return a fresh environment block, might need native code?
if
(
isWindows
)
{
mainProcessParentEnv
=
process
.
env
as
IProcess
Environment
;
mainProcessParentEnv
=
base
Environment
;
}
return
mainProcessParentEnv
!
;
...
...
src/vs/workbench/workbench.common.main.ts
浏览文件 @
a5c2f2ef
...
...
@@ -80,6 +80,7 @@ import 'vs/workbench/services/extensionRecommendations/common/workspaceExtension
import
'
vs/workbench/services/notification/common/notificationService
'
;
import
'
vs/workbench/services/userDataSync/common/userDataSyncUtil
'
;
import
'
vs/workbench/services/remote/common/remoteExplorerService
'
;
import
'
vs/workbench/contrib/terminal/browser/remoteTerminalService
'
;
import
'
vs/workbench/services/workingCopy/common/workingCopyService
'
;
import
'
vs/workbench/services/workingCopy/common/workingCopyFileService
'
;
import
'
vs/workbench/services/filesConfiguration/common/filesConfigurationService
'
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录