Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
a4b49166
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,发现更多精彩内容 >>
提交
a4b49166
编写于
3月 06, 2019
作者:
S
Sandeep Somavarapu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix #69110
上级
4bfec9c8
变更
9
展开全部
显示空白变更内容
内联
并排
Showing
9 changed file
with
917 addition
and
6 deletion
+917
-6
src/tsconfig.strictNullChecks.json
src/tsconfig.strictNullChecks.json
+3
-3
src/vs/workbench/api/node/extHostOutputService.ts
src/vs/workbench/api/node/extHostOutputService.ts
+1
-1
src/vs/workbench/contrib/output/browser/output.contribution.ts
...s/workbench/contrib/output/browser/output.contribution.ts
+1
-1
src/vs/workbench/contrib/output/browser/outputServices.ts
src/vs/workbench/contrib/output/browser/outputServices.ts
+291
-0
src/vs/workbench/services/output/common/outputChannelModel.ts
...vs/workbench/services/output/common/outputChannelModel.ts
+413
-0
src/vs/workbench/services/output/common/outputChannelModelService.ts
...bench/services/output/common/outputChannelModelService.ts
+14
-0
src/vs/workbench/services/output/node/outputAppender.ts
src/vs/workbench/services/output/node/outputAppender.ts
+0
-0
src/vs/workbench/services/output/node/outputChannelModelService.ts
...rkbench/services/output/node/outputChannelModelService.ts
+192
-0
src/vs/workbench/workbench.main.ts
src/vs/workbench/workbench.main.ts
+2
-1
未找到文件。
src/tsconfig.strictNullChecks.json
浏览文件 @
a4b49166
...
...
@@ -27,6 +27,7 @@
"./vs/workbench/services/files/node/watcher/**/*"
,
"./vs/workbench/services/themes/**/*.ts"
,
"./vs/workbench/services/bulkEdit/**/*.ts"
,
"./vs/workbench/services/output/**/*.ts"
,
"./vs/workbench/services/progress/**/*.ts"
,
"./vs/workbench/services/preferences/**/*.ts"
,
"./vs/workbench/services/timer/**/*.ts"
,
...
...
@@ -313,9 +314,8 @@
"./vs/workbench/contrib/output/common/output.ts"
,
"./vs/workbench/contrib/output/common/outputLinkComputer.ts"
,
"./vs/workbench/contrib/output/common/outputLinkProvider.ts"
,
"./vs/workbench/contrib/output/electron-browser/output.contribution.ts"
,
"./vs/workbench/contrib/output/electron-browser/outputServices.ts"
,
"./vs/workbench/contrib/output/node/outputAppender.ts"
,
"./vs/workbench/contrib/output/browser/output.contribution.ts"
,
"./vs/workbench/contrib/output/browser/outputServices.ts"
,
"./vs/workbench/contrib/preferences/browser/preferencesActions.ts"
,
"./vs/workbench/contrib/preferences/browser/preferencesWidgets.ts"
,
"./vs/workbench/contrib/preferences/browser/settingsLayout.ts"
,
...
...
src/vs/workbench/api/node/extHostOutputService.ts
浏览文件 @
a4b49166
...
...
@@ -7,7 +7,7 @@ import { MainContext, MainThreadOutputServiceShape, IMainContext, ExtHostOutputS
import
*
as
vscode
from
'
vscode
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
join
}
from
'
vs/base/common/path
'
;
import
{
OutputAppender
}
from
'
vs/workbench/
contrib
/output/node/outputAppender
'
;
import
{
OutputAppender
}
from
'
vs/workbench/
services
/output/node/outputAppender
'
;
import
{
toLocalISOString
}
from
'
vs/base/common/date
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Disposable
,
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
...
...
src/vs/workbench/contrib/output/
electron-
browser/output.contribution.ts
→
src/vs/workbench/contrib/output/browser/output.contribution.ts
浏览文件 @
a4b49166
...
...
@@ -10,7 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import
{
MenuId
,
MenuRegistry
,
SyncActionDescriptor
,
registerAction
}
from
'
vs/platform/actions/common/actions
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
import
{
IWorkbenchActionRegistry
,
Extensions
as
ActionExtensions
}
from
'
vs/workbench/common/actions
'
;
import
{
OutputService
,
LogContentProvider
}
from
'
vs/workbench/contrib/output/
electron-
browser/outputServices
'
;
import
{
OutputService
,
LogContentProvider
}
from
'
vs/workbench/contrib/output/browser/outputServices
'
;
import
{
ToggleOutputAction
,
ClearOutputAction
,
OpenLogOutputFile
,
ShowLogsOutputChannelAction
,
OpenOutputLogFileAction
}
from
'
vs/workbench/contrib/output/browser/outputActions
'
;
import
{
OUTPUT_MODE_ID
,
OUTPUT_MIME
,
OUTPUT_PANEL_ID
,
IOutputService
,
CONTEXT_IN_OUTPUT
,
LOG_SCHEME
,
LOG_MODE_ID
,
LOG_MIME
,
CONTEXT_ACTIVE_LOG_OUTPUT
}
from
'
vs/workbench/contrib/output/common/output
'
;
import
{
PanelRegistry
,
Extensions
,
PanelDescriptor
}
from
'
vs/workbench/browser/panel
'
;
...
...
src/vs/workbench/contrib/output/browser/outputServices.ts
0 → 100644
浏览文件 @
a4b49166
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
nls
from
'
vs/nls
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
IDisposable
,
dispose
,
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IStorageService
,
StorageScope
}
from
'
vs/platform/storage/common/storage
'
;
import
{
Registry
}
from
'
vs/platform/registry/common/platform
'
;
import
{
EditorOptions
}
from
'
vs/workbench/common/editor
'
;
import
{
IOutputChannelDescriptor
,
IOutputChannel
,
IOutputService
,
Extensions
,
OUTPUT_PANEL_ID
,
IOutputChannelRegistry
,
OUTPUT_SCHEME
,
LOG_SCHEME
,
CONTEXT_ACTIVE_LOG_OUTPUT
,
LOG_MIME
,
OUTPUT_MIME
}
from
'
vs/workbench/contrib/output/common/output
'
;
import
{
OutputPanel
}
from
'
vs/workbench/contrib/output/browser/outputPanel
'
;
import
{
IPanelService
}
from
'
vs/workbench/services/panel/common/panelService
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
OutputLinkProvider
}
from
'
vs/workbench/contrib/output/common/outputLinkProvider
'
;
import
{
ITextModelService
,
ITextModelContentProvider
}
from
'
vs/editor/common/services/resolverService
'
;
import
{
ITextModel
}
from
'
vs/editor/common/model
'
;
import
{
IPanel
}
from
'
vs/workbench/common/panel
'
;
import
{
ResourceEditorInput
}
from
'
vs/workbench/common/editor/resourceEditorInput
'
;
import
{
IEnvironmentService
}
from
'
vs/platform/environment/common/environment
'
;
import
{
IWindowService
}
from
'
vs/platform/windows/common/windows
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
ILifecycleService
}
from
'
vs/platform/lifecycle/common/lifecycle
'
;
import
{
IContextKeyService
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
CancellationToken
}
from
'
vs/base/common/cancellation
'
;
import
{
IOutputChannelModel
,
IOutputChannelModelService
}
from
'
vs/workbench/services/output/common/outputChannelModel
'
;
const
OUTPUT_ACTIVE_CHANNEL_KEY
=
'
output.activechannel
'
;
class
OutputChannel
extends
Disposable
implements
IOutputChannel
{
scrollLock
:
boolean
=
false
;
readonly
model
:
IOutputChannelModel
;
readonly
id
:
string
;
readonly
label
:
string
;
constructor
(
readonly
outputChannelDescriptor
:
IOutputChannelDescriptor
,
@
IOutputChannelModelService
outputChannelModelService
:
IOutputChannelModelService
)
{
super
();
this
.
id
=
outputChannelDescriptor
.
id
;
this
.
label
=
outputChannelDescriptor
.
label
;
this
.
model
=
this
.
_register
(
outputChannelModelService
.
createOutputChannelModel
(
this
.
id
,
URI
.
from
({
scheme
:
OUTPUT_SCHEME
,
path
:
this
.
id
}),
outputChannelDescriptor
.
log
?
LOG_MIME
:
OUTPUT_MIME
,
outputChannelDescriptor
.
file
));
}
append
(
output
:
string
):
void
{
this
.
model
.
append
(
output
);
}
update
():
void
{
this
.
model
.
update
();
}
clear
(
till
?:
number
):
void
{
this
.
model
.
clear
(
till
);
}
}
export
class
OutputService
extends
Disposable
implements
IOutputService
,
ITextModelContentProvider
{
public
_serviceBrand
:
any
;
private
channels
:
Map
<
string
,
OutputChannel
>
=
new
Map
<
string
,
OutputChannel
>
();
private
activeChannelIdInStorage
:
string
;
private
activeChannel
:
OutputChannel
|
null
;
private
readonly
_onActiveOutputChannel
=
new
Emitter
<
string
>
();
readonly
onActiveOutputChannel
:
Event
<
string
>
=
this
.
_onActiveOutputChannel
.
event
;
private
_outputPanel
:
OutputPanel
;
constructor
(
@
IStorageService
private
readonly
storageService
:
IStorageService
,
@
IInstantiationService
private
readonly
instantiationService
:
IInstantiationService
,
@
IPanelService
private
readonly
panelService
:
IPanelService
,
@
IWorkspaceContextService
contextService
:
IWorkspaceContextService
,
@
ITextModelService
textModelResolverService
:
ITextModelService
,
@
IEnvironmentService
environmentService
:
IEnvironmentService
,
@
IWindowService
windowService
:
IWindowService
,
@
ILogService
private
readonly
logService
:
ILogService
,
@
ILifecycleService
private
readonly
lifecycleService
:
ILifecycleService
,
@
IContextKeyService
private
readonly
contextKeyService
:
IContextKeyService
,
)
{
super
();
this
.
activeChannelIdInStorage
=
this
.
storageService
.
get
(
OUTPUT_ACTIVE_CHANNEL_KEY
,
StorageScope
.
WORKSPACE
,
''
);
// Register as text model content provider for output
textModelResolverService
.
registerTextModelContentProvider
(
OUTPUT_SCHEME
,
this
);
instantiationService
.
createInstance
(
OutputLinkProvider
);
// Create output channels for already registered channels
const
registry
=
Registry
.
as
<
IOutputChannelRegistry
>
(
Extensions
.
OutputChannels
);
for
(
const
channelIdentifier
of
registry
.
getChannels
())
{
this
.
onDidRegisterChannel
(
channelIdentifier
.
id
);
}
this
.
_register
(
registry
.
onDidRegisterChannel
(
this
.
onDidRegisterChannel
,
this
));
this
.
_register
(
panelService
.
onDidPanelOpen
(({
panel
,
focus
})
=>
this
.
onDidPanelOpen
(
panel
,
!
focus
),
this
));
this
.
_register
(
panelService
.
onDidPanelClose
(
this
.
onDidPanelClose
,
this
));
// Set active channel to first channel if not set
if
(
!
this
.
activeChannel
)
{
const
channels
=
this
.
getChannelDescriptors
();
this
.
activeChannel
=
channels
&&
channels
.
length
>
0
?
this
.
getChannel
(
channels
[
0
].
id
)
:
null
;
}
this
.
_register
(
this
.
lifecycleService
.
onShutdown
(()
=>
this
.
dispose
()));
this
.
_register
(
this
.
storageService
.
onWillSaveState
(()
=>
this
.
saveState
()));
}
provideTextContent
(
resource
:
URI
):
Promise
<
ITextModel
>
|
null
{
const
channel
=
<
OutputChannel
>
this
.
getChannel
(
resource
.
path
);
if
(
channel
)
{
return
channel
.
model
.
loadModel
();
}
return
null
;
}
showChannel
(
id
:
string
,
preserveFocus
?:
boolean
):
Promise
<
void
>
{
const
channel
=
this
.
getChannel
(
id
);
if
(
!
channel
||
this
.
isChannelShown
(
channel
))
{
if
(
this
.
_outputPanel
&&
!
preserveFocus
)
{
this
.
_outputPanel
.
focus
();
}
return
Promise
.
resolve
(
undefined
);
}
this
.
activeChannel
=
channel
;
let
promise
:
Promise
<
void
>
;
if
(
this
.
isPanelShown
())
{
promise
=
this
.
doShowChannel
(
channel
,
!!
preserveFocus
);
}
else
{
this
.
panelService
.
openPanel
(
OUTPUT_PANEL_ID
);
promise
=
this
.
doShowChannel
(
this
.
activeChannel
,
!!
preserveFocus
);
}
return
promise
.
then
(()
=>
this
.
_onActiveOutputChannel
.
fire
(
id
));
}
getChannel
(
id
:
string
):
OutputChannel
|
null
{
return
this
.
channels
.
get
(
id
)
||
null
;
}
getChannelDescriptors
():
IOutputChannelDescriptor
[]
{
return
Registry
.
as
<
IOutputChannelRegistry
>
(
Extensions
.
OutputChannels
).
getChannels
();
}
getActiveChannel
():
IOutputChannel
|
null
{
return
this
.
activeChannel
;
}
private
onDidRegisterChannel
(
channelId
:
string
):
void
{
const
channel
=
this
.
createChannel
(
channelId
);
this
.
channels
.
set
(
channelId
,
channel
);
if
(
this
.
activeChannelIdInStorage
===
channelId
)
{
this
.
activeChannel
=
channel
;
this
.
onDidPanelOpen
(
this
.
panelService
.
getActivePanel
(),
true
)
.
then
(()
=>
this
.
_onActiveOutputChannel
.
fire
(
channelId
));
}
}
private
onDidPanelOpen
(
panel
:
IPanel
|
null
,
preserveFocus
:
boolean
):
Promise
<
void
>
{
if
(
panel
&&
panel
.
getId
()
===
OUTPUT_PANEL_ID
)
{
this
.
_outputPanel
=
<
OutputPanel
>
this
.
panelService
.
getActivePanel
();
if
(
this
.
activeChannel
)
{
return
this
.
doShowChannel
(
this
.
activeChannel
,
preserveFocus
);
}
}
return
Promise
.
resolve
(
undefined
);
}
private
onDidPanelClose
(
panel
:
IPanel
):
void
{
if
(
this
.
_outputPanel
&&
panel
.
getId
()
===
OUTPUT_PANEL_ID
)
{
CONTEXT_ACTIVE_LOG_OUTPUT
.
bindTo
(
this
.
contextKeyService
).
set
(
false
);
this
.
_outputPanel
.
clearInput
();
}
}
private
createChannel
(
id
:
string
):
OutputChannel
{
const
channelDisposables
:
IDisposable
[]
=
[];
const
channel
=
this
.
instantiateChannel
(
id
);
channel
.
model
.
onDidAppendedContent
(()
=>
{
if
(
!
channel
.
scrollLock
)
{
const
panel
=
this
.
panelService
.
getActivePanel
();
if
(
panel
&&
panel
.
getId
()
===
OUTPUT_PANEL_ID
&&
this
.
isChannelShown
(
channel
))
{
let
outputPanel
=
<
OutputPanel
>
panel
;
outputPanel
.
revealLastLine
();
}
}
},
channelDisposables
);
channel
.
model
.
onDispose
(()
=>
{
if
(
this
.
activeChannel
===
channel
)
{
const
channels
=
this
.
getChannelDescriptors
();
const
channel
=
channels
.
length
?
this
.
getChannel
(
channels
[
0
].
id
)
:
null
;
if
(
channel
&&
this
.
isPanelShown
())
{
this
.
showChannel
(
channel
.
id
,
true
);
}
else
{
this
.
activeChannel
=
channel
;
if
(
this
.
activeChannel
)
{
this
.
_onActiveOutputChannel
.
fire
(
this
.
activeChannel
.
id
);
}
}
}
Registry
.
as
<
IOutputChannelRegistry
>
(
Extensions
.
OutputChannels
).
removeChannel
(
id
);
dispose
(
channelDisposables
);
},
channelDisposables
);
return
channel
;
}
private
instantiateChannel
(
id
:
string
):
OutputChannel
{
const
channelData
=
Registry
.
as
<
IOutputChannelRegistry
>
(
Extensions
.
OutputChannels
).
getChannel
(
id
);
if
(
!
channelData
)
{
this
.
logService
.
error
(
`Channel '
${
id
}
' is not registered yet`
);
throw
new
Error
(
`Channel '
${
id
}
' is not registered yet`
);
}
return
this
.
instantiationService
.
createInstance
(
OutputChannel
,
channelData
);
}
private
doShowChannel
(
channel
:
OutputChannel
,
preserveFocus
:
boolean
):
Promise
<
void
>
{
if
(
this
.
_outputPanel
)
{
CONTEXT_ACTIVE_LOG_OUTPUT
.
bindTo
(
this
.
contextKeyService
).
set
(
!!
channel
.
outputChannelDescriptor
.
file
&&
channel
.
outputChannelDescriptor
.
log
);
return
this
.
_outputPanel
.
setInput
(
this
.
createInput
(
channel
),
EditorOptions
.
create
({
preserveFocus
}),
CancellationToken
.
None
)
.
then
(()
=>
{
if
(
!
preserveFocus
)
{
this
.
_outputPanel
.
focus
();
}
});
}
return
Promise
.
resolve
(
undefined
);
}
private
isChannelShown
(
channel
:
IOutputChannel
):
boolean
{
return
this
.
isPanelShown
()
&&
this
.
activeChannel
===
channel
;
}
private
isPanelShown
():
boolean
{
const
panel
=
this
.
panelService
.
getActivePanel
();
return
!!
panel
&&
panel
.
getId
()
===
OUTPUT_PANEL_ID
;
}
private
createInput
(
channel
:
IOutputChannel
):
ResourceEditorInput
{
const
resource
=
URI
.
from
({
scheme
:
OUTPUT_SCHEME
,
path
:
channel
.
id
});
return
this
.
instantiationService
.
createInstance
(
ResourceEditorInput
,
nls
.
localize
(
'
output
'
,
"
{0} - Output
"
,
channel
.
label
),
nls
.
localize
(
'
channel
'
,
"
Output channel for '{0}'
"
,
channel
.
label
),
resource
);
}
private
saveState
():
void
{
if
(
this
.
activeChannel
)
{
this
.
storageService
.
store
(
OUTPUT_ACTIVE_CHANNEL_KEY
,
this
.
activeChannel
.
id
,
StorageScope
.
WORKSPACE
);
}
}
}
export
class
LogContentProvider
{
private
channelModels
:
Map
<
string
,
IOutputChannelModel
>
=
new
Map
<
string
,
IOutputChannelModel
>
();
constructor
(
@
IOutputService
private
readonly
outputService
:
IOutputService
,
@
IOutputChannelModelService
private
readonly
outputChannelModelService
:
IOutputChannelModelService
)
{
}
provideTextContent
(
resource
:
URI
):
Promise
<
ITextModel
>
|
null
{
if
(
resource
.
scheme
===
LOG_SCHEME
)
{
let
channelModel
=
this
.
getChannelModel
(
resource
);
if
(
channelModel
)
{
return
channelModel
.
loadModel
();
}
}
return
null
;
}
private
getChannelModel
(
resource
:
URI
):
IOutputChannelModel
|
undefined
{
const
channelId
=
resource
.
path
;
let
channelModel
=
this
.
channelModels
.
get
(
channelId
);
if
(
!
channelModel
)
{
const
channelDisposables
:
IDisposable
[]
=
[];
const
outputChannelDescriptor
=
this
.
outputService
.
getChannelDescriptors
().
filter
(({
id
})
=>
id
===
channelId
)[
0
];
if
(
outputChannelDescriptor
&&
outputChannelDescriptor
.
file
)
{
channelModel
=
this
.
outputChannelModelService
.
createOutputChannelModel
(
channelId
,
resource
,
outputChannelDescriptor
.
log
?
LOG_MIME
:
OUTPUT_MIME
,
outputChannelDescriptor
.
file
);
channelModel
.
onDispose
(()
=>
dispose
(
channelDisposables
),
channelDisposables
);
this
.
channelModels
.
set
(
channelId
,
channelModel
);
}
}
return
channelModel
;
}
}
\ No newline at end of file
src/vs/workbench/
contrib/output/electron-browser/outputServices
.ts
→
src/vs/workbench/
services/output/common/outputChannelModel
.ts
浏览文件 @
a4b49166
此差异已折叠。
点击以展开。
src/vs/workbench/services/output/common/outputChannelModelService.ts
0 → 100644
浏览文件 @
a4b49166
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
IOutputChannelModelService
,
AsbtractOutputChannelModelService
}
from
'
vs/workbench/services/output/common/outputChannelModel
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
export
class
OutputChannelModelService
extends
AsbtractOutputChannelModelService
implements
IOutputChannelModelService
{
_serviceBrand
:
any
;
}
registerSingleton
(
IOutputChannelModelService
,
OutputChannelModelService
);
src/vs/workbench/
contrib
/output/node/outputAppender.ts
→
src/vs/workbench/
services
/output/node/outputAppender.ts
浏览文件 @
a4b49166
文件已移动
src/vs/workbench/services/output/node/outputChannelModelService.ts
0 → 100644
浏览文件 @
a4b49166
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
*
as
extfs
from
'
vs/base/node/extfs
'
;
import
{
dirname
,
join
}
from
'
vs/base/common/path
'
;
import
{
ITextModel
}
from
'
vs/editor/common/model
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
ThrottledDelayer
}
from
'
vs/base/common/async
'
;
import
{
IFileService
}
from
'
vs/platform/files/common/files
'
;
import
{
IModelService
}
from
'
vs/editor/common/services/modelService
'
;
import
{
IModeService
}
from
'
vs/editor/common/services/modeService
'
;
import
{
toDisposable
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
IOutputChannelModel
,
AbstractFileOutputChannelModel
,
IOutputChannelModelService
,
AsbtractOutputChannelModelService
}
from
'
vs/workbench/services/output/common/outputChannelModel
'
;
import
{
OutputAppender
}
from
'
vs/workbench/services/output/node/outputAppender
'
;
import
{
IEnvironmentService
}
from
'
vs/platform/environment/common/environment
'
;
import
{
IWindowService
}
from
'
vs/platform/windows/common/windows
'
;
import
{
toLocalISOString
}
from
'
vs/base/common/date
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
let
watchingOutputDir
=
false
;
let
callbacks
:
((
eventType
:
string
,
fileName
?:
string
)
=>
void
)[]
=
[];
function
watchOutputDirectory
(
outputDir
:
string
,
logService
:
ILogService
,
onChange
:
(
eventType
:
string
,
fileName
:
string
)
=>
void
):
IDisposable
{
callbacks
.
push
(
onChange
);
if
(
!
watchingOutputDir
)
{
const
watcherDisposable
=
extfs
.
watch
(
outputDir
,
(
eventType
,
fileName
)
=>
{
for
(
const
callback
of
callbacks
)
{
callback
(
eventType
,
fileName
);
}
},
(
error
:
string
)
=>
{
logService
.
error
(
error
);
});
watchingOutputDir
=
true
;
return
toDisposable
(()
=>
{
callbacks
=
[];
watcherDisposable
.
dispose
();
});
}
return
toDisposable
(()
=>
{
});
}
class
OutputChannelBackedByFile
extends
AbstractFileOutputChannelModel
implements
IOutputChannelModel
{
private
appender
:
OutputAppender
;
private
appendedMessage
:
string
;
private
loadingFromFileInProgress
:
boolean
;
private
resettingDelayer
:
ThrottledDelayer
<
void
>
;
private
readonly
rotatingFilePath
:
string
;
constructor
(
id
:
string
,
modelUri
:
URI
,
mimeType
:
string
,
@
IWindowService
windowService
:
IWindowService
,
@
IEnvironmentService
environmentService
:
IEnvironmentService
,
@
IFileService
fileService
:
IFileService
,
@
IModelService
modelService
:
IModelService
,
@
IModeService
modeService
:
IModeService
,
@
ILogService
logService
:
ILogService
)
{
const
outputDir
=
join
(
environmentService
.
logsPath
,
`output_
${
windowService
.
getCurrentWindowId
()}
_
${
toLocalISOString
(
new
Date
()).
replace
(
/-|:|
\.\d
+Z$/g
,
''
)}
`
);
super
(
modelUri
,
mimeType
,
URI
.
file
(
join
(
outputDir
,
`
${
id
}
.log`
)),
fileService
,
modelService
,
modeService
);
this
.
appendedMessage
=
''
;
this
.
loadingFromFileInProgress
=
false
;
// Use one rotating file to check for main file reset
this
.
appender
=
new
OutputAppender
(
id
,
this
.
file
.
fsPath
);
this
.
rotatingFilePath
=
`
${
id
}
.1.log`
;
this
.
_register
(
watchOutputDirectory
(
dirname
(
this
.
file
.
fsPath
),
logService
,
(
eventType
,
file
)
=>
this
.
onFileChangedInOutputDirector
(
eventType
,
file
)));
this
.
resettingDelayer
=
new
ThrottledDelayer
<
void
>
(
50
);
}
append
(
message
:
string
):
void
{
// update end offset always as message is read
this
.
endOffset
=
this
.
endOffset
+
Buffer
.
from
(
message
).
byteLength
;
if
(
this
.
loadingFromFileInProgress
)
{
this
.
appendedMessage
+=
message
;
}
else
{
this
.
write
(
message
);
if
(
this
.
model
)
{
this
.
appendedMessage
+=
message
;
if
(
!
this
.
modelUpdater
.
isScheduled
())
{
this
.
modelUpdater
.
schedule
();
}
}
}
}
clear
(
till
?:
number
):
void
{
super
.
clear
(
till
);
this
.
appendedMessage
=
''
;
}
loadModel
():
Promise
<
ITextModel
>
{
this
.
loadingFromFileInProgress
=
true
;
if
(
this
.
modelUpdater
.
isScheduled
())
{
this
.
modelUpdater
.
cancel
();
}
this
.
appendedMessage
=
''
;
return
this
.
loadFile
()
.
then
(
content
=>
{
if
(
this
.
endOffset
!==
this
.
startOffset
+
Buffer
.
from
(
content
).
byteLength
)
{
// Queue content is not written into the file
// Flush it and load file again
this
.
flush
();
return
this
.
loadFile
();
}
return
content
;
})
.
then
(
content
=>
{
if
(
this
.
appendedMessage
)
{
this
.
write
(
this
.
appendedMessage
);
this
.
appendedMessage
=
''
;
}
this
.
loadingFromFileInProgress
=
false
;
return
this
.
createModel
(
content
);
});
}
private
resetModel
():
Promise
<
void
>
{
this
.
startOffset
=
0
;
this
.
endOffset
=
0
;
if
(
this
.
model
)
{
return
this
.
loadModel
().
then
(()
=>
undefined
);
}
return
Promise
.
resolve
(
undefined
);
}
private
loadFile
():
Promise
<
string
>
{
return
this
.
fileService
.
resolveContent
(
this
.
file
,
{
position
:
this
.
startOffset
,
encoding
:
'
utf8
'
})
.
then
(
content
=>
this
.
appendedMessage
?
content
.
value
+
this
.
appendedMessage
:
content
.
value
);
}
protected
updateModel
():
void
{
if
(
this
.
model
&&
this
.
appendedMessage
)
{
this
.
appendToModel
(
this
.
appendedMessage
);
this
.
appendedMessage
=
''
;
}
}
private
onFileChangedInOutputDirector
(
eventType
:
string
,
fileName
?:
string
):
void
{
// Check if rotating file has changed. It changes only when the main file exceeds its limit.
if
(
this
.
rotatingFilePath
===
fileName
)
{
this
.
resettingDelayer
.
trigger
(()
=>
this
.
resetModel
());
}
}
private
write
(
content
:
string
):
void
{
this
.
appender
.
append
(
content
);
}
private
flush
():
void
{
this
.
appender
.
flush
();
}
}
export
class
OutputChannelModelService
extends
AsbtractOutputChannelModelService
implements
IOutputChannelModelService
{
_serviceBrand
:
any
;
constructor
(
@
IInstantiationService
instantiationService
:
IInstantiationService
,
@
ILogService
private
readonly
logService
:
ILogService
,
@
ITelemetryService
private
readonly
telemetryService
:
ITelemetryService
)
{
super
(
instantiationService
);
}
createOutputChannelModel
(
id
:
string
,
modelUri
:
URI
,
mimeType
:
string
,
file
?:
URI
):
IOutputChannelModel
{
if
(
!
file
)
{
try
{
return
this
.
instantiationService
.
createInstance
(
OutputChannelBackedByFile
,
id
,
modelUri
,
mimeType
);
}
catch
(
e
)
{
// Do not crash if spdlog rotating logger cannot be loaded (workaround for https://github.com/Microsoft/vscode/issues/47883)
this
.
logService
.
error
(
e
);
/* __GDPR__
"output.channel.creation.error" : {}
*/
this
.
telemetryService
.
publicLog
(
'
output.channel.creation.error
'
);
}
}
return
super
.
createOutputChannelModel
(
id
,
modelUri
,
mimeType
,
file
);
}
}
registerSingleton
(
IOutputChannelModelService
,
OutputChannelModelService
);
src/vs/workbench/workbench.main.ts
浏览文件 @
a4b49166
...
...
@@ -69,6 +69,7 @@ import 'vs/workbench/services/progress/browser/progressService2';
import
'
vs/workbench/services/editor/browser/codeEditorService
'
;
import
'
vs/workbench/services/broadcast/electron-browser/broadcastService
'
;
import
'
vs/workbench/services/preferences/browser/preferencesService
'
;
import
'
vs/workbench/services/output/node/outputChannelModelService
'
;
import
'
vs/workbench/services/configuration/node/jsonEditingService
'
;
import
'
vs/workbench/services/textmodelResolver/common/textModelResolverService
'
;
import
'
vs/workbench/services/textfile/common/textFileService
'
;
...
...
@@ -155,7 +156,7 @@ import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen';
import
'
vs/workbench/contrib/extensions/electron-browser/extensionsViewlet
'
;
// Output Panel
import
'
vs/workbench/contrib/output/
electron-
browser/output.contribution
'
;
import
'
vs/workbench/contrib/output/browser/output.contribution
'
;
import
'
vs/workbench/contrib/output/browser/outputPanel
'
;
// Terminal
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录