Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
8d4466df
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,发现更多精彩内容 >>
未验证
提交
8d4466df
编写于
6月 19, 2018
作者:
D
Daniel Imms
提交者:
GitHub
6月 19, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #52143 from Microsoft/46192_terminal_renderer
Terminal renderer and activeTerminal APIs
上级
f7e80c35
1558fd55
变更
22
隐藏空白更改
内联
并排
Showing
22 changed file
with
856 addition
and
248 deletion
+856
-248
extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts
...ns/vscode-api-tests/src/singlefolder-tests/window.test.ts
+132
-26
src/vs/vscode.proposed.d.ts
src/vs/vscode.proposed.d.ts
+135
-1
src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts
...rkbench/api/electron-browser/mainThreadTerminalService.ts
+63
-12
src/vs/workbench/api/node/extHost.api.impl.ts
src/vs/workbench/api/node/extHost.api.impl.ts
+9
-0
src/vs/workbench/api/node/extHost.protocol.ts
src/vs/workbench/api/node/extHost.protocol.ts
+12
-0
src/vs/workbench/api/node/extHostTerminalService.ts
src/vs/workbench/api/node/extHostTerminalService.ts
+224
-55
src/vs/workbench/parts/terminal/browser/terminalFindWidget.ts
...vs/workbench/parts/terminal/browser/terminalFindWidget.ts
+3
-4
src/vs/workbench/parts/terminal/browser/terminalTab.ts
src/vs/workbench/parts/terminal/browser/terminalTab.ts
+1
-1
src/vs/workbench/parts/terminal/browser/terminalWidgetManager.ts
...workbench/parts/terminal/browser/terminalWidgetManager.ts
+9
-1
src/vs/workbench/parts/terminal/common/terminal.ts
src/vs/workbench/parts/terminal/common/terminal.ts
+80
-29
src/vs/workbench/parts/terminal/common/terminalColorRegistry.ts
.../workbench/parts/terminal/common/terminalColorRegistry.ts
+3
-3
src/vs/workbench/parts/terminal/common/terminalService.ts
src/vs/workbench/parts/terminal/common/terminalService.ts
+10
-2
src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts
.../parts/terminal/electron-browser/terminal.contribution.ts
+2
-2
src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts
...kbench/parts/terminal/electron-browser/terminalActions.ts
+17
-16
src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts
...h/parts/terminal/electron-browser/terminalConfigHelper.ts
+7
-7
src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts
...bench/parts/terminal/electron-browser/terminalInstance.ts
+108
-58
src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts
...ch/parts/terminal/electron-browser/terminalLinkHandler.ts
+2
-1
src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts
...orkbench/parts/terminal/electron-browser/terminalPanel.ts
+8
-8
src/vs/workbench/parts/terminal/electron-browser/terminalService.ts
...kbench/parts/terminal/electron-browser/terminalService.ts
+6
-2
src/vs/workbench/parts/terminal/node/terminalCommandTracker.ts
...s/workbench/parts/terminal/node/terminalCommandTracker.ts
+8
-3
src/vs/workbench/parts/terminal/node/terminalEnvironment.ts
src/vs/workbench/parts/terminal/node/terminalEnvironment.ts
+2
-2
src/vs/workbench/parts/terminal/node/terminalProcess.ts
src/vs/workbench/parts/terminal/node/terminalProcess.ts
+15
-15
未找到文件。
extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts
浏览文件 @
8d4466df
...
...
@@ -6,7 +6,7 @@
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
{
workspace
,
window
,
commands
,
ViewColumn
,
TextEditorViewColumnChangeEvent
,
Uri
,
Selection
,
Position
,
CancellationTokenSource
,
TextEditorSelectionChangeKind
}
from
'
vscode
'
;
import
{
workspace
,
window
,
commands
,
ViewColumn
,
TextEditorViewColumnChangeEvent
,
Uri
,
Selection
,
Position
,
CancellationTokenSource
,
TextEditorSelectionChangeKind
,
Terminal
}
from
'
vscode
'
;
import
{
join
}
from
'
path
'
;
import
{
closeAllEditors
,
pathEquals
,
createRandomFile
}
from
'
../utils
'
;
...
...
@@ -557,37 +557,143 @@ suite('window namespace tests', () => {
});
});
test
(
'
createTerminal, Terminal.name
'
,
()
=>
{
const
terminal
=
window
.
createTerminal
(
'
foo
'
);
assert
.
equal
(
terminal
.
name
,
'
foo
'
);
suite
(
'
Terminal
'
,
()
=>
{
test
(
'
createTerminal, Terminal.name
'
,
()
=>
{
const
terminal
=
window
.
createTerminal
(
'
foo
'
);
assert
.
equal
(
terminal
.
name
,
'
foo
'
);
assert
.
throws
(()
=>
{
(
<
any
>
terminal
).
name
=
'
bar
'
;
},
'
Terminal.name should be readonly
'
);
});
assert
.
throws
(()
=>
{
(
<
any
>
terminal
).
name
=
'
bar
'
;
},
'
Terminal.name should be readonly
'
);
terminal
.
dispose
();
});
test
(
'
terminal, sendText immediately after createTerminal should not throw
'
,
()
=>
{
const
terminal
=
window
.
createTerminal
();
assert
.
doesNotThrow
(
terminal
.
sendText
.
bind
(
terminal
,
'
echo "foo"
'
));
});
test
(
'
sendText immediately after createTerminal should not throw
'
,
()
=>
{
const
terminal
=
window
.
createTerminal
();
assert
.
doesNotThrow
(
terminal
.
sendText
.
bind
(
terminal
,
'
echo "foo"
'
));
terminal
.
dispose
();
});
test
(
'
terminal, onDidCloseTerminal event fires when terminal is disposed
'
,
(
done
)
=>
{
const
terminal
=
window
.
createTerminal
();
window
.
onDidCloseTerminal
((
eventTerminal
)
=>
{
assert
.
equal
(
terminal
,
eventTerminal
);
done
();
test
(
'
onDidCloseTerminal event fires when terminal is disposed
'
,
(
done
)
=>
{
const
terminal
=
window
.
createTerminal
();
const
reg
=
window
.
onDidCloseTerminal
((
eventTerminal
)
=>
{
assert
.
equal
(
terminal
,
eventTerminal
);
reg
.
dispose
();
done
();
});
terminal
.
dispose
();
});
terminal
.
dispose
();
});
test
(
'
terminal, processId immediately after createTerminal should fetch the pid
'
,
(
done
)
=>
{
window
.
createTerminal
().
processId
.
then
(
id
=>
{
assert
.
ok
(
id
>
0
);
done
();
test
(
'
processId immediately after createTerminal should fetch the pid
'
,
(
done
)
=>
{
const
terminal
=
window
.
createTerminal
();
terminal
.
processId
.
then
(
id
=>
{
assert
.
ok
(
id
>
0
);
terminal
.
dispose
();
done
();
});
});
test
(
'
name in constructor should set terminal.name
'
,
()
=>
{
const
terminal
=
window
.
createTerminal
(
'
a
'
);
assert
.
equal
(
terminal
.
name
,
'
a
'
);
terminal
.
dispose
();
});
test
(
'
onDidOpenTerminal should fire when a terminal is created
'
,
(
done
)
=>
{
const
reg1
=
window
.
onDidOpenTerminal
(
term
=>
{
assert
.
equal
(
term
.
name
,
'
b
'
);
reg1
.
dispose
();
const
reg2
=
window
.
onDidCloseTerminal
(()
=>
{
reg2
.
dispose
();
done
();
});
terminal
.
dispose
();
});
const
terminal
=
window
.
createTerminal
(
'
b
'
);
});
test
(
'
createTerminalRenderer should fire onDidOpenTerminal and onDidCloseTerminal
'
,
(
done
)
=>
{
const
reg1
=
window
.
onDidOpenTerminal
(
term
=>
{
assert
.
equal
(
term
.
name
,
'
c
'
);
reg1
.
dispose
();
const
reg2
=
window
.
onDidCloseTerminal
(()
=>
{
reg2
.
dispose
();
done
();
});
term
.
dispose
();
});
window
.
createTerminalRenderer
(
'
c
'
);
});
});
test
(
'
terminal, name should set terminal.name
'
,
()
=>
{
assert
.
equal
(
window
.
createTerminal
(
'
foo
'
).
name
,
'
foo
'
);
test
(
'
terminal renderers should get maximum dimensions set when shown
'
,
(
done
)
=>
{
let
terminal
:
Terminal
;
const
reg1
=
window
.
onDidOpenTerminal
(
term
=>
{
reg1
.
dispose
();
term
.
show
();
terminal
=
term
;
});
const
renderer
=
window
.
createTerminalRenderer
(
'
foo
'
);
const
reg2
=
renderer
.
onDidChangeMaximumDimensions
(
dimensions
=>
{
assert
.
ok
(
dimensions
.
cols
>
0
);
assert
.
ok
(
dimensions
.
rows
>
0
);
reg2
.
dispose
();
const
reg3
=
window
.
onDidCloseTerminal
(()
=>
{
reg3
.
dispose
();
done
();
});
terminal
.
dispose
();
});
});
test
(
'
TerminalRenderer.write should fire Terminal.onData
'
,
(
done
)
=>
{
const
reg1
=
window
.
onDidOpenTerminal
(
terminal
=>
{
reg1
.
dispose
();
const
reg2
=
terminal
.
onData
(
data
=>
{
assert
.
equal
(
data
,
'
bar
'
);
reg2
.
dispose
();
const
reg3
=
window
.
onDidCloseTerminal
(()
=>
{
reg3
.
dispose
();
done
();
});
terminal
.
dispose
();
});
renderer
.
write
(
'
bar
'
);
});
const
renderer
=
window
.
createTerminalRenderer
(
'
foo
'
);
});
test
(
'
Terminal.sendText should fire Termnial.onInput
'
,
(
done
)
=>
{
const
reg1
=
window
.
onDidOpenTerminal
(
terminal
=>
{
reg1
.
dispose
();
const
reg2
=
renderer
.
onInput
(
data
=>
{
assert
.
equal
(
data
,
'
bar
'
);
reg2
.
dispose
();
const
reg3
=
window
.
onDidCloseTerminal
(()
=>
{
reg3
.
dispose
();
done
();
});
terminal
.
dispose
();
});
terminal
.
sendText
(
'
bar
'
,
false
);
});
const
renderer
=
window
.
createTerminalRenderer
(
'
foo
'
);
});
test
(
'
onDidChangeActiveTerminal should fire when new terminals are created
'
,
(
done
)
=>
{
const
reg1
=
window
.
onDidChangeActiveTerminal
((
active
:
Terminal
|
undefined
)
=>
{
assert
.
equal
(
active
,
terminal
);
assert
.
equal
(
active
,
window
.
activeTerminal
);
reg1
.
dispose
();
const
reg2
=
window
.
onDidChangeActiveTerminal
((
active
:
Terminal
|
undefined
)
=>
{
assert
.
equal
(
active
,
undefined
);
assert
.
equal
(
active
,
window
.
activeTerminal
);
reg2
.
dispose
();
done
();
});
terminal
.
dispose
();
});
const
terminal
=
window
.
createTerminal
();
terminal
.
show
();
});
});
});
src/vs/vscode.proposed.d.ts
浏览文件 @
8d4466df
...
...
@@ -339,11 +339,123 @@ declare module 'vscode' {
/**
* Fires when the terminal's pty slave pseudo-device is written to. In other words, this
* provides access to the raw data stream from the process running within the terminal,
* including
ANSI
sequences.
* including
VT
sequences.
*/
onData
:
Event
<
string
>
;
}
/**
* Represents the dimensions of a terminal.
*/
export
interface
TerminalDimensions
{
/**
* The number of columns in the terminal.
*/
cols
:
number
;
/**
* The number of rows in the terminal.
*/
rows
:
number
;
}
/**
* Represents a terminal without a process where all interaction and output in the terminal is
* controlled by an extension. This is similar to an output window but has the same VT sequence
* compatility as the regular terminal.
*
* Note that an instance of [Terminal](#Terminal) will be created when a TerminalRenderer is
* created with all its APIs available for use by extensions. When using the Terminal object
* of a TerminalRenderer it acts just like normal only the extension that created the
* TerminalRenderer essentially acts as a process. For example when an
* [Terminal.onData](#Terminal.onData) listener is registered, that will fire when
* [TerminalRenderer.write](#TerminalRenderer.write) is called. Similarly when
* [Terminal.sendText](#Terminal.sendText) is triggered that will fire the
* [TerminalRenderer.onInput](#TerminalRenderer.onInput) event.
*
* **Example:** Create a terminal renderer, show it and write hello world in red
* ```typescript
* const renderer = window.createTerminalRenderer('foo');
* renderer.terminal.then(t => t.show());
* renderer.write('\x1b[31mHello world\x1b[0m');
* ```
*/
export
interface
TerminalRenderer
{
/**
* The name of the terminal, this will appear in the terminal selector.
*/
name
:
string
;
/**
* The dimensions of the terminal, the rows and columns of the terminal can only be set to
* a value smaller than the maximum value, if this is undefined the terminal will auto fit
* to the maximum value [maximumDimensions](TerminalRenderer.maximumDimensions).
*
* **Example:** Override the dimensions of a TerminalRenderer to 20 columns and 10 rows
* ```typescript
* terminalRenderer.dimensions = {
* cols: 20,
* rows: 10
* };
* ```
*/
dimensions
:
TerminalDimensions
;
/**
* The maximum dimensions of the terminal, this will be undefined immediately after a
* terminal renderer is created and also until the terminal becomes visible in the UI.
* Listen to [onDidChangeMaximumDimensions](TerminalRenderer.onDidChangeMaximumDimensions)
* to get notified when this value changes.
*/
readonly
maximumDimensions
:
TerminalDimensions
;
/**
* The corressponding [Terminal](#Terminal) for this TerminalRenderer.
*/
readonly
terminal
:
Thenable
<
Terminal
>
;
/**
* Write text to the terminal. Unlike [Terminal.sendText](#Terminal.sendText) which sends
* text to the underlying _process_, this will write the text to the terminal itself.
*
* **Example:** Write red text to the terminal
* ```typescript
* terminalRenderer.write('\x1b[31mHello world\x1b[0m');
* ```
*
* **Example:** Move the cursor to the 10th row and 20th column and write an asterisk
* ```typescript
* terminalRenderer.write('\x1b[10;20H*');
* ```
*
* @param text The text to write.
*/
write
(
text
:
string
):
void
;
/**
* An event which fires on keystrokes in the terminal or when an extension calls
* [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their
* corresponding VT sequence representation.
*
* **Example:** Simulate interaction with the terminal from an outside extension or a
* workbench command such as `workbench.action.terminal.runSelectedText`
* ```typescript
* const terminalRenderer = window.createTerminalRenderer('test');
* terminalRenderer.onInput(data => {
* cosole.log(data); // 'Hello world'
* });
* terminalRenderer.terminal.then(t => t.sendText('Hello world'));
* ```
*/
onInput
:
Event
<
string
>
;
/**
* An event which fires when the [maximum dimensions](#TerminalRenderer.maimumDimensions) of
* the terminal renderer change.
*/
onDidChangeMaximumDimensions
:
Event
<
TerminalDimensions
>
;
}
export
namespace
window
{
/**
* The currently opened terminals or an empty array.
...
...
@@ -352,11 +464,33 @@ declare module 'vscode' {
*/
export
let
terminals
:
Terminal
[];
/**
* The currently active terminal or `undefined`. The active terminal is the one that
* currently has focus or most recently had focus.
*
* @readonly
*/
export
let
activeTerminal
:
Terminal
|
undefined
;
/**
* An [event](#Event) which fires when the [active terminal](#window.activeTerminal)
* has changed. *Note* that the event also fires when the active editor changes
* to `undefined`.
*/
export
const
onDidChangeActiveTerminal
:
Event
<
Terminal
|
undefined
>
;
/**
* An [event](#Event) which fires when a terminal has been created, either through the
* [createTerminal](#window.createTerminal) API or commands.
*/
export
const
onDidOpenTerminal
:
Event
<
Terminal
>
;
/**
* Create a [TerminalRenderer](#TerminalRenderer).
*
* @param name The name of the terminal renderer, this shows up in the terminal selector.
*/
export
function
createTerminalRenderer
(
name
:
string
):
TerminalRenderer
;
}
//#endregion
...
...
src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts
浏览文件 @
8d4466df
...
...
@@ -5,7 +5,7 @@
'
use strict
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
ITerminalService
,
ITerminalInstance
,
IShellLaunchConfig
,
ITerminalProcessExtHostProxy
,
ITerminalProcessExtHostRequest
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
ITerminalService
,
ITerminalInstance
,
IShellLaunchConfig
,
ITerminalProcessExtHostProxy
,
ITerminalProcessExtHostRequest
,
ITerminalDimensions
,
EXT_HOST_CREATION_DELAY
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
ExtHostContext
,
ExtHostTerminalServiceShape
,
MainThreadTerminalServiceShape
,
MainContext
,
IExtHostContext
,
ShellLaunchConfigDto
}
from
'
../node/extHost.protocol
'
;
import
{
extHostNamedCustomer
}
from
'
vs/workbench/api/electron-browser/extHostCustomers
'
;
...
...
@@ -16,22 +16,23 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
private
_proxy
:
ExtHostTerminalServiceShape
;
private
_toDispose
:
IDisposable
[]
=
[];
private
_terminalProcesses
:
{
[
id
:
number
]:
ITerminalProcessExtHostProxy
}
=
{};
private
_dataListeners
:
{
[
id
:
number
]:
IDisposable
}
=
{};
constructor
(
extHostContext
:
IExtHostContext
,
@
ITerminalService
private
terminalService
:
ITerminalService
)
{
this
.
_proxy
=
extHostContext
.
getProxy
(
ExtHostContext
.
ExtHostTerminalService
);
this
.
_toDispose
.
push
(
terminalService
.
onInstanceCreated
((
terminalI
nstance
)
=>
{
this
.
_toDispose
.
push
(
terminalService
.
onInstanceCreated
((
i
nstance
)
=>
{
// Delay this message so the TerminalInstance constructor has a chance to finish and
// return the ID normally to the extension host. The ID that is passed here will be used
// to register non-extension API terminals in the extension host.
setTimeout
(()
=>
this
.
_onTerminalOpened
(
terminalInstance
),
100
);
setTimeout
(()
=>
this
.
_onTerminalOpened
(
instance
),
EXT_HOST_CREATION_DELAY
);
}));
this
.
_toDispose
.
push
(
terminalService
.
onInstanceDisposed
(
terminalInstance
=>
this
.
_onTerminalDisposed
(
terminalInstance
)));
this
.
_toDispose
.
push
(
terminalService
.
onInstanceProcessIdReady
(
terminalInstance
=>
this
.
_onTerminalProcessIdReady
(
terminalInstance
)));
this
.
_toDispose
.
push
(
terminalService
.
onInstanceDisposed
(
instance
=>
this
.
_onTerminalDisposed
(
instance
)));
this
.
_toDispose
.
push
(
terminalService
.
onInstanceProcessIdReady
(
instance
=>
this
.
_onTerminalProcessIdReady
(
instance
)));
this
.
_toDispose
.
push
(
terminalService
.
onInstanceDimensionsChanged
(
instance
=>
this
.
_onInstanceDimensionsChanged
(
instance
)));
this
.
_toDispose
.
push
(
terminalService
.
onInstanceRequestExtHostProcess
(
request
=>
this
.
_onTerminalRequestExtHostProcess
(
request
)));
this
.
_toDispose
.
push
(
terminalService
.
onActiveInstanceChanged
(
instance
=>
this
.
_onActiveTerminalChanged
(
instance
?
instance
.
id
:
undefined
)));
// Set initial ext host state
this
.
terminalService
.
terminalInstances
.
forEach
(
t
=>
{
...
...
@@ -60,8 +61,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
return
TPromise
.
as
(
this
.
terminalService
.
createTerminal
(
shellLaunchConfig
).
id
);
}
public
$createTerminalRenderer
(
name
:
string
):
TPromise
<
number
>
{
const
instance
=
this
.
terminalService
.
createTerminalRenderer
(
name
);
return
TPromise
.
as
(
instance
.
id
);
}
public
$show
(
terminalId
:
number
,
preserveFocus
:
boolean
):
void
{
le
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
cons
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
)
{
this
.
terminalService
.
setActiveInstance
(
terminalInstance
);
this
.
terminalService
.
showPanel
(
!
preserveFocus
);
...
...
@@ -75,31 +81,68 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
public
$dispose
(
terminalId
:
number
):
void
{
le
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
cons
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
)
{
terminalInstance
.
dispose
();
}
}
public
$terminalRendererWrite
(
terminalId
:
number
,
text
:
string
):
void
{
const
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
&&
terminalInstance
.
shellLaunchConfig
.
isRendererOnly
)
{
terminalInstance
.
write
(
text
);
}
}
public
$terminalRendererSetName
(
terminalId
:
number
,
name
:
string
):
void
{
const
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
&&
terminalInstance
.
shellLaunchConfig
.
isRendererOnly
)
{
terminalInstance
.
setTitle
(
name
,
false
);
}
}
public
$terminalRendererSetDimensions
(
terminalId
:
number
,
dimensions
:
ITerminalDimensions
):
void
{
const
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
&&
terminalInstance
.
shellLaunchConfig
.
isRendererOnly
)
{
terminalInstance
.
setDimensions
(
dimensions
);
}
}
public
$terminalRendererRegisterOnInputListener
(
terminalId
:
number
):
void
{
const
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
)
{
terminalInstance
.
addDisposable
(
terminalInstance
.
onRendererInput
(
data
=>
this
.
_onTerminalRendererInput
(
terminalId
,
data
)));
}
}
public
$sendText
(
terminalId
:
number
,
text
:
string
,
addNewLine
:
boolean
):
void
{
le
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
cons
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
)
{
terminalInstance
.
sendText
(
text
,
addNewLine
);
}
}
public
$registerOnDataListener
(
terminalId
:
number
):
void
{
le
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
cons
t
terminalInstance
=
this
.
terminalService
.
getInstanceFromId
(
terminalId
);
if
(
terminalInstance
)
{
this
.
_dataListeners
[
terminalId
]
=
terminalInstance
.
onData
(
data
=>
this
.
_onTerminalData
(
terminalId
,
data
));
terminalInstance
.
onDisposed
(
instance
=>
delete
this
.
_dataListeners
[
terminalId
]);
terminalInstance
.
addDisposable
(
terminalInstance
.
onData
(
data
=>
{
this
.
_onTerminalData
(
terminalId
,
data
);
}));
}
}
private
_onActiveTerminalChanged
(
terminalId
:
number
|
undefined
):
void
{
this
.
_proxy
.
$acceptActiveTerminalChanged
(
terminalId
);
}
private
_onTerminalData
(
terminalId
:
number
,
data
:
string
):
void
{
this
.
_proxy
.
$acceptTerminalProcessData
(
terminalId
,
data
);
}
private
_onTerminalRendererInput
(
terminalId
:
number
,
data
:
string
):
void
{
this
.
_proxy
.
$acceptTerminalRendererInput
(
terminalId
,
data
);
}
private
_onTerminalDisposed
(
terminalInstance
:
ITerminalInstance
):
void
{
this
.
_proxy
.
$acceptTerminalClosed
(
terminalInstance
.
id
);
}
...
...
@@ -112,6 +155,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this
.
_proxy
.
$acceptTerminalProcessId
(
terminalInstance
.
id
,
terminalInstance
.
processId
);
}
private
_onInstanceDimensionsChanged
(
instance
:
ITerminalInstance
):
void
{
// Only send the dimensions if the terminal is a renderer only as there is no API to access
// dimensions on a plain Terminal.
if
(
instance
.
shellLaunchConfig
.
isRendererOnly
)
{
this
.
_proxy
.
$acceptTerminalRendererDimensions
(
instance
.
id
,
instance
.
cols
,
instance
.
rows
);
}
}
private
_onTerminalRequestExtHostProcess
(
request
:
ITerminalProcessExtHostRequest
):
void
{
this
.
_terminalProcesses
[
request
.
proxy
.
terminalId
]
=
request
.
proxy
;
const
shellLaunchConfigDto
:
ShellLaunchConfigDto
=
{
...
...
src/vs/workbench/api/node/extHost.api.impl.ts
浏览文件 @
8d4466df
...
...
@@ -331,6 +331,9 @@ export function createApiFactory(
get
visibleTextEditors
()
{
return
extHostEditors
.
getVisibleTextEditors
();
},
get
activeTerminal
()
{
return
proposedApiFunction
(
extension
,
extHostTerminalService
.
activeTerminal
);
},
get
terminals
()
{
return
proposedApiFunction
(
extension
,
extHostTerminalService
.
terminals
);
},
...
...
@@ -372,6 +375,9 @@ export function createApiFactory(
onDidOpenTerminal
:
proposedApiFunction
(
extension
,
(
listener
,
thisArg
?,
disposables
?)
=>
{
return
extHostTerminalService
.
onDidOpenTerminal
(
listener
,
thisArg
,
disposables
);
}),
onDidChangeActiveTerminal
:
proposedApiFunction
(
extension
,
(
listener
,
thisArg
?,
disposables
?)
=>
{
return
extHostTerminalService
.
onDidChangeActiveTerminal
(
listener
,
thisArg
,
disposables
);
}),
get
state
()
{
return
extHostWindow
.
state
;
},
...
...
@@ -427,6 +433,9 @@ export function createApiFactory(
}
return
extHostTerminalService
.
createTerminal
(
<
string
>
nameOrOptions
,
shellPath
,
shellArgs
);
},
createTerminalRenderer
(
name
:
string
):
vscode
.
TerminalRenderer
{
return
extHostTerminalService
.
createTerminalRenderer
(
name
);
},
registerTreeDataProvider
(
viewId
:
string
,
treeDataProvider
:
vscode
.
TreeDataProvider
<
any
>
):
vscode
.
Disposable
{
return
extHostTreeViews
.
registerTreeDataProvider
(
viewId
,
treeDataProvider
);
},
...
...
src/vs/workbench/api/node/extHost.protocol.ts
浏览文件 @
8d4466df
...
...
@@ -49,6 +49,7 @@ import { ISingleEditOperation } from 'vs/editor/common/model';
import
{
IPatternInfo
,
IRawSearchQuery
,
IRawFileMatch2
,
ISearchCompleteStats
}
from
'
vs/platform/search/common/search
'
;
import
{
LogLevel
}
from
'
vs/platform/log/common/log
'
;
import
{
TaskExecutionDTO
,
TaskDTO
,
TaskHandleDTO
,
TaskFilterDTO
,
TaskProcessStartedDTO
,
TaskProcessEndedDTO
,
TaskSystemInfoDTO
}
from
'
vs/workbench/api/shared/tasks
'
;
import
{
ITerminalDimensions
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
export
interface
IEnvironment
{
isExtensionDevelopmentDebug
:
boolean
;
...
...
@@ -324,16 +325,24 @@ export interface MainThreadProgressShape extends IDisposable {
export
interface
MainThreadTerminalServiceShape
extends
IDisposable
{
$createTerminal
(
name
?:
string
,
shellPath
?:
string
,
shellArgs
?:
string
[],
cwd
?:
string
,
env
?:
{
[
key
:
string
]:
string
},
waitOnExit
?:
boolean
):
TPromise
<
number
>
;
$createTerminalRenderer
(
name
:
string
):
TPromise
<
number
>
;
$dispose
(
terminalId
:
number
):
void
;
$hide
(
terminalId
:
number
):
void
;
$sendText
(
terminalId
:
number
,
text
:
string
,
addNewLine
:
boolean
):
void
;
$show
(
terminalId
:
number
,
preserveFocus
:
boolean
):
void
;
$registerOnDataListener
(
terminalId
:
number
):
void
;
// Process
$sendProcessTitle
(
terminalId
:
number
,
title
:
string
):
void
;
$sendProcessData
(
terminalId
:
number
,
data
:
string
):
void
;
$sendProcessPid
(
terminalId
:
number
,
pid
:
number
):
void
;
$sendProcessExit
(
terminalId
:
number
,
exitCode
:
number
):
void
;
// Renderer
$terminalRendererSetName
(
terminalId
:
number
,
name
:
string
):
void
;
$terminalRendererSetDimensions
(
terminalId
:
number
,
dimensions
:
ITerminalDimensions
):
void
;
$terminalRendererWrite
(
terminalId
:
number
,
text
:
string
):
void
;
$terminalRendererRegisterOnInputListener
(
terminalId
:
number
):
void
;
}
export
interface
TransferQuickPickItems
extends
IQuickPickItem
{
...
...
@@ -841,8 +850,11 @@ export interface ShellLaunchConfigDto {
export
interface
ExtHostTerminalServiceShape
{
$acceptTerminalClosed
(
id
:
number
):
void
;
$acceptTerminalOpened
(
id
:
number
,
name
:
string
):
void
;
$acceptActiveTerminalChanged
(
id
:
number
|
null
):
void
;
$acceptTerminalProcessId
(
id
:
number
,
processId
:
number
):
void
;
$acceptTerminalProcessData
(
id
:
number
,
data
:
string
):
void
;
$acceptTerminalRendererInput
(
id
:
number
,
data
:
string
):
void
;
$acceptTerminalRendererDimensions
(
id
:
number
,
cols
:
number
,
rows
:
number
):
void
;
$createProcess
(
id
:
number
,
shellLaunchConfig
:
ShellLaunchConfigDto
,
cols
:
number
,
rows
:
number
):
void
;
$acceptProcessInput
(
id
:
number
,
data
:
string
):
void
;
$acceptProcessResize
(
id
:
number
,
cols
:
number
,
rows
:
number
):
void
;
...
...
src/vs/workbench/api/node/extHostTerminalService.ts
浏览文件 @
8d4466df
...
...
@@ -15,13 +15,64 @@ import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShap
import
{
IMessageFromTerminalProcess
}
from
'
vs/workbench/parts/terminal/node/terminal
'
;
import
{
ExtHostConfiguration
}
from
'
vs/workbench/api/node/extHostConfiguration
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
EXT_HOST_CREATION_DELAY
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
export
class
ExtHostTerminal
implements
vscode
.
Terminal
{
private
_name
:
string
;
private
_id
:
number
;
private
_proxy
:
MainThreadTerminalServiceShape
;
private
_disposed
:
boolean
;
private
_queuedRequests
:
ApiRequest
[];
const
RENDERER_NO_PROCESS_ID
=
-
1
;
export
class
BaseExtHostTerminal
{
public
_id
:
number
;
protected
_idPromise
:
Promise
<
number
>
;
private
_idPromiseComplete
:
(
value
:
number
)
=>
any
;
private
_disposed
:
boolean
=
false
;
private
_queuedRequests
:
ApiRequest
[]
=
[];
constructor
(
protected
_proxy
:
MainThreadTerminalServiceShape
,
id
?:
number
)
{
this
.
_idPromise
=
new
Promise
<
number
>
(
c
=>
{
if
(
id
!==
undefined
)
{
this
.
_id
=
id
;
c
(
id
);
}
else
{
this
.
_idPromiseComplete
=
c
;
}
});
}
public
dispose
():
void
{
if
(
!
this
.
_disposed
)
{
this
.
_disposed
=
true
;
this
.
_queueApiRequest
(
this
.
_proxy
.
$dispose
,
[]);
}
}
protected
_checkDisposed
()
{
if
(
this
.
_disposed
)
{
throw
new
Error
(
'
Terminal has already been disposed
'
);
}
}
protected
_queueApiRequest
(
callback
:
(...
args
:
any
[])
=>
void
,
args
:
any
[]):
void
{
const
request
:
ApiRequest
=
new
ApiRequest
(
callback
,
args
);
if
(
!
this
.
_id
)
{
this
.
_queuedRequests
.
push
(
request
);
return
;
}
request
.
run
(
this
.
_proxy
,
this
.
_id
);
}
protected
_runQueuedRequests
(
id
:
number
):
void
{
this
.
_id
=
id
;
this
.
_idPromiseComplete
(
id
);
this
.
_queuedRequests
.
forEach
((
r
)
=>
{
r
.
run
(
this
.
_proxy
,
this
.
_id
);
});
this
.
_queuedRequests
.
length
=
0
;
}
}
export
class
ExtHostTerminal
extends
BaseExtHostTerminal
implements
vscode
.
Terminal
{
private
_pidPromise
:
Promise
<
number
>
;
private
_pidPromiseComplete
:
(
value
:
number
)
=>
any
;
...
...
@@ -34,17 +85,17 @@ export class ExtHostTerminal implements vscode.Terminal {
constructor
(
proxy
:
MainThreadTerminalServiceShape
,
name
:
string
=
''
,
id
?:
number
private
_name
:
string
,
id
?:
number
,
pid
?:
number
)
{
this
.
_proxy
=
proxy
;
this
.
_name
=
name
;
if
(
id
)
{
this
.
_id
=
id
;
}
this
.
_queuedRequests
=
[];
super
(
proxy
,
id
);
this
.
_pidPromise
=
new
Promise
<
number
>
(
c
=>
{
this
.
_pidPromiseComplete
=
c
;
if
(
pid
===
RENDERER_NO_PROCESS_ID
)
{
c
(
undefined
);
}
else
{
this
.
_pidPromiseComplete
=
c
;
}
});
}
...
...
@@ -56,11 +107,7 @@ export class ExtHostTerminal implements vscode.Terminal {
waitOnExit
?:
boolean
):
void
{
this
.
_proxy
.
$createTerminal
(
this
.
_name
,
shellPath
,
shellArgs
,
cwd
,
env
,
waitOnExit
).
then
((
id
)
=>
{
this
.
_id
=
id
;
this
.
_queuedRequests
.
forEach
((
r
)
=>
{
r
.
run
(
this
.
_proxy
,
this
.
_id
);
});
this
.
_queuedRequests
=
[];
this
.
_runQueuedRequests
(
id
);
});
}
...
...
@@ -87,13 +134,6 @@ export class ExtHostTerminal implements vscode.Terminal {
this
.
_queueApiRequest
(
this
.
_proxy
.
$hide
,
[]);
}
public
dispose
():
void
{
if
(
!
this
.
_disposed
)
{
this
.
_disposed
=
true
;
this
.
_queueApiRequest
(
this
.
_proxy
.
$dispose
,
[]);
}
}
public
_setProcessId
(
processId
:
number
):
void
{
// The event may fire 2 times when the panel is restored
if
(
this
.
_pidPromiseComplete
)
{
...
...
@@ -105,34 +145,95 @@ export class ExtHostTerminal implements vscode.Terminal {
public
_fireOnData
(
data
:
string
):
void
{
this
.
_onData
.
fire
(
data
);
}
}
private
_queueApiRequest
(
callback
:
(...
args
:
any
[])
=>
void
,
args
:
any
[])
{
let
request
:
ApiRequest
=
new
ApiRequest
(
callback
,
args
);
if
(
!
this
.
_id
)
{
this
.
_queuedRequests
.
push
(
request
);
return
;
}
request
.
run
(
this
.
_proxy
,
this
.
_id
);
export
class
ExtHostTerminalRenderer
extends
BaseExtHostTerminal
implements
vscode
.
TerminalRenderer
{
public
get
name
():
string
{
return
this
.
_name
;
}
public
set
name
(
newName
:
string
)
{
this
.
_name
=
newName
;
this
.
_checkDisposed
();
this
.
_queueApiRequest
(
this
.
_proxy
.
$terminalRendererSetName
,
[
this
.
_name
]);
}
private
_checkDisposed
()
{
if
(
this
.
_disposed
)
{
throw
new
Error
(
'
Terminal has already been disposed
'
);
private
readonly
_onInput
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onInput
():
Event
<
string
>
{
this
.
_checkDisposed
();
this
.
_queueApiRequest
(
this
.
_proxy
.
$terminalRendererRegisterOnInputListener
,
[
this
.
_id
]);
// Tell the main side to start sending data if it's not already
// this._proxy.$terminalRendererRegisterOnDataListener(this._id);
return
this
.
_onInput
&&
this
.
_onInput
.
event
;
}
private
_dimensions
:
vscode
.
TerminalDimensions
|
undefined
;
public
get
dimensions
():
vscode
.
TerminalDimensions
{
return
this
.
_dimensions
;
}
public
set
dimensions
(
dimensions
:
vscode
.
TerminalDimensions
)
{
this
.
_checkDisposed
();
this
.
_dimensions
=
dimensions
;
this
.
_queueApiRequest
(
this
.
_proxy
.
$terminalRendererSetDimensions
,
[
dimensions
]);
}
private
_maximumDimensions
:
vscode
.
TerminalDimensions
;
public
get
maximumDimensions
():
vscode
.
TerminalDimensions
{
if
(
!
this
.
_maximumDimensions
)
{
return
undefined
;
}
return
{
rows
:
this
.
_maximumDimensions
.
rows
,
cols
:
this
.
_maximumDimensions
.
cols
};
}
private
readonly
_onDidChangeMaximumDimensions
:
Emitter
<
vscode
.
TerminalDimensions
>
=
new
Emitter
<
vscode
.
TerminalDimensions
>
();
public
get
onDidChangeMaximumDimensions
():
Event
<
vscode
.
TerminalDimensions
>
{
return
this
.
_onDidChangeMaximumDimensions
&&
this
.
_onDidChangeMaximumDimensions
.
event
;
}
public
get
terminal
():
Promise
<
ExtHostTerminal
>
{
return
this
.
_idPromise
.
then
(
id
=>
this
.
_fetchTerminal
(
id
));
}
constructor
(
proxy
:
MainThreadTerminalServiceShape
,
private
_name
:
string
,
private
_fetchTerminal
:
(
id
:
number
)
=>
Promise
<
ExtHostTerminal
>
)
{
super
(
proxy
);
this
.
_proxy
.
$createTerminalRenderer
(
this
.
_name
).
then
(
id
=>
{
this
.
_runQueuedRequests
(
id
);
});
}
public
write
(
data
:
string
):
void
{
this
.
_checkDisposed
();
this
.
_queueApiRequest
(
this
.
_proxy
.
$terminalRendererWrite
,
[
data
]);
}
public
_fireOnInput
(
data
:
string
):
void
{
this
.
_onInput
.
fire
(
data
);
}
public
_setMaximumDimensions
(
cols
:
number
,
rows
:
number
):
void
{
this
.
_maximumDimensions
=
{
cols
,
rows
};
this
.
_onDidChangeMaximumDimensions
.
fire
(
this
.
maximumDimensions
);
}
}
export
class
ExtHostTerminalService
implements
ExtHostTerminalServiceShape
{
private
_proxy
:
MainThreadTerminalServiceShape
;
private
_activeTerminal
:
ExtHostTerminal
;
private
_terminals
:
ExtHostTerminal
[]
=
[];
private
_terminalProcesses
:
{
[
id
:
number
]:
cp
.
ChildProcess
}
=
{};
private
_terminalRenderers
:
ExtHostTerminalRenderer
[]
=
[];
public
get
activeTerminal
():
ExtHostTerminal
{
return
this
.
_activeTerminal
;
}
public
get
terminals
():
ExtHostTerminal
[]
{
return
this
.
_terminals
;
}
private
readonly
_onDidCloseTerminal
:
Emitter
<
vscode
.
Terminal
>
=
new
Emitter
<
vscode
.
Terminal
>
();
public
get
onDidCloseTerminal
():
Event
<
vscode
.
Terminal
>
{
return
this
.
_onDidCloseTerminal
&&
this
.
_onDidCloseTerminal
.
event
;
}
private
readonly
_onDidOpenTerminal
:
Emitter
<
vscode
.
Terminal
>
=
new
Emitter
<
vscode
.
Terminal
>
();
public
get
onDidOpenTerminal
():
Event
<
vscode
.
Terminal
>
{
return
this
.
_onDidOpenTerminal
&&
this
.
_onDidOpenTerminal
.
event
;
}
private
readonly
_onDidChangeActiveTerminal
:
Emitter
<
vscode
.
Terminal
|
undefined
>
=
new
Emitter
<
vscode
.
Terminal
|
undefined
>
();
public
get
onDidChangeActiveTerminal
():
Event
<
vscode
.
Terminal
|
undefined
>
{
return
this
.
_onDidChangeActiveTerminal
&&
this
.
_onDidChangeActiveTerminal
.
event
;
}
constructor
(
mainContext
:
IMainContext
,
...
...
@@ -143,53 +244,94 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
}
public
createTerminal
(
name
?:
string
,
shellPath
?:
string
,
shellArgs
?:
string
[]):
vscode
.
Terminal
{
le
t
terminal
=
new
ExtHostTerminal
(
this
.
_proxy
,
name
);
cons
t
terminal
=
new
ExtHostTerminal
(
this
.
_proxy
,
name
);
terminal
.
create
(
shellPath
,
shellArgs
);
this
.
_terminals
.
push
(
terminal
);
return
terminal
;
}
public
createTerminalFromOptions
(
options
:
vscode
.
TerminalOptions
):
vscode
.
Terminal
{
le
t
terminal
=
new
ExtHostTerminal
(
this
.
_proxy
,
options
.
name
);
cons
t
terminal
=
new
ExtHostTerminal
(
this
.
_proxy
,
options
.
name
);
terminal
.
create
(
options
.
shellPath
,
options
.
shellArgs
,
options
.
cwd
,
options
.
env
/*, options.waitOnExit*/
);
this
.
_terminals
.
push
(
terminal
);
return
terminal
;
}
public
createTerminalRenderer
(
name
:
string
):
vscode
.
TerminalRenderer
{
const
renderer
=
new
ExtHostTerminalRenderer
(
this
.
_proxy
,
name
,
(
id
)
=>
this
.
_getTerminalByIdEventually
(
id
));
this
.
_terminalRenderers
.
push
(
renderer
);
return
renderer
;
}
public
$acceptActiveTerminalChanged
(
id
:
number
|
null
):
void
{
const
original
=
this
.
_activeTerminal
;
if
(
id
===
null
)
{
this
.
_activeTerminal
=
undefined
;
}
else
{
const
terminal
=
this
.
_getTerminalById
(
id
);
if
(
terminal
)
{
this
.
_activeTerminal
=
terminal
;
}
}
if
(
original
!==
this
.
_activeTerminal
)
{
this
.
_onDidChangeActiveTerminal
.
fire
(
this
.
_activeTerminal
);
}
}
public
$acceptTerminalProcessData
(
id
:
number
,
data
:
string
):
void
{
let
index
=
this
.
_getTerminalIndexById
(
id
);
if
(
index
===
null
)
{
return
;
const
terminal
=
this
.
_getTerminalById
(
id
);
if
(
terminal
)
{
terminal
.
_fireOnData
(
data
);
}
}
public
$acceptTerminalRendererDimensions
(
id
:
number
,
cols
:
number
,
rows
:
number
):
void
{
const
renderer
=
this
.
_getTerminalRendererById
(
id
);
if
(
renderer
)
{
renderer
.
_setMaximumDimensions
(
cols
,
rows
);
}
}
public
$acceptTerminalRendererInput
(
id
:
number
,
data
:
string
):
void
{
const
renderer
=
this
.
_getTerminalRendererById
(
id
);
if
(
renderer
)
{
renderer
.
_fireOnInput
(
data
);
}
const
terminal
=
this
.
_terminals
[
index
];
terminal
.
_fireOnData
(
data
);
}
public
$acceptTerminalClosed
(
id
:
number
):
void
{
let
index
=
this
.
_getTerminalIndexById
(
id
);
const
index
=
this
.
_getTerminalObjectIndexById
(
this
.
terminals
,
id
);
if
(
index
===
null
)
{
return
;
}
le
t
terminal
=
this
.
_terminals
.
splice
(
index
,
1
)[
0
];
cons
t
terminal
=
this
.
_terminals
.
splice
(
index
,
1
)[
0
];
this
.
_onDidCloseTerminal
.
fire
(
terminal
);
}
public
$acceptTerminalOpened
(
id
:
number
,
name
:
string
):
void
{
let
index
=
this
.
_getTerminalIndexById
(
id
);
const
index
=
this
.
_getTerminalObjectIndexById
(
this
.
_terminals
,
id
);
if
(
index
!==
null
)
{
// The terminal has already been created (via createTerminal*), only fire the event
this
.
_onDidOpenTerminal
.
fire
(
this
.
terminals
[
index
]);
return
;
}
let
terminal
=
new
ExtHostTerminal
(
this
.
_proxy
,
name
,
id
);
const
renderer
=
this
.
_getTerminalRendererById
(
id
);
const
terminal
=
new
ExtHostTerminal
(
this
.
_proxy
,
name
,
id
,
renderer
?
RENDERER_NO_PROCESS_ID
:
undefined
);
this
.
_terminals
.
push
(
terminal
);
this
.
_onDidOpenTerminal
.
fire
(
terminal
);
}
public
$acceptTerminalProcessId
(
id
:
number
,
processId
:
number
):
void
{
let
terminal
=
this
.
_getTerminalById
(
id
);
if
(
terminal
)
{
terminal
.
_setProcessId
(
processId
);
}
else
{
// Retry one more time in case the terminal has not yet been initialized.
setTimeout
(()
=>
{
terminal
=
this
.
_getTerminalById
(
id
);
terminal
.
_setProcessId
(
processId
);
},
EXT_HOST_CREATION_DELAY
);
}
}
...
...
@@ -232,7 +374,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
// Continue env initialization, merging in the env from the launch
// config and adding keys that are needed to create the process
const
env
=
terminalEnvironment
.
createTerminalEnv
(
parentEnv
,
shellLaunchConfig
,
initialCwd
,
locale
,
cols
,
rows
);
le
t
cwd
=
Uri
.
parse
(
require
.
toUrl
(
'
../../parts/terminal/node
'
)).
fsPath
;
cons
t
cwd
=
Uri
.
parse
(
require
.
toUrl
(
'
../../parts/terminal/node
'
)).
fsPath
;
const
options
=
{
env
,
cwd
,
execArgv
:
[]
};
// Fork the process and listen for messages
...
...
@@ -286,16 +428,43 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
this
.
_proxy
.
$sendProcessExit
(
id
,
exitCode
);
}
private
_getTerminalByIdEventually
(
id
:
number
,
retries
:
number
=
5
):
Promise
<
ExtHostTerminal
>
{
return
new
Promise
(
c
=>
{
if
(
retries
===
0
)
{
c
(
undefined
);
return
;
}
const
terminal
=
this
.
_getTerminalById
(
id
);
if
(
terminal
)
{
c
(
terminal
);
}
else
{
// This should only be needed immediately after createTerminalRenderer is called as
// the ExtHostTerminal has not yet been iniitalized
setTimeout
(()
=>
{
c
(
this
.
_getTerminalByIdEventually
(
id
,
retries
-
1
));
},
200
);
}
});
}
private
_getTerminalById
(
id
:
number
):
ExtHostTerminal
{
let
index
=
this
.
_getTerminalIndexById
(
id
);
return
index
!==
null
?
this
.
_terminals
[
index
]
:
null
;
return
this
.
_getTerminalObjectById
(
this
.
_terminals
,
id
);
}
private
_getTerminalRendererById
(
id
:
number
):
ExtHostTerminalRenderer
{
return
this
.
_getTerminalObjectById
(
this
.
_terminalRenderers
,
id
);
}
private
_getTerminalObjectById
<
T
extends
ExtHostTerminal
|
ExtHostTerminalRenderer
>
(
array
:
T
[],
id
:
number
):
T
{
const
index
=
this
.
_getTerminalObjectIndexById
(
array
,
id
);
return
index
!==
null
?
array
[
index
]
:
null
;
}
private
_getTerminal
IndexById
(
id
:
number
):
number
{
private
_getTerminal
ObjectIndexById
<
T
extends
ExtHostTerminal
|
ExtHostTerminalRenderer
>
(
array
:
T
[],
id
:
number
):
number
{
let
index
:
number
=
null
;
this
.
_terminals
.
some
((
terminal
,
i
)
=>
{
// TODO: This shouldn't be cas
let
thisId
=
(
<
any
>
terminal
).
_id
;
array
.
some
((
item
,
i
)
=>
{
const
thisId
=
item
.
_id
;
if
(
thisId
===
id
)
{
index
=
i
;
return
true
;
...
...
src/vs/workbench/parts/terminal/browser/terminalFindWidget.ts
浏览文件 @
8d4466df
...
...
@@ -21,13 +21,12 @@ export class TerminalFindWidget extends SimpleFindWidget {
}
public
find
(
previous
:
boolean
)
{
let
val
=
this
.
inputValue
;
let
instance
=
this
.
_terminalService
.
getActiveInstance
();
const
instance
=
this
.
_terminalService
.
getActiveInstance
();
if
(
instance
!==
null
)
{
if
(
previous
)
{
instance
.
findPrevious
(
val
);
instance
.
findPrevious
(
this
.
inputValue
);
}
else
{
instance
.
findNext
(
val
);
instance
.
findNext
(
this
.
inputValue
);
}
}
}
...
...
src/vs/workbench/parts/terminal/browser/terminalTab.ts
浏览文件 @
8d4466df
...
...
@@ -278,7 +278,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
// Adjust focus if the instance was active
if
(
wasActiveInstance
&&
this
.
_terminalInstances
.
length
>
0
)
{
le
t
newIndex
=
index
<
this
.
_terminalInstances
.
length
?
index
:
this
.
_terminalInstances
.
length
-
1
;
cons
t
newIndex
=
index
<
this
.
_terminalInstances
.
length
?
index
:
this
.
_terminalInstances
.
length
-
1
;
this
.
setActiveInstanceByIndex
(
newIndex
);
// TODO: Only focus the new instance if the tab had focus?
this
.
activeInstance
.
focus
(
true
);
...
...
src/vs/workbench/parts/terminal/browser/terminalWidgetManager.ts
浏览文件 @
8d4466df
...
...
@@ -7,7 +7,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
const
WIDGET_HEIGHT
=
29
;
export
class
TerminalWidgetManager
{
export
class
TerminalWidgetManager
implements
IDisposable
{
private
_container
:
HTMLElement
;
private
_xtermViewport
:
HTMLElement
;
...
...
@@ -24,6 +24,14 @@ export class TerminalWidgetManager {
this
.
_initTerminalHeightWatcher
(
terminalWrapper
);
}
public
dispose
():
void
{
if
(
this
.
_container
)
{
this
.
_container
.
parentElement
.
removeChild
(
this
.
_container
);
this
.
_container
=
null
;
}
this
.
_xtermViewport
=
null
;
}
private
_initTerminalHeightWatcher
(
terminalWrapper
:
HTMLElement
)
{
// Watch the xterm.js viewport for style changes and do a layout if it changes
this
.
_xtermViewport
=
<
HTMLElement
>
terminalWrapper
.
querySelector
(
'
.xterm-viewport
'
);
...
...
src/vs/workbench/parts/terminal/common/terminal.ts
浏览文件 @
8d4466df
...
...
@@ -37,6 +37,11 @@ export const IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY = 'terminal.integrated.isWor
export
const
NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY
=
'
terminal.integrated.neverSuggestSelectWindowsShell
'
;
export
const
NEVER_MEASURE_RENDER_TIME_STORAGE_KEY
=
'
terminal.integrated.neverMeasureRenderTime
'
;
// The creation of extension host terminals is delayed by this value (milliseconds). The purpose of
// this delay is to allow the terminal instance to initialize correctly and have its ID set before
// trying to create the corressponding object on the ext host.
export
const
EXT_HOST_CREATION_DELAY
=
100
;
export
const
ITerminalService
=
createDecorator
<
ITerminalService
>
(
TERMINAL_SERVICE_ID
);
export
const
TerminalCursorStyle
=
{
...
...
@@ -159,6 +164,12 @@ export interface IShellLaunchConfig {
* of the terminal. Use \x1b over \033 or \e for the escape control character.
*/
initialText
?:
string
;
/**
* When true the terminal will be created with no process. This is primarily used to give
* extensions full control over the terminal.
*/
isRendererOnly
?:
boolean
;
}
export
interface
ITerminalService
{
...
...
@@ -171,9 +182,11 @@ export interface ITerminalService {
onInstanceCreated
:
Event
<
ITerminalInstance
>
;
onInstanceDisposed
:
Event
<
ITerminalInstance
>
;
onInstanceProcessIdReady
:
Event
<
ITerminalInstance
>
;
onInstanceDimensionsChanged
:
Event
<
ITerminalInstance
>
;
onInstanceRequestExtHostProcess
:
Event
<
ITerminalProcessExtHostRequest
>
;
onInstancesChanged
:
Event
<
void
>
;
onInstanceTitleChanged
:
Event
<
string
>
;
onActiveInstanceChanged
:
Event
<
ITerminalInstance
>
;
terminalInstances
:
ITerminalInstance
[];
terminalTabs
:
ITerminalTab
[];
...
...
@@ -184,6 +197,12 @@ export interface ITerminalService {
* default shell selection dialog may display.
*/
createTerminal
(
shell
?:
IShellLaunchConfig
,
wasNewTerminalAction
?:
boolean
):
ITerminalInstance
;
/**
* Creates a terminal renderer.
* @param name The name of the terminal.
*/
createTerminalRenderer
(
name
:
string
):
ITerminalInstance
;
/**
* Creates a raw terminal instance, this should not be used outside of the terminal part.
*/
...
...
@@ -239,12 +258,27 @@ export interface ITerminalTab {
split
(
terminalFocusContextKey
:
IContextKey
<
boolean
>
,
configHelper
:
ITerminalConfigHelper
,
shellLaunchConfig
:
IShellLaunchConfig
):
ITerminalInstance
;
}
export
interface
ITerminalDimensions
{
/**
* The columns of the terminal.
*/
readonly
cols
:
number
;
/**
* The rows of the terminal.
*/
readonly
rows
:
number
;
}
export
interface
ITerminalInstance
{
/**
* The ID of the terminal instance, this is an arbitrary number only used to identify the
* terminal instance.
*/
id
:
number
;
readonly
id
:
number
;
readonly
cols
:
number
;
readonly
rows
:
number
;
/**
* The process ID of the shell process, this is undefined when there is no process associated
...
...
@@ -268,6 +302,42 @@ export interface ITerminalInstance {
onRequestExtHostProcess
:
Event
<
ITerminalInstance
>
;
onDimensionsChanged
:
Event
<
void
>
;
onFocus
:
Event
<
ITerminalInstance
>
;
/**
* Attach a listener to the raw data stream coming from the pty, including ANSI escape
* sequences.
*/
onData
:
Event
<
string
>
;
/**
* Attach a listener to the "renderer" input event, this event fires for terminal renderers on
* keystrokes and when the Terminal.sendText extension API is used.
* @param listener The listener function.
*/
onRendererInput
:
Event
<
string
>
;
/**
* Attach a listener to listen for new lines added to this terminal instance.
*
* @param listener The listener function which takes new line strings added to the terminal,
* excluding ANSI escape sequences. The line event will fire when an LF character is added to
* the terminal (ie. the line is not wrapped). Note that this means that the line data will
* not fire for the last line, until either the line is ended with a LF character of the process
* is exited. The lineData string will contain the fully wrapped line, not containing any LF/CR
* characters.
*/
onLineData
:
Event
<
string
>
;
/**
* Attach a listener that fires when the terminal's pty process exits. The number in the event
* is the processes' exit code, an exit code of null means the process was killed as a result of
* the ITerminalInstance being disposed.
*/
onExit
:
Event
<
number
>
;
processReady
:
TPromise
<
void
>
;
/**
...
...
@@ -294,7 +364,7 @@ export interface ITerminalInstance {
/**
* The shell launch config used to launch the shell.
*/
shellLaunchConfig
:
IShellLaunchConfig
;
readonly
shellLaunchConfig
:
IShellLaunchConfig
;
/**
* Whether to disable layout for the terminal. This is useful when the size of the terminal is
...
...
@@ -397,6 +467,12 @@ 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. */
...
...
@@ -448,33 +524,6 @@ export interface ITerminalInstance {
*/
setVisible
(
visible
:
boolean
):
void
;
/**
* Attach a listener to the raw data stream coming from the pty, including ANSI escape
* sequecnes.
* @param listener The listener function.
*/
onData
(
listener
:
(
data
:
string
)
=>
void
):
IDisposable
;
/**
* Attach a listener to listen for new lines added to this terminal instance.
*
* @param listener The listener function which takes new line strings added to the terminal,
* excluding ANSI escape sequences. The line event will fire when an LF character is added to
* the terminal (ie. the line is not wrapped). Note that this means that the line data will
* not fire for the last line, until either the line is ended with a LF character of the process
* is exited. The lineData string will contain the fully wrapped line, not containing any LF/CR
* characters.
*/
onLineData
(
listener
:
(
lineData
:
string
)
=>
void
):
IDisposable
;
/**
* Attach a listener that fires when the terminal's pty process exits.
*
* @param listener The listener function which takes the processes' exit code, an exit code of
* null means the process was killed as a result of the ITerminalInstance being disposed.
*/
onExit
(
listener
:
(
exitCode
:
number
)
=>
void
):
IDisposable
;
/**
* Immediately kills the terminal's current pty process and launches a new one to replace it.
*
...
...
@@ -487,6 +536,8 @@ export interface ITerminalInstance {
*/
setTitle
(
title
:
string
,
eventFromProcess
:
boolean
):
void
;
setDimensions
(
dimensions
:
ITerminalDimensions
):
void
;
addDisposable
(
disposable
:
IDisposable
):
void
;
}
...
...
src/vs/workbench/parts/terminal/common/terminalColorRegistry.ts
浏览文件 @
8d4466df
...
...
@@ -160,9 +160,9 @@ const ansiColorMap = {
};
export
function
registerColors
():
void
{
for
(
le
t
id
in
ansiColorMap
)
{
le
t
entry
=
ansiColorMap
[
id
];
le
t
colorName
=
id
.
substring
(
13
);
for
(
cons
t
id
in
ansiColorMap
)
{
cons
t
entry
=
ansiColorMap
[
id
];
cons
t
colorName
=
id
.
substring
(
13
);
ansiColorIdentifiers
[
entry
.
index
]
=
registerColor
(
id
,
entry
.
defaults
,
nls
.
localize
(
'
terminal.ansiColor
'
,
'
\'
{0}
\'
ANSI color in the terminal.
'
,
colorName
));
}
}
src/vs/workbench/parts/terminal/common/terminalService.ts
浏览文件 @
8d4466df
...
...
@@ -41,10 +41,14 @@ export abstract class TerminalService implements ITerminalService {
public
get
onInstanceProcessIdReady
():
Event
<
ITerminalInstance
>
{
return
this
.
_onInstanceProcessIdReady
.
event
;
}
protected
readonly
_onInstanceRequestExtHostProcess
:
Emitter
<
ITerminalProcessExtHostRequest
>
=
new
Emitter
<
ITerminalProcessExtHostRequest
>
();
public
get
onInstanceRequestExtHostProcess
():
Event
<
ITerminalProcessExtHostRequest
>
{
return
this
.
_onInstanceRequestExtHostProcess
.
event
;
}
protected
readonly
_onInstanceDimensionsChanged
:
Emitter
<
ITerminalInstance
>
=
new
Emitter
<
ITerminalInstance
>
();
public
get
onInstanceDimensionsChanged
():
Event
<
ITerminalInstance
>
{
return
this
.
_onInstanceDimensionsChanged
.
event
;
}
protected
readonly
_onInstancesChanged
:
Emitter
<
void
>
=
new
Emitter
<
void
>
();
public
get
onInstancesChanged
():
Event
<
void
>
{
return
this
.
_onInstancesChanged
.
event
;
}
protected
readonly
_onInstanceTitleChanged
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onInstanceTitleChanged
():
Event
<
string
>
{
return
this
.
_onInstanceTitleChanged
.
event
;
}
protected
readonly
_onActiveInstanceChanged
:
Emitter
<
ITerminalInstance
>
=
new
Emitter
<
ITerminalInstance
>
();
public
get
onActiveInstanceChanged
():
Event
<
ITerminalInstance
>
{
return
this
.
_onActiveInstanceChanged
.
event
;
}
protected
readonly
_onTabDisposed
:
Emitter
<
ITerminalTab
>
=
new
Emitter
<
ITerminalTab
>
();
public
get
onTabDisposed
():
Event
<
ITerminalTab
>
{
return
this
.
_onTabDisposed
.
event
;
}
...
...
@@ -71,6 +75,7 @@ export abstract class TerminalService implements ITerminalService {
protected
abstract
_showTerminalCloseConfirmation
():
TPromise
<
boolean
>
;
public
abstract
createTerminal
(
shell
?:
IShellLaunchConfig
,
wasNewTerminalAction
?:
boolean
):
ITerminalInstance
;
public
abstract
createTerminalRenderer
(
name
:
string
):
ITerminalInstance
;
public
abstract
createInstance
(
terminalFocusContextKey
:
IContextKey
<
boolean
>
,
configHelper
:
ITerminalConfigHelper
,
container
:
HTMLElement
,
shellLaunchConfig
:
IShellLaunchConfig
,
doCreateProcess
:
boolean
):
ITerminalInstance
;
public
abstract
getActiveOrCreateInstance
(
wasNewTerminalAction
?:
boolean
):
ITerminalInstance
;
public
abstract
selectDefaultWindowsShell
():
TPromise
<
string
>
;
...
...
@@ -152,7 +157,7 @@ export abstract class TerminalService implements ITerminalService {
if
(
wasActiveTab
&&
this
.
_terminalTabs
.
length
>
0
)
{
// TODO: Only focus the new tab if the removed tab had focus?
// const hasFocusOnExit = tab.activeInstance.hadFocusOnExit;
le
t
newIndex
=
index
<
this
.
_terminalTabs
.
length
?
index
:
this
.
_terminalTabs
.
length
-
1
;
cons
t
newIndex
=
index
<
this
.
_terminalTabs
.
length
?
index
:
this
.
_terminalTabs
.
length
-
1
;
this
.
setActiveTabByIndex
(
newIndex
);
this
.
getActiveInstance
().
focus
(
true
);
}
...
...
@@ -162,6 +167,7 @@ export abstract class TerminalService implements ITerminalService {
// launch.
if
(
this
.
_terminalTabs
.
length
===
0
&&
!
this
.
_isShuttingDown
)
{
this
.
hidePanel
();
this
.
_onActiveInstanceChanged
.
fire
(
undefined
);
}
// Fire events
...
...
@@ -287,6 +293,8 @@ export abstract class TerminalService implements ITerminalService {
instance
.
addDisposable
(
instance
.
onDisposed
(
this
.
_onInstanceDisposed
.
fire
,
this
.
_onInstanceDisposed
));
instance
.
addDisposable
(
instance
.
onTitleChanged
(
this
.
_onInstanceTitleChanged
.
fire
,
this
.
_onInstanceTitleChanged
));
instance
.
addDisposable
(
instance
.
onProcessIdReady
(
this
.
_onInstanceProcessIdReady
.
fire
,
this
.
_onInstanceProcessIdReady
));
instance
.
addDisposable
(
instance
.
onDimensionsChanged
(()
=>
this
.
_onInstanceDimensionsChanged
.
fire
(
instance
)));
instance
.
addDisposable
(
instance
.
onFocus
(
this
.
_onActiveInstanceChanged
.
fire
,
this
.
_onActiveInstanceChanged
));
}
private
_getTabForInstance
(
instance
:
ITerminalInstance
):
ITerminalTab
{
...
...
@@ -301,7 +309,7 @@ export abstract class TerminalService implements ITerminalService {
public
showPanel
(
focus
?:
boolean
):
TPromise
<
void
>
{
return
new
TPromise
<
void
>
((
complete
)
=>
{
le
t
panel
=
this
.
_panelService
.
getActivePanel
();
cons
t
panel
=
this
.
_panelService
.
getActivePanel
();
if
(
!
panel
||
panel
.
getId
()
!==
TERMINAL_PANEL_ID
)
{
return
this
.
_panelService
.
openPanel
(
TERMINAL_PANEL_ID
,
focus
).
then
(()
=>
{
if
(
focus
)
{
...
...
src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts
浏览文件 @
8d4466df
...
...
@@ -66,7 +66,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenTermAction, Q
const
actionBarRegistry
=
Registry
.
as
<
IActionBarRegistry
>
(
ActionBarExtensions
.
Actionbar
);
actionBarRegistry
.
registerActionBarContributor
(
Scope
.
VIEWER
,
QuickOpenActionTermContributor
);
le
t
configurationRegistry
=
Registry
.
as
<
IConfigurationRegistry
>
(
Extensions
.
Configuration
);
cons
t
configurationRegistry
=
Registry
.
as
<
IConfigurationRegistry
>
(
Extensions
.
Configuration
);
configurationRegistry
.
registerConfiguration
({
'
id
'
:
'
terminal
'
,
'
order
'
:
100
,
...
...
@@ -368,7 +368,7 @@ registerSingleton(ITerminalService, TerminalService);
// On mac cmd+` is reserved to cycle between windows, that's why the keybindings use WinCtrl
const
category
=
nls
.
localize
(
'
terminalCategory
'
,
"
Terminal
"
);
le
t
actionRegistry
=
Registry
.
as
<
IWorkbenchActionRegistry
>
(
ActionExtensions
.
WorkbenchActions
);
cons
t
actionRegistry
=
Registry
.
as
<
IWorkbenchActionRegistry
>
(
ActionExtensions
.
WorkbenchActions
);
actionRegistry
.
registerWorkbenchAction
(
new
SyncActionDescriptor
(
KillTerminalAction
,
KillTerminalAction
.
ID
,
KillTerminalAction
.
LABEL
),
'
Terminal: Kill the Active Terminal Instance
'
,
category
);
actionRegistry
.
registerWorkbenchAction
(
new
SyncActionDescriptor
(
CopyTerminalSelectionAction
,
CopyTerminalSelectionAction
.
ID
,
CopyTerminalSelectionAction
.
LABEL
,
{
primary
:
KeyMod
.
CtrlCmd
|
KeyCode
.
KEY_C
,
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts
浏览文件 @
8d4466df
...
...
@@ -71,9 +71,10 @@ export class KillTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
let
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
this
.
terminalService
.
getActiveInstance
().
dispose
();
console
.
log
(
'
kill
'
);
const
instance
=
this
.
terminalService
.
getActiveInstance
();
if
(
instance
)
{
instance
.
dispose
();
if
(
this
.
terminalService
.
terminalInstances
.
length
>
0
)
{
this
.
terminalService
.
showPanel
(
true
);
}
...
...
@@ -121,7 +122,7 @@ export class CopyTerminalSelectionAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
copySelection
();
}
...
...
@@ -142,7 +143,7 @@ export class SelectAllTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
selectAll
();
}
...
...
@@ -161,7 +162,7 @@ export abstract class BaseSendTextTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
_terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
_terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
sendText
(
this
.
_text
,
false
);
}
...
...
@@ -598,7 +599,7 @@ export class RunSelectedTextInTerminalAction extends Action {
if
(
selection
.
isEmpty
())
{
text
=
editor
.
getModel
().
getLineContent
(
selection
.
selectionStartLineNumber
).
trim
();
}
else
{
le
t
endOfLinePreference
=
os
.
EOL
===
'
\n
'
?
EndOfLinePreference
.
LF
:
EndOfLinePreference
.
CRLF
;
cons
t
endOfLinePreference
=
os
.
EOL
===
'
\n
'
?
EndOfLinePreference
.
LF
:
EndOfLinePreference
.
CRLF
;
text
=
editor
.
getModel
().
getValueInRange
(
selection
,
endOfLinePreference
);
}
instance
.
sendText
(
text
,
true
);
...
...
@@ -695,7 +696,7 @@ export class ScrollDownTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
scrollDownLine
();
}
...
...
@@ -716,7 +717,7 @@ export class ScrollDownPageTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
scrollDownPage
();
}
...
...
@@ -737,7 +738,7 @@ export class ScrollToBottomTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
scrollToBottom
();
}
...
...
@@ -758,7 +759,7 @@ export class ScrollUpTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
scrollUpLine
();
}
...
...
@@ -779,7 +780,7 @@ export class ScrollUpPageTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
scrollUpPage
();
}
...
...
@@ -800,7 +801,7 @@ export class ScrollToTopTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
scrollToTop
();
}
...
...
@@ -821,7 +822,7 @@ export class ClearTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
)
{
terminalInstance
.
clear
();
}
...
...
@@ -842,7 +843,7 @@ export class ClearSelectionTerminalAction extends Action {
}
public
run
(
event
?:
any
):
TPromise
<
any
>
{
le
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
cons
t
terminalInstance
=
this
.
terminalService
.
getActiveInstance
();
if
(
terminalInstance
&&
terminalInstance
.
hasSelection
())
{
terminalInstance
.
clearSelection
();
}
...
...
@@ -959,7 +960,7 @@ export class QuickOpenActionTermContributor extends ActionBarContributor {
}
public
getActions
(
context
:
any
):
IAction
[]
{
le
t
actions
:
Action
[]
=
[];
cons
t
actions
:
Action
[]
=
[];
if
(
context
.
element
instanceof
TerminalEntry
)
{
actions
.
push
(
this
.
instantiationService
.
createInstance
(
RenameTerminalQuickOpenAction
,
RenameTerminalQuickOpenAction
.
ID
,
RenameTerminalQuickOpenAction
.
LABEL
,
context
.
element
));
actions
.
push
(
this
.
instantiationService
.
createInstance
(
QuickKillTerminalAction
,
QuickKillTerminalAction
.
ID
,
QuickKillTerminalAction
.
LABEL
,
context
.
element
));
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts
浏览文件 @
8d4466df
...
...
@@ -50,12 +50,12 @@ export class TerminalConfigHelper implements ITerminalConfigHelper {
public
configFontIsMonospace
():
boolean
{
this
.
_createCharMeasureElementIfNecessary
();
le
t
fontSize
=
15
;
le
t
fontFamily
=
this
.
config
.
fontFamily
||
this
.
_configurationService
.
getValue
<
IEditorOptions
>
(
'
editor
'
).
fontFamily
;
le
t
i_rect
=
this
.
_getBoundingRectFor
(
'
i
'
,
fontFamily
,
fontSize
);
le
t
w_rect
=
this
.
_getBoundingRectFor
(
'
w
'
,
fontFamily
,
fontSize
);
cons
t
fontSize
=
15
;
cons
t
fontFamily
=
this
.
config
.
fontFamily
||
this
.
_configurationService
.
getValue
<
IEditorOptions
>
(
'
editor
'
).
fontFamily
;
cons
t
i_rect
=
this
.
_getBoundingRectFor
(
'
i
'
,
fontFamily
,
fontSize
);
cons
t
w_rect
=
this
.
_getBoundingRectFor
(
'
w
'
,
fontFamily
,
fontSize
);
le
t
invalidBounds
=
!
i_rect
.
width
||
!
w_rect
.
width
;
cons
t
invalidBounds
=
!
i_rect
.
width
||
!
w_rect
.
width
;
if
(
invalidBounds
)
{
// There is no reason to believe the font is not Monospace.
return
true
;
...
...
@@ -88,7 +88,7 @@ export class TerminalConfigHelper implements ITerminalConfigHelper {
private
_measureFont
(
fontFamily
:
string
,
fontSize
:
number
,
letterSpacing
:
number
,
lineHeight
:
number
):
ITerminalFont
{
this
.
_createCharMeasureElementIfNecessary
();
le
t
rect
=
this
.
_getBoundingRectFor
(
'
X
'
,
fontFamily
,
fontSize
);
cons
t
rect
=
this
.
_getBoundingRectFor
(
'
X
'
,
fontFamily
,
fontSize
);
// Bounding client rect was invalid, use last font measurement if available.
if
(
this
.
_lastFontMeasurement
&&
!
rect
.
width
&&
!
rect
.
height
)
{
...
...
@@ -122,7 +122,7 @@ export class TerminalConfigHelper implements ITerminalConfigHelper {
}
}
le
t
fontSize
=
this
.
_toInteger
(
this
.
config
.
fontSize
,
MINIMUM_FONT_SIZE
,
MAXIMUM_FONT_SIZE
,
EDITOR_FONT_DEFAULTS
.
fontSize
);
cons
t
fontSize
=
this
.
_toInteger
(
this
.
config
.
fontSize
,
MINIMUM_FONT_SIZE
,
MAXIMUM_FONT_SIZE
,
EDITOR_FONT_DEFAULTS
.
fontSize
);
const
letterSpacing
=
this
.
config
.
letterSpacing
?
Math
.
max
(
Math
.
floor
(
this
.
config
.
letterSpacing
),
MINIMUM_LETTER_SPACING
)
:
DEFAULT_LETTER_SPACING
;
const
lineHeight
=
this
.
config
.
lineHeight
?
Math
.
max
(
this
.
config
.
lineHeight
,
1
)
:
DEFAULT_LINE_HEIGHT
;
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts
浏览文件 @
8d4466df
...
...
@@ -14,7 +14,7 @@ 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
{
ITerminalInstance
,
KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED
,
TERMINAL_PANEL_ID
,
IShellLaunchConfig
,
ITerminalProcessManager
,
ProcessState
,
NEVER_MEASURE_RENDER_TIME_STORAGE_KEY
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
ITerminalInstance
,
KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED
,
TERMINAL_PANEL_ID
,
IShellLaunchConfig
,
ITerminalProcessManager
,
ProcessState
,
NEVER_MEASURE_RENDER_TIME_STORAGE_KEY
,
ITerminalDimensions
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
StandardKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
import
{
TabFocus
}
from
'
vs/editor/common/config/commonEditorConfig
'
;
...
...
@@ -63,8 +63,8 @@ export class TerminalInstance implements ITerminalInstance {
private
_terminalHasTextContextKey
:
IContextKey
<
boolean
>
;
private
_cols
:
number
;
private
_rows
:
number
;
private
_dimensionsOverride
:
ITerminalDimensions
;
private
_windowsShellHelper
:
WindowsShellHelper
;
private
_onLineDataListeners
:
((
lineData
:
string
)
=>
void
)[];
private
_xtermReadyPromise
:
TPromise
<
void
>
;
private
_disposables
:
lifecycle
.
IDisposable
[];
...
...
@@ -76,6 +76,8 @@ export class TerminalInstance implements ITerminalInstance {
public
disableLayout
:
boolean
;
public
get
id
():
number
{
return
this
.
_id
;
}
public
get
cols
():
number
{
return
this
.
_cols
;
}
public
get
rows
():
number
{
return
this
.
_rows
;
}
// TODO: Ideally processId would be merged into processReady
public
get
processId
():
number
|
undefined
{
return
this
.
_processManager
?
this
.
_processManager
.
shellProcessId
:
undefined
;
}
// TODO: How does this work with detached processes?
...
...
@@ -84,10 +86,11 @@ export class TerminalInstance implements ITerminalInstance {
public
get
title
():
string
{
return
this
.
_title
;
}
public
get
hadFocusOnExit
():
boolean
{
return
this
.
_hadFocusOnExit
;
}
public
get
isTitleSetByProcess
():
boolean
{
return
!!
this
.
_messageTitleDisposable
;
}
public
get
shellLaunchConfig
():
IShellLaunchConfig
{
return
Object
.
freeze
(
this
.
_shellLaunchConfig
)
;
}
public
get
shellLaunchConfig
():
IShellLaunchConfig
{
return
this
.
_shellLaunchConfig
;
}
public
get
commandTracker
():
TerminalCommandTracker
{
return
this
.
_commandTracker
;
}
private
readonly
_onExit
:
Emitter
<
number
>
=
new
Emitter
<
number
>
();
public
get
onExit
():
Event
<
number
>
{
return
this
.
_onExit
.
event
;
}
private
readonly
_onDisposed
:
Emitter
<
ITerminalInstance
>
=
new
Emitter
<
ITerminalInstance
>
();
public
get
onDisposed
():
Event
<
ITerminalInstance
>
{
return
this
.
_onDisposed
.
event
;
}
private
readonly
_onFocused
:
Emitter
<
ITerminalInstance
>
=
new
Emitter
<
ITerminalInstance
>
();
...
...
@@ -96,15 +99,24 @@ export class TerminalInstance implements ITerminalInstance {
public
get
onProcessIdReady
():
Event
<
ITerminalInstance
>
{
return
this
.
_onProcessIdReady
.
event
;
}
private
readonly
_onTitleChanged
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onTitleChanged
():
Event
<
string
>
{
return
this
.
_onTitleChanged
.
event
;
}
private
readonly
_onData
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onData
():
Event
<
string
>
{
return
this
.
_onData
.
event
;
}
private
readonly
_onLineData
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onLineData
():
Event
<
string
>
{
return
this
.
_onLineData
.
event
;
}
private
readonly
_onRendererInput
:
Emitter
<
string
>
=
new
Emitter
<
string
>
();
public
get
onRendererInput
():
Event
<
string
>
{
return
this
.
_onRendererInput
.
event
;
}
private
readonly
_onRequestExtHostProcess
:
Emitter
<
ITerminalInstance
>
=
new
Emitter
<
ITerminalInstance
>
();
public
get
onRequestExtHostProcess
():
Event
<
ITerminalInstance
>
{
return
this
.
_onRequestExtHostProcess
.
event
;
}
private
readonly
_onDimensionsChanged
:
Emitter
<
void
>
=
new
Emitter
<
void
>
();
public
get
onDimensionsChanged
():
Event
<
void
>
{
return
this
.
_onDimensionsChanged
.
event
;
}
private
readonly
_onFocus
:
Emitter
<
ITerminalInstance
>
=
new
Emitter
<
ITerminalInstance
>
();
public
get
onFocus
():
Event
<
ITerminalInstance
>
{
return
this
.
_onFocus
.
event
;
}
public
constructor
(
private
_terminalFocusContextKey
:
IContextKey
<
boolean
>
,
private
_configHelper
:
TerminalConfigHelper
,
private
readonly
_terminalFocusContextKey
:
IContextKey
<
boolean
>
,
private
readonly
_configHelper
:
TerminalConfigHelper
,
private
_container
:
HTMLElement
,
private
_shellLaunchConfig
:
IShellLaunchConfig
,
doCreateProcess
:
boolean
,
@
IContextKeyService
private
readonly
_contextKeyService
:
IContextKeyService
,
@
IKeybindingService
private
readonly
_keybindingService
:
IKeybindingService
,
@
INotificationService
private
readonly
_notificationService
:
INotificationService
,
...
...
@@ -118,7 +130,6 @@ export class TerminalInstance implements ITerminalInstance {
)
{
this
.
_disposables
=
[];
this
.
_skipTerminalCommands
=
[];
this
.
_onLineDataListeners
=
[];
this
.
_isExiting
=
false
;
this
.
_hadFocusOnExit
=
false
;
this
.
_isVisible
=
false
;
...
...
@@ -130,8 +141,10 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_logService
.
trace
(
`terminalInstance#ctor (id:
${
this
.
id
}
)`
,
this
.
_shellLaunchConfig
);
this
.
_initDimensions
();
if
(
doCreateProcess
)
{
if
(
!
this
.
shellLaunchConfig
.
isRendererOnly
)
{
this
.
_createProcess
();
}
else
{
this
.
setTitle
(
this
.
_shellLaunchConfig
.
name
,
false
);
}
this
.
_xtermReadyPromise
=
this
.
_createXterm
();
...
...
@@ -142,14 +155,14 @@ export class TerminalInstance implements ITerminalInstance {
}
});
this
.
_configurationService
.
onDidChangeConfiguration
(
e
=>
{
this
.
addDisposable
(
this
.
_configurationService
.
onDidChangeConfiguration
(
e
=>
{
if
(
e
.
affectsConfiguration
(
'
terminal.integrated
'
))
{
this
.
updateConfig
();
}
if
(
e
.
affectsConfiguration
(
'
editor.accessibilitySupport
'
))
{
this
.
updateAccessibilitySupport
();
}
});
})
)
;
}
public
addDisposable
(
disposable
:
lifecycle
.
IDisposable
):
void
{
...
...
@@ -286,6 +299,13 @@ export class TerminalInstance implements ITerminalInstance {
// TODO: How does the cwd work on detached processes?
this
.
_linkHandler
=
this
.
_instantiationService
.
createInstance
(
TerminalLinkHandler
,
this
.
_xterm
,
platform
.
platform
,
this
.
_processManager
.
initialCwd
);
}
this
.
_xterm
.
on
(
'
focus
'
,
()
=>
this
.
_onFocus
.
fire
(
this
));
// Register listener to trigger the onInput ext API if the terminal is a renderer only
if
(
this
.
_shellLaunchConfig
.
isRendererOnly
)
{
this
.
_xterm
.
on
(
'
data
'
,
(
data
)
=>
this
.
_sendRendererInput
(
data
));
}
this
.
_commandTracker
=
new
TerminalCommandTracker
(
this
.
_xterm
);
this
.
_disposables
.
push
(
this
.
_themeService
.
onThemeChange
(
theme
=>
this
.
_updateTheme
(
theme
)));
}
...
...
@@ -439,7 +459,7 @@ export class TerminalInstance implements ITerminalInstance {
}
private
_measureRenderTime
():
void
{
le
t
frameTimes
:
number
[]
=
[];
cons
t
frameTimes
:
number
[]
=
[];
const
textRenderLayer
=
(
<
any
>
this
.
_xterm
).
renderer
.
_renderLayers
[
0
];
const
originalOnGridChanged
=
textRenderLayer
.
onGridChanged
;
...
...
@@ -538,18 +558,21 @@ export class TerminalInstance implements ITerminalInstance {
public
dispose
():
void
{
this
.
_logService
.
trace
(
`terminalInstance#dispose (id:
${
this
.
id
}
)`
);
if
(
this
.
_windowsShellHelper
)
{
this
.
_windowsShellHelper
.
dispose
();
}
if
(
this
.
_linkHandler
)
{
this
.
_linkHandler
.
dispose
();
}
this
.
_windowsShellHelper
=
lifecycle
.
dispose
(
this
.
_windowsShellHelper
);
this
.
_linkHandler
=
lifecycle
.
dispose
(
this
.
_linkHandler
);
this
.
_commandTracker
=
lifecycle
.
dispose
(
this
.
_commandTracker
);
this
.
_widgetManager
=
lifecycle
.
dispose
(
this
.
_widgetManager
);
if
(
this
.
_xterm
&&
this
.
_xterm
.
element
)
{
this
.
_hadFocusOnExit
=
dom
.
hasClass
(
this
.
_xterm
.
element
,
'
focus
'
);
}
if
(
this
.
_wrapperElement
)
{
if
((
<
any
>
this
.
_wrapperElement
).
xterm
)
{
(
<
any
>
this
.
_wrapperElement
).
xterm
=
null
;
}
this
.
_container
.
removeChild
(
this
.
_wrapperElement
);
this
.
_wrapperElement
=
null
;
this
.
_xtermElement
=
null
;
}
if
(
this
.
_xterm
)
{
const
buffer
=
(
<
any
>
this
.
_xterm
.
buffer
);
...
...
@@ -557,9 +580,7 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_xterm
.
dispose
();
this
.
_xterm
=
null
;
}
if
(
this
.
_processManager
)
{
this
.
_processManager
.
dispose
();
}
this
.
_processManager
=
lifecycle
.
dispose
(
this
.
_processManager
);
if
(
!
this
.
_isDisposed
)
{
this
.
_isDisposed
=
true
;
this
.
_onDisposed
.
fire
(
this
);
...
...
@@ -584,17 +605,39 @@ export class TerminalInstance implements ITerminalInstance {
document
.
execCommand
(
'
paste
'
);
}
public
sendText
(
text
:
string
,
addNewLine
:
boolean
):
void
{
this
.
_processManager
.
ptyProcessReady
.
then
(()
=>
{
// Normalize line endings to 'enter' press.
text
=
text
.
replace
(
TerminalInstance
.
EOL_REGEX
,
'
\r
'
);
if
(
addNewLine
&&
text
.
substr
(
text
.
length
-
1
)
!==
'
\r
'
)
{
text
+=
'
\r
'
;
public
write
(
text
:
string
):
void
{
this
.
_xtermReadyPromise
.
then
(()
=>
{
if
(
!
this
.
_xterm
)
{
return
;
}
this
.
_xterm
.
write
(
text
);
if
(
this
.
_shellLaunchConfig
.
isRendererOnly
)
{
// Fire onData API in the extension host
this
.
_onData
.
fire
(
text
);
}
this
.
_processManager
.
write
(
text
);
});
}
public
sendText
(
text
:
string
,
addNewLine
:
boolean
):
void
{
// Normalize line endings to 'enter' press.
text
=
text
.
replace
(
TerminalInstance
.
EOL_REGEX
,
'
\r
'
);
if
(
addNewLine
&&
text
.
substr
(
text
.
length
-
1
)
!==
'
\r
'
)
{
text
+=
'
\r
'
;
}
if
(
this
.
_shellLaunchConfig
.
isRendererOnly
)
{
// If the terminal is a renderer only, fire the onInput ext API
this
.
_sendRendererInput
(
text
);
}
else
{
// If the terminal has a process, send it to the process
if
(
this
.
_processManager
)
{
this
.
_processManager
.
ptyProcessReady
.
then
(()
=>
{
this
.
_processManager
.
write
(
text
);
});
}
}
}
public
setVisible
(
visible
:
boolean
):
void
{
this
.
_isVisible
=
visible
;
if
(
this
.
_wrapperElement
)
{
...
...
@@ -660,6 +703,8 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_processManager
.
onProcessExit
(
exitCode
=>
this
.
_onProcessExit
(
exitCode
));
this
.
_processManager
.
createProcess
(
this
.
_shellLaunchConfig
,
this
.
_cols
,
this
.
_rows
);
this
.
_processManager
.
onProcessData
(
data
=>
this
.
_onData
.
fire
(
data
));
if
(
this
.
_shellLaunchConfig
.
name
)
{
this
.
setTitle
(
this
.
_shellLaunchConfig
.
name
,
false
);
}
else
{
...
...
@@ -751,6 +796,8 @@ export class TerminalInstance implements ITerminalInstance {
}
}
}
this
.
_onExit
.
fire
(
exitCode
);
}
private
_attachPressAnyKeyToCloseListener
()
{
...
...
@@ -791,26 +838,16 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_shellLaunchConfig
=
shell
;
}
public
onData
(
listener
:
(
data
:
string
)
=>
void
):
lifecycle
.
IDisposable
{
return
this
.
_processManager
.
onProcessData
(
data
=>
listener
(
data
));
}
private
_sendRendererInput
(
input
:
string
):
void
{
if
(
this
.
_processManager
)
{
throw
new
Error
(
'
onRendererInput attempted to be used on a regular terminal
'
);
}
public
onLineData
(
listener
:
(
lineData
:
string
)
=>
void
):
lifecycle
.
IDisposable
{
this
.
_onLineDataListeners
.
push
(
listener
);
return
{
dispose
:
()
=>
{
const
i
=
this
.
_onLineDataListeners
.
indexOf
(
listener
);
if
(
i
>=
0
)
{
this
.
_onLineDataListeners
.
splice
(
i
,
1
);
}
}
};
// For terminal renderers onData fires on keystrokes and when sendText is called.
this
.
_onRendererInput
.
fire
(
input
);
}
private
_onLineFeed
():
void
{
if
(
this
.
_onLineDataListeners
.
length
===
0
)
{
return
;
}
const
buffer
=
(
<
any
>
this
.
_xterm
.
buffer
);
const
newLine
=
buffer
.
lines
.
get
(
buffer
.
ybase
+
buffer
.
y
);
if
(
!
newLine
.
isWrapped
)
{
...
...
@@ -823,17 +860,7 @@ export class TerminalInstance implements ITerminalInstance {
while
(
lineIndex
>=
0
&&
buffer
.
lines
.
get
(
lineIndex
--
).
isWrapped
)
{
lineData
=
buffer
.
translateBufferLineToString
(
lineIndex
,
false
)
+
lineData
;
}
this
.
_onLineDataListeners
.
forEach
(
listener
=>
{
try
{
listener
(
lineData
);
}
catch
(
err
)
{
console
.
error
(
`onLineData listener threw`
,
err
);
}
});
}
public
onExit
(
listener
:
(
exitCode
:
number
)
=>
void
):
lifecycle
.
IDisposable
{
return
this
.
_processManager
.
onProcessExit
(
listener
);
this
.
_onLineData
.
fire
(
lineData
);
}
public
updateConfig
():
void
{
...
...
@@ -905,6 +932,21 @@ export class TerminalInstance implements ITerminalInstance {
return
;
}
if
(
this
.
_xterm
)
{
this
.
_xterm
.
element
.
style
.
width
=
terminalWidth
+
'
px
'
;
}
this
.
_resize
();
}
private
_resize
():
void
{
let
cols
=
this
.
_cols
;
let
rows
=
this
.
_rows
;
if
(
this
.
_dimensionsOverride
&&
this
.
_dimensionsOverride
.
cols
&&
this
.
_dimensionsOverride
.
rows
)
{
cols
=
Math
.
min
(
Math
.
max
(
this
.
_dimensionsOverride
.
cols
,
2
),
this
.
_cols
);
rows
=
Math
.
min
(
Math
.
max
(
this
.
_dimensionsOverride
.
rows
,
2
),
this
.
_rows
);
}
if
(
this
.
_xterm
)
{
const
font
=
this
.
_configHelper
.
getFont
(
this
.
_xterm
);
...
...
@@ -921,8 +963,11 @@ export class TerminalInstance implements ITerminalInstance {
this
.
_safeSetOption
(
'
drawBoldTextInBrightColors
'
,
config
.
drawBoldTextInBrightColors
);
}
this
.
_xterm
.
resize
(
this
.
_cols
,
this
.
_rows
);
this
.
_xterm
.
element
.
style
.
width
=
terminalWidth
+
'
px
'
;
if
(
cols
!==
this
.
_xterm
.
getOption
(
'
cols
'
)
||
rows
!==
this
.
_xterm
.
getOption
(
'
rows
'
))
{
this
.
_onDimensionsChanged
.
fire
();
}
this
.
_xterm
.
resize
(
cols
,
rows
);
if
(
this
.
_isVisible
)
{
// Force the renderer to unpause by simulating an IntersectionObserver event. This
// is to fix an issue where dragging the window to the top of the screen to maximize
...
...
@@ -935,7 +980,7 @@ export class TerminalInstance implements ITerminalInstance {
}
if
(
this
.
_processManager
)
{
this
.
_processManager
.
ptyProcessReady
.
then
(()
=>
this
.
_processManager
.
setDimensions
(
this
.
_cols
,
this
.
_
rows
));
this
.
_processManager
.
ptyProcessReady
.
then
(()
=>
this
.
_processManager
.
setDimensions
(
cols
,
rows
));
}
}
...
...
@@ -964,6 +1009,11 @@ export class TerminalInstance implements ITerminalInstance {
}
}
public
setDimensions
(
dimensions
:
ITerminalDimensions
):
void
{
this
.
_dimensionsOverride
=
dimensions
;
this
.
_resize
();
}
private
_getXtermTheme
(
theme
?:
ITheme
):
any
{
if
(
!
theme
)
{
theme
=
this
.
_themeService
.
getTheme
();
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts
浏览文件 @
8d4466df
...
...
@@ -121,6 +121,7 @@ export class TerminalLinkHandler {
}
public
dispose
():
void
{
this
.
_xterm
=
null
;
this
.
_hoverDisposables
=
dispose
(
this
.
_hoverDisposables
);
this
.
_mouseMoveDisposable
=
dispose
(
this
.
_mouseMoveDisposable
);
}
...
...
@@ -172,7 +173,7 @@ export class TerminalLinkHandler {
}
private
_handleHypertextLink
(
url
:
string
):
void
{
le
t
uri
=
Uri
.
parse
(
url
);
cons
t
uri
=
Uri
.
parse
(
url
);
this
.
_openerService
.
open
(
uri
);
}
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts
浏览文件 @
8d4466df
...
...
@@ -77,7 +77,7 @@ export class TerminalPanel extends Panel {
}
if
(
e
.
affectsConfiguration
(
'
terminal.integrated.fontFamily
'
)
||
e
.
affectsConfiguration
(
'
editor.fontFamily
'
))
{
le
t
configHelper
=
this
.
_terminalService
.
configHelper
;
cons
t
configHelper
=
this
.
_terminalService
.
configHelper
;
if
(
configHelper
instanceof
TerminalConfigHelper
)
{
if
(
!
configHelper
.
configFontIsMonospace
())
{
const
choices
:
IPromptChoice
[]
=
[{
...
...
@@ -203,7 +203,7 @@ export class TerminalPanel extends Panel {
this
.
_terminalService
.
getActiveInstance
().
focus
();
}
else
if
(
event
.
which
===
3
)
{
if
(
this
.
_terminalService
.
configHelper
.
config
.
rightClickBehavior
===
'
copyPaste
'
)
{
le
t
terminal
=
this
.
_terminalService
.
getActiveInstance
();
cons
t
terminal
=
this
.
_terminalService
.
getActiveInstance
();
if
(
terminal
.
hasSelection
())
{
terminal
.
copySelection
();
terminal
.
clearSelection
();
...
...
@@ -230,7 +230,7 @@ export class TerminalPanel extends Panel {
}
if
(
event
.
which
===
1
)
{
le
t
terminal
=
this
.
_terminalService
.
getActiveInstance
();
cons
t
terminal
=
this
.
_terminalService
.
getActiveInstance
();
if
(
terminal
.
hasSelection
())
{
terminal
.
copySelection
();
}
...
...
@@ -240,7 +240,7 @@ export class TerminalPanel extends Panel {
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_parentDomElement
,
'
contextmenu
'
,
(
event
:
MouseEvent
)
=>
{
if
(
!
this
.
_cancelContextMenu
)
{
const
standardEvent
=
new
StandardMouseEvent
(
event
);
le
t
anchor
:
{
x
:
number
,
y
:
number
}
=
{
x
:
standardEvent
.
posx
,
y
:
standardEvent
.
posy
};
cons
t
anchor
:
{
x
:
number
,
y
:
number
}
=
{
x
:
standardEvent
.
posx
,
y
:
standardEvent
.
posy
};
this
.
_contextMenuService
.
showContextMenu
({
getAnchor
:
()
=>
anchor
,
getActions
:
()
=>
TPromise
.
as
(
this
.
_getContextMenuActions
()),
...
...
@@ -269,7 +269,7 @@ export class TerminalPanel extends Panel {
// Check if files were dragged from the tree explorer
let
path
:
string
;
le
t
resources
=
e
.
dataTransfer
.
getData
(
DataTransfers
.
RESOURCES
);
cons
t
resources
=
e
.
dataTransfer
.
getData
(
DataTransfers
.
RESOURCES
);
if
(
resources
)
{
path
=
URI
.
parse
(
JSON
.
parse
(
resources
)[
0
]).
path
;
}
else
if
(
e
.
dataTransfer
.
files
.
length
>
0
)
{
...
...
@@ -315,15 +315,15 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
}
// Borrow the editor's hover background for now
le
t
hoverBackground
=
theme
.
getColor
(
editorHoverBackground
);
cons
t
hoverBackground
=
theme
.
getColor
(
editorHoverBackground
);
if
(
hoverBackground
)
{
collector
.
addRule
(
`.monaco-workbench .panel.integrated-terminal .terminal-message-widget { background-color:
${
hoverBackground
}
; }`
);
}
le
t
hoverBorder
=
theme
.
getColor
(
editorHoverBorder
);
cons
t
hoverBorder
=
theme
.
getColor
(
editorHoverBorder
);
if
(
hoverBorder
)
{
collector
.
addRule
(
`.monaco-workbench .panel.integrated-terminal .terminal-message-widget { border: 1px solid
${
hoverBorder
}
; }`
);
}
le
t
hoverForeground
=
theme
.
getColor
(
editorForeground
);
cons
t
hoverForeground
=
theme
.
getColor
(
editorForeground
);
if
(
hoverForeground
)
{
collector
.
addRule
(
`.monaco-workbench .panel.integrated-terminal .terminal-message-widget { color:
${
hoverForeground
}
; }`
);
}
...
...
src/vs/workbench/parts/terminal/electron-browser/terminalService.ts
浏览文件 @
8d4466df
...
...
@@ -91,8 +91,12 @@ export class TerminalService extends AbstractTerminalService implements ITermina
return
instance
;
}
public
createTerminalRenderer
(
name
:
string
):
ITerminalInstance
{
return
this
.
createTerminal
({
name
,
isRendererOnly
:
true
});
}
public
createInstance
(
terminalFocusContextKey
:
IContextKey
<
boolean
>
,
configHelper
:
ITerminalConfigHelper
,
container
:
HTMLElement
,
shellLaunchConfig
:
IShellLaunchConfig
,
doCreateProcess
:
boolean
):
ITerminalInstance
{
const
instance
=
this
.
_instantiationService
.
createInstance
(
TerminalInstance
,
terminalFocusContextKey
,
configHelper
,
container
,
shellLaunchConfig
,
true
);
const
instance
=
this
.
_instantiationService
.
createInstance
(
TerminalInstance
,
terminalFocusContextKey
,
configHelper
,
container
,
shellLaunchConfig
);
this
.
_onInstanceCreated
.
fire
(
instance
);
return
instance
;
}
...
...
@@ -109,7 +113,7 @@ export class TerminalService extends AbstractTerminalService implements ITermina
public
focusFindWidget
():
TPromise
<
void
>
{
return
this
.
showPanel
(
false
).
then
(()
=>
{
le
t
panel
=
this
.
_panelService
.
getActivePanel
()
as
TerminalPanel
;
cons
t
panel
=
this
.
_panelService
.
getActivePanel
()
as
TerminalPanel
;
panel
.
focusFindWidget
();
this
.
_findWidgetVisible
.
set
(
true
);
});
...
...
src/vs/workbench/parts/terminal/node/terminalCommandTracker.ts
浏览文件 @
8d4466df
...
...
@@ -5,6 +5,7 @@
import
{
Terminal
,
IMarker
}
from
'
vscode-xterm
'
;
import
{
ITerminalCommandTracker
}
from
'
vs/workbench/parts/terminal/common/terminal
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
/**
* The minimize size of the prompt in which to assume the line is a command.
...
...
@@ -21,7 +22,7 @@ export enum ScrollPosition {
Middle
}
export
class
TerminalCommandTracker
implements
ITerminalCommandTracker
{
export
class
TerminalCommandTracker
implements
ITerminalCommandTracker
,
IDisposable
{
private
_currentMarker
:
IMarker
|
Boundary
=
Boundary
.
Bottom
;
private
_selectionStart
:
IMarker
|
Boundary
|
null
=
null
;
private
_isDisposable
:
boolean
=
false
;
...
...
@@ -32,6 +33,10 @@ export class TerminalCommandTracker implements ITerminalCommandTracker {
this
.
_xterm
.
on
(
'
key
'
,
key
=>
this
.
_onKey
(
key
));
}
public
dispose
():
void
{
this
.
_xterm
=
null
;
}
private
_onKey
(
key
:
string
):
void
{
if
(
key
===
'
\
x0d
'
)
{
this
.
_onEnter
();
...
...
@@ -194,7 +199,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker {
if
(
this
.
_currentMarker
===
Boundary
.
Bottom
)
{
this
.
_currentMarker
=
this
.
_xterm
.
addMarker
(
this
.
_getOffset
()
-
1
);
}
else
{
le
t
offset
=
this
.
_getOffset
();
cons
t
offset
=
this
.
_getOffset
();
if
(
this
.
_isDisposable
)
{
this
.
_currentMarker
.
dispose
();
}
...
...
@@ -217,7 +222,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker {
if
(
this
.
_currentMarker
===
Boundary
.
Top
)
{
this
.
_currentMarker
=
this
.
_xterm
.
addMarker
(
this
.
_getOffset
()
+
1
);
}
else
{
le
t
offset
=
this
.
_getOffset
();
cons
t
offset
=
this
.
_getOffset
();
if
(
this
.
_isDisposable
)
{
this
.
_currentMarker
.
dispose
();
}
...
...
src/vs/workbench/parts/terminal/node/terminalEnvironment.ts
浏览文件 @
8d4466df
...
...
@@ -25,9 +25,9 @@ export function mergeEnvironments(parent: IStringDictionary<string>, other: IStr
// On Windows apply the new values ignoring case, while still retaining
// the case of the original key.
if
(
platform
.
isWindows
)
{
for
(
le
t
configKey
in
other
)
{
for
(
cons
t
configKey
in
other
)
{
let
actualKey
=
configKey
;
for
(
le
t
envKey
in
parent
)
{
for
(
cons
t
envKey
in
parent
)
{
if
(
configKey
.
toLowerCase
()
===
envKey
.
toLowerCase
())
{
actualKey
=
envKey
;
break
;
...
...
src/vs/workbench/parts/terminal/node/terminalProcess.ts
浏览文件 @
8d4466df
...
...
@@ -9,7 +9,7 @@ import * as pty from 'node-pty';
// The pty process needs to be run in its own child process to get around maxing out CPU on Mac,
// see https://github.com/electron/electron/issues/38
var
shellName
:
string
;
let
shellName
:
string
;
if
(
os
.
platform
()
===
'
win32
'
)
{
shellName
=
path
.
basename
(
process
.
env
.
PTYSHELL
);
}
else
{
...
...
@@ -17,12 +17,12 @@ if (os.platform() === 'win32') {
// color prompt as defined in the default ~/.bashrc file.
shellName
=
'
xterm-256color
'
;
}
var
shell
=
process
.
env
.
PTYSHELL
;
var
args
=
getArgs
();
var
cwd
=
process
.
env
.
PTYCWD
;
var
cols
=
process
.
env
.
PTYCOLS
;
var
rows
=
process
.
env
.
PTYROWS
;
var
currentTitle
=
''
;
const
shell
=
process
.
env
.
PTYSHELL
;
const
args
=
getArgs
();
const
cwd
=
process
.
env
.
PTYCWD
;
const
cols
=
process
.
env
.
PTYCOLS
;
const
rows
=
process
.
env
.
PTYROWS
;
let
currentTitle
=
''
;
setupPlanB
(
Number
(
process
.
env
.
PTYPID
));
cleanEnv
();
...
...
@@ -34,7 +34,7 @@ interface IOptions {
rows
?:
number
;
}
var
options
:
IOptions
=
{
const
options
:
IOptions
=
{
name
:
shellName
,
cwd
};
...
...
@@ -43,10 +43,10 @@ if (cols && rows) {
options
.
rows
=
parseInt
(
rows
,
10
);
}
var
ptyProcess
=
pty
.
spawn
(
shell
,
args
,
options
);
const
ptyProcess
=
pty
.
spawn
(
shell
,
args
,
options
);
var
closeTimeout
:
number
;
var
exitCode
:
number
;
let
closeTimeout
:
number
;
let
exitCode
:
number
;
// Allow any trailing data events to be sent before the exit event is sent.
// See https://github.com/Tyriar/node-pty/issues/72
...
...
@@ -95,8 +95,8 @@ function getArgs(): string | string[] {
if
(
process
.
env
[
'
PTYSHELLCMDLINE
'
])
{
return
process
.
env
[
'
PTYSHELLCMDLINE
'
];
}
var
args
=
[];
var
i
=
0
;
const
args
=
[];
let
i
=
0
;
while
(
process
.
env
[
'
PTYSHELLARG
'
+
i
])
{
args
.
push
(
process
.
env
[
'
PTYSHELLARG
'
+
i
]);
i
++
;
...
...
@@ -105,7 +105,7 @@ function getArgs(): string | string[] {
}
function
cleanEnv
()
{
var
keys
=
[
const
keys
=
[
'
AMD_ENTRYPOINT
'
,
'
ELECTRON_NO_ASAR
'
,
'
ELECTRON_RUN_AS_NODE
'
,
...
...
@@ -124,7 +124,7 @@ function cleanEnv() {
delete
process
.
env
[
key
];
}
});
var
i
=
0
;
let
i
=
0
;
while
(
process
.
env
[
'
PTYSHELLARG
'
+
i
])
{
delete
process
.
env
[
'
PTYSHELLARG
'
+
i
];
i
++
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录