Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
旅途_2012
vscode
提交
c49edf91
V
vscode
项目概览
旅途_2012
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c49edf91
编写于
7月 09, 2018
作者:
J
Johannes Rieken
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'joh/breadcrumbs'
上级
e89b02b4
5b4261c3
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
1218 addition
and
63 deletion
+1218
-63
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css
+40
-0
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts
+242
-0
src/vs/base/browser/ui/breadcrumbs/collapsed.svg
src/vs/base/browser/ui/breadcrumbs/collapsed.svg
+1
-0
src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg
src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg
+1
-0
src/vs/editor/contrib/documentSymbols/media/outlineTree.css
src/vs/editor/contrib/documentSymbols/media/outlineTree.css
+66
-0
src/vs/editor/contrib/documentSymbols/outlineTree.ts
src/vs/editor/contrib/documentSymbols/outlineTree.ts
+4
-3
src/vs/platform/theme/common/styler.ts
src/vs/platform/theme/common/styler.ts
+31
-1
src/vs/workbench/browser/parts/editor/editor.ts
src/vs/workbench/browser/parts/editor/editor.ts
+1
-1
src/vs/workbench/browser/parts/editor/editorBreadcrumbs.ts
src/vs/workbench/browser/parts/editor/editorBreadcrumbs.ts
+548
-0
src/vs/workbench/browser/parts/editor/editorBreadcrumbsModel.ts
.../workbench/browser/parts/editor/editorBreadcrumbsModel.ts
+166
-0
src/vs/workbench/browser/parts/editor/editorGroupView.ts
src/vs/workbench/browser/parts/editor/editorGroupView.ts
+44
-3
src/vs/workbench/browser/parts/editor/media/editorbreadcrumbs.css
...orkbench/browser/parts/editor/media/editorbreadcrumbs.css
+13
-0
src/vs/workbench/parts/outline/electron-browser/outlinePanel.css
...workbench/parts/outline/electron-browser/outlinePanel.css
+0
-53
src/vs/workbench/services/group/common/editorGroupsService.ts
...vs/workbench/services/group/common/editorGroupsService.ts
+13
-1
src/vs/workbench/test/browser/parts/editor/editorBreadcrumbModel.test.ts
...h/test/browser/parts/editor/editorBreadcrumbModel.test.ts
+46
-0
src/vs/workbench/test/workbenchTestServices.ts
src/vs/workbench/test/workbenchTestServices.ts
+2
-1
未找到文件。
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css
0 → 100644
浏览文件 @
c49edf91
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-breadcrumbs
{
user-select
:
none
;
display
:
flex
;
flex-direction
:
row
;
flex-wrap
:
nowrap
;
justify-content
:
flex-start
;
}
.monaco-breadcrumbs
.monaco-breadcrumb-item
{
display
:
flex
;
align-items
:
center
;
flex
:
0
1
auto
;
white-space
:
nowrap
;
cursor
:
default
;
align-self
:
center
;
height
:
100%
;
}
.monaco-breadcrumbs
.monaco-breadcrumb-item
:not
(
:last-child
)
::after
{
background-image
:
url(./collapsed.svg)
;
width
:
16px
;
height
:
16px
;
display
:
inline-block
;
background-size
:
16px
;
background-position
:
50%
50%
;
content
:
' '
;
}
.vs-dark
.monaco-breadcrumbs
.monaco-breadcrumb-item
:not
(
:last-child
)
::after
{
background-image
:
url(./collpased-dark.svg)
;
}
.monaco-breadcrumbs
.monaco-breadcrumb-item.focused
{
font-weight
:
bold
;
}
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts
0 → 100644
浏览文件 @
c49edf91
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
'
vs/css!./breadcrumbsWidget
'
;
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
{
DomScrollableElement
}
from
'
vs/base/browser/ui/scrollbar/scrollableElement
'
;
import
{
ScrollbarVisibility
}
from
'
vs/base/common/scrollable
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
IMouseEvent
}
from
'
vs/base/browser/mouseEvent
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Color
}
from
'
vs/base/common/color
'
;
import
{
commonPrefixLength
}
from
'
vs/base/common/arrays
'
;
export
abstract
class
BreadcrumbsItem
{
dispose
():
void
{
}
abstract
equals
(
other
:
BreadcrumbsItem
):
boolean
;
abstract
render
(
container
:
HTMLElement
):
void
;
}
export
class
SimpleBreadcrumbsItem
extends
BreadcrumbsItem
{
constructor
(
readonly
text
:
string
,
readonly
title
:
string
=
text
)
{
super
();
}
equals
(
other
:
this
)
{
return
other
===
this
||
other
instanceof
SimpleBreadcrumbsItem
&&
other
.
text
===
this
.
text
&&
other
.
title
===
this
.
title
;
}
render
(
container
:
HTMLElement
):
void
{
let
node
=
document
.
createElement
(
'
div
'
);
node
.
title
=
this
.
title
;
node
.
innerText
=
this
.
text
;
container
.
appendChild
(
node
);
}
}
export
interface
IBreadcrumbsWidgetStyles
{
breadcrumbsBackground
?:
Color
;
breadcrumbsActiveForeground
?:
Color
;
breadcrumbsInactiveForeground
?:
Color
;
}
export
interface
IBreadcrumbsItemEvent
{
item
:
BreadcrumbsItem
;
node
:
HTMLElement
;
}
export
class
BreadcrumbsWidget
{
private
readonly
_disposables
=
new
Array
<
IDisposable
>
();
private
readonly
_domNode
:
HTMLDivElement
;
private
readonly
_styleElement
:
HTMLStyleElement
;
private
readonly
_scrollable
:
DomScrollableElement
;
private
readonly
_onDidSelectItem
=
new
Emitter
<
IBreadcrumbsItemEvent
>
();
private
readonly
_onDidFocusItem
=
new
Emitter
<
IBreadcrumbsItemEvent
>
();
private
readonly
_onDidChangeFocus
=
new
Emitter
<
boolean
>
();
readonly
onDidSelectItem
:
Event
<
IBreadcrumbsItemEvent
>
=
this
.
_onDidSelectItem
.
event
;
readonly
onDidFocusItem
:
Event
<
IBreadcrumbsItemEvent
>
=
this
.
_onDidFocusItem
.
event
;
readonly
onDidChangeFocus
:
Event
<
boolean
>
=
this
.
_onDidChangeFocus
.
event
;
private
readonly
_items
=
new
Array
<
BreadcrumbsItem
>
();
private
readonly
_nodes
=
new
Array
<
HTMLDivElement
>
();
private
readonly
_freeNodes
=
new
Array
<
HTMLDivElement
>
();
private
_focusedItemIdx
:
number
=
-
1
;
private
_selectedItemIdx
:
number
=
-
1
;
constructor
(
container
:
HTMLElement
)
{
this
.
_domNode
=
document
.
createElement
(
'
div
'
);
this
.
_domNode
.
className
=
'
monaco-breadcrumbs
'
;
this
.
_domNode
.
tabIndex
=
-
1
;
this
.
_scrollable
=
new
DomScrollableElement
(
this
.
_domNode
,
{
vertical
:
ScrollbarVisibility
.
Hidden
,
horizontal
:
ScrollbarVisibility
.
Auto
,
horizontalScrollbarSize
:
3
,
useShadows
:
false
});
this
.
_disposables
.
push
(
this
.
_scrollable
);
this
.
_disposables
.
push
(
dom
.
addStandardDisposableListener
(
this
.
_domNode
,
'
click
'
,
e
=>
this
.
_onClick
(
e
)));
container
.
appendChild
(
this
.
_scrollable
.
getDomNode
());
this
.
_styleElement
=
dom
.
createStyleSheet
(
this
.
_domNode
);
let
focusTracker
=
dom
.
trackFocus
(
this
.
_domNode
);
this
.
_disposables
.
push
(
focusTracker
);
this
.
_disposables
.
push
(
focusTracker
.
onDidBlur
(
_
=>
this
.
_onDidChangeFocus
.
fire
(
false
)));
this
.
_disposables
.
push
(
focusTracker
.
onDidFocus
(
_
=>
this
.
_onDidChangeFocus
.
fire
(
true
)));
}
dispose
():
void
{
dispose
(
this
.
_disposables
);
this
.
_domNode
.
remove
();
this
.
_disposables
.
length
=
0
;
this
.
_nodes
.
length
=
0
;
this
.
_freeNodes
.
length
=
0
;
}
layout
(
dim
:
dom
.
Dimension
):
void
{
if
(
!
dim
)
{
this
.
_scrollable
.
scanDomNode
();
}
else
{
this
.
_domNode
.
style
.
width
=
`
${
dim
.
width
}
px`
;
this
.
_domNode
.
style
.
height
=
`
${
dim
.
height
}
px`
;
this
.
_scrollable
.
scanDomNode
();
}
}
style
(
style
:
IBreadcrumbsWidgetStyles
):
void
{
let
content
=
''
;
if
(
style
.
breadcrumbsBackground
)
{
content
+=
`.monaco-breadcrumbs { background-color:
${
style
.
breadcrumbsBackground
}
}`
;
}
if
(
style
.
breadcrumbsActiveForeground
)
{
content
+=
`.monaco-breadcrumbs:focus .monaco-breadcrumb-item { color:
${
style
.
breadcrumbsActiveForeground
}
}\n`
;
}
if
(
style
.
breadcrumbsInactiveForeground
)
{
content
+=
`.monaco-breadcrumbs .monaco-breadcrumb-item { color:
${
style
.
breadcrumbsInactiveForeground
}
}\n`
;
}
if
(
this
.
_styleElement
.
innerHTML
!==
content
)
{
this
.
_styleElement
.
innerHTML
=
content
;
}
}
domFocus
():
void
{
this
.
_domNode
.
focus
();
}
getFocused
():
BreadcrumbsItem
{
return
this
.
_items
[
this
.
_focusedItemIdx
];
}
setFocused
(
item
:
BreadcrumbsItem
):
void
{
this
.
_focus
(
this
.
_items
.
indexOf
(
item
));
}
focusPrev
():
any
{
this
.
_focus
((
this
.
_focusedItemIdx
-
1
+
this
.
_nodes
.
length
)
%
this
.
_nodes
.
length
);
this
.
_domNode
.
focus
();
}
focusNext
():
any
{
this
.
_focus
((
this
.
_focusedItemIdx
+
1
)
%
this
.
_nodes
.
length
);
this
.
_domNode
.
focus
();
}
private
_focus
(
nth
:
number
):
void
{
this
.
_focusedItemIdx
=
-
1
;
for
(
let
i
=
0
;
i
<
this
.
_nodes
.
length
;
i
++
)
{
const
node
=
this
.
_nodes
[
i
];
if
(
i
!==
nth
)
{
dom
.
removeClass
(
node
,
'
focused
'
);
}
else
{
this
.
_focusedItemIdx
=
i
;
dom
.
addClass
(
node
,
'
focused
'
);
}
}
this
.
_onDidFocusItem
.
fire
({
item
:
this
.
_items
[
this
.
_focusedItemIdx
],
node
:
this
.
_nodes
[
this
.
_focusedItemIdx
]
});
}
getSelected
():
BreadcrumbsItem
{
return
this
.
_items
[
this
.
_selectedItemIdx
];
}
setSelected
(
item
:
BreadcrumbsItem
):
void
{
this
.
_select
(
this
.
_items
.
indexOf
(
item
));
}
private
_select
(
nth
:
number
):
void
{
this
.
_selectedItemIdx
=
-
1
;
for
(
let
i
=
0
;
i
<
this
.
_nodes
.
length
;
i
++
)
{
const
node
=
this
.
_nodes
[
i
];
if
(
i
!==
nth
)
{
dom
.
removeClass
(
node
,
'
selected
'
);
}
else
{
this
.
_selectedItemIdx
=
i
;
dom
.
addClass
(
node
,
'
selected
'
);
}
}
this
.
_onDidSelectItem
.
fire
({
item
:
this
.
_items
[
this
.
_selectedItemIdx
],
node
:
this
.
_nodes
[
this
.
_selectedItemIdx
]
});
}
setItems
(
items
:
BreadcrumbsItem
[]):
void
{
let
prefix
=
commonPrefixLength
(
this
.
_items
,
items
,
(
a
,
b
)
=>
a
.
equals
(
b
));
let
removed
=
this
.
_items
.
splice
(
prefix
,
this
.
_items
.
length
-
prefix
,
...
items
.
slice
(
prefix
));
this
.
_render
(
prefix
);
dispose
(
removed
);
}
private
_render
(
start
:
number
):
void
{
for
(;
start
<
this
.
_items
.
length
&&
start
<
this
.
_nodes
.
length
;
start
++
)
{
let
item
=
this
.
_items
[
start
];
let
node
=
this
.
_nodes
[
start
];
this
.
_renderItem
(
item
,
node
);
}
// case a: more nodes -> remove them
for
(;
start
<
this
.
_nodes
.
length
;
start
++
)
{
this
.
_nodes
[
start
].
remove
();
this
.
_freeNodes
.
push
(
this
.
_nodes
[
start
]);
}
this
.
_nodes
.
length
=
this
.
_items
.
length
;
// case b: more items -> render them
for
(;
start
<
this
.
_items
.
length
;
start
++
)
{
let
item
=
this
.
_items
[
start
];
let
node
=
this
.
_freeNodes
.
length
>
0
?
this
.
_freeNodes
.
pop
()
:
document
.
createElement
(
'
div
'
);
this
.
_renderItem
(
item
,
node
);
this
.
_domNode
.
appendChild
(
node
);
this
.
_nodes
[
start
]
=
node
;
}
this
.
layout
(
undefined
);
}
private
_renderItem
(
item
:
BreadcrumbsItem
,
container
:
HTMLDivElement
):
void
{
dom
.
clearNode
(
container
);
item
.
render
(
container
);
dom
.
append
(
container
);
dom
.
addClass
(
container
,
'
monaco-breadcrumb-item
'
);
}
private
_onClick
(
event
:
IMouseEvent
):
void
{
for
(
let
el
=
event
.
target
;
el
;
el
=
el
.
parentElement
)
{
let
idx
=
this
.
_nodes
.
indexOf
(
el
as
any
);
if
(
idx
>=
0
)
{
this
.
_focus
(
idx
);
this
.
_select
(
idx
);
break
;
}
}
}
}
src/vs/base/browser/ui/breadcrumbs/collapsed.svg
0 → 100755
浏览文件 @
c49edf91
<svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 16 16"
><path
fill=
"#646465"
d=
"M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"
/></svg>
\ No newline at end of file
src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg
0 → 100755
浏览文件 @
c49edf91
<svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 16 16"
><path
fill=
"#E8E8E8"
d=
"M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"
/></svg>
\ No newline at end of file
src/vs/editor/contrib/documentSymbols/media/outlineTree.css
0 → 100644
浏览文件 @
c49edf91
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-tree.focused
.selected
.outline-element-label
,
.monaco-tree.focused
.selected
.outline-element-decoration
{
/* make sure selection color wins when a label is being selected */
color
:
inherit
!important
;
}
.monaco-tree
.outline-element
{
display
:
flex
;
flex
:
1
;
flex-flow
:
row
nowrap
;
align-items
:
center
;
}
.monaco-tree
.outline-element
.outline-element-icon
{
padding-right
:
3px
;
}
/* .monaco-tree.no-icons .outline-element .outline-element-icon {
display: none;
} */
.monaco-tree
.outline-element
.outline-element-label
{
text-overflow
:
ellipsis
;
overflow
:
hidden
;
color
:
var
(
--outline-element-color
);
}
.monaco-tree
.outline-element
.outline-element-label
.monaco-highlighted-label
.highlight
{
font-weight
:
bold
;
}
.monaco-tree
.outline-element
.outline-element-detail
{
visibility
:
hidden
;
flex
:
1
;
flex-basis
:
10%
;
opacity
:
0.8
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
font-size
:
90%
;
padding-left
:
4px
;
padding-top
:
3px
;
}
.monaco-tree
.monaco-tree-row.focused
.outline-element
.outline-element-detail
{
visibility
:
inherit
;
}
.monaco-tree
.outline-element
.outline-element-decoration
{
opacity
:
0.75
;
font-size
:
90%
;
font-weight
:
600
;
padding
:
0
12px
0
5px
;
margin-left
:
auto
;
text-align
:
center
;
color
:
var
(
--outline-element-color
);
}
.monaco-tree
.outline-element
.outline-element-decoration.bubble
{
font-family
:
octicons
;
font-size
:
14px
;
opacity
:
0.4
;
}
src/vs/editor/contrib/documentSymbols/outlineTree.ts
浏览文件 @
c49edf91
...
...
@@ -5,22 +5,23 @@
'
use strict
'
;
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
'
vs/css!./media/symbol-icons
'
;
import
{
IMouseEvent
}
from
'
vs/base/browser/mouseEvent
'
;
import
{
HighlightedLabel
}
from
'
vs/base/browser/ui/highlightedlabel/highlightedLabel
'
;
import
{
values
}
from
'
vs/base/common/collections
'
;
import
{
createMatches
}
from
'
vs/base/common/filters
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IDataSource
,
IFilter
,
IRenderer
,
ISorter
,
ITree
}
from
'
vs/base/parts/tree/browser/tree
'
;
import
'
vs/css!./media/outlineTree
'
;
import
'
vs/css!./media/symbol-icons
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
symbolKindToCssClass
,
SymbolKind
}
from
'
vs/editor/common/modes
'
;
import
{
SymbolKind
,
symbolKindToCssClass
}
from
'
vs/editor/common/modes
'
;
import
{
OutlineElement
,
OutlineGroup
,
OutlineModel
,
TreeElement
}
from
'
vs/editor/contrib/documentSymbols/outlineModel
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
WorkbenchTreeController
}
from
'
vs/platform/list/browser/listService
'
;
import
{
MarkerSeverity
}
from
'
vs/platform/markers/common/markers
'
;
import
{
listErrorForeground
,
listWarningForeground
}
from
'
vs/platform/theme/common/colorRegistry
'
;
import
{
IThemeService
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
export
enum
OutlineItemCompareType
{
ByPosition
,
...
...
src/vs/platform/theme/common/styler.ts
浏览文件 @
c49edf91
...
...
@@ -261,4 +261,34 @@ export function attachProgressBarStyler(widget: IThemable, themeService: IThemeS
export
function
attachStylerCallback
(
themeService
:
IThemeService
,
colors
:
{
[
name
:
string
]:
ColorIdentifier
},
callback
:
styleFn
):
IDisposable
{
return
attachStyler
(
themeService
,
colors
,
callback
);
}
\ No newline at end of file
}
export
interface
IBreadcrumbsWidgetStyleOverrides
extends
IStyleOverrides
{
breadcrumbsBackground
?:
ColorIdentifier
;
breadcrumbsItemHoverBackground
?:
ColorIdentifier
;
breadcrumbsItemHoverForeground
?:
ColorIdentifier
;
breadcrumbsItemFocusBackground
?:
ColorIdentifier
;
breadcrumbsItemFocusForeground
?:
ColorIdentifier
;
breadcrumbsActiveItemSelectionBackground
?:
ColorIdentifier
;
breadcrumbsActiveItemSelectionForeground
?:
ColorIdentifier
;
breadcrumbsInactiveItemSelectionBackground
?:
ColorIdentifier
;
breadcrumbsInactiveItemSelectionForeground
?:
ColorIdentifier
;
}
export
const
defaultBreadcrumbsStyles
=
<
IBreadcrumbsWidgetStyleOverrides
>
{
breadcrumbsBackground
:
editorBackground
,
breadcrumbsItemHoverBackground
:
listHoverBackground
,
breadcrumbsItemHoverForeground
:
listHoverForeground
,
breadcrumbsItemFocusBackground
:
listFocusBackground
,
breadcrumbsItemFocusForeground
:
listFocusForeground
,
breadcrumbsItemSelectionBackground
:
listActiveSelectionBackground
,
breadcrumbsItemSelectionForeground
:
listActiveSelectionForeground
,
breadcrumbsActiveItemSelectionBackground
:
listActiveSelectionBackground
,
breadcrumbsActiveItemSelectionForeground
:
listActiveSelectionForeground
,
breadcrumbsInactiveItemSelectionBackground
:
editorBackground
,
breadcrumbsInactiveItemSelectionForeground
:
listInactiveSelectionForeground
,
};
export
function
attachBreadcrumbsStyler
(
widget
:
IThemable
,
themeService
:
IThemeService
,
style
?:
IBreadcrumbsWidgetStyleOverrides
):
IDisposable
{
return
attachStyler
(
themeService
,
{
...
defaultBreadcrumbsStyles
,
...
style
},
widget
);
}
src/vs/workbench/browser/parts/editor/editor.ts
浏览文件 @
c49edf91
...
...
@@ -159,4 +159,4 @@ export interface EditorGroupsServiceImpl extends IEditorGroupsService {
* A promise that resolves when groups have been restored.
*/
readonly
whenRestored
:
TPromise
<
void
>
;
}
\ No newline at end of file
}
src/vs/workbench/browser/parts/editor/editorBreadcrumbs.ts
0 → 100644
浏览文件 @
c49edf91
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
{
BreadcrumbsItem
,
BreadcrumbsWidget
,
IBreadcrumbsItemEvent
}
from
'
vs/base/browser/ui/breadcrumbs/breadcrumbsWidget
'
;
import
{
IconLabel
}
from
'
vs/base/browser/ui/iconLabel/iconLabel
'
;
import
{
compareFileNames
}
from
'
vs/base/common/comparers
'
;
import
{
debounceEvent
,
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
KeyCode
,
KeyMod
}
from
'
vs/base/common/keyCodes
'
;
import
{
dispose
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
dirname
,
isEqual
}
from
'
vs/base/common/resources
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IDataSource
,
IRenderer
,
ISelectionEvent
,
ISorter
,
ITree
,
ITreeConfiguration
}
from
'
vs/base/parts/tree/browser/tree
'
;
import
'
vs/css!./media/editorbreadcrumbs
'
;
import
{
ICodeEditor
,
isCodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
OutlineElement
,
OutlineGroup
,
OutlineModel
,
TreeElement
}
from
'
vs/editor/contrib/documentSymbols/outlineModel
'
;
import
{
OutlineController
,
OutlineDataSource
,
OutlineItemComparator
,
OutlineRenderer
}
from
'
vs/editor/contrib/documentSymbols/outlineTree
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
Extensions
,
IConfigurationRegistry
}
from
'
vs/platform/configuration/common/configurationRegistry
'
;
import
{
ContextKeyExpr
,
IContextKey
,
IContextKeyService
,
RawContextKey
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
IContextViewService
}
from
'
vs/platform/contextview/browser/contextView
'
;
import
{
FileKind
,
IFileService
,
IFileStat
}
from
'
vs/platform/files/common/files
'
;
import
{
IConstructorSignature2
,
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
KeybindingsRegistry
}
from
'
vs/platform/keybinding/common/keybindingsRegistry
'
;
import
{
WorkbenchTree
}
from
'
vs/platform/list/browser/listService
'
;
import
{
Registry
}
from
'
vs/platform/registry/common/platform
'
;
import
{
attachBreadcrumbsStyler
}
from
'
vs/platform/theme/common/styler
'
;
import
{
IThemeService
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
FileLabel
}
from
'
vs/workbench/browser/labels
'
;
import
{
BreadcrumbElement
,
EditorBreadcrumbsModel
,
FileElement
}
from
'
vs/workbench/browser/parts/editor/editorBreadcrumbsModel
'
;
import
{
EditorGroupView
}
from
'
vs/workbench/browser/parts/editor/editorGroupView
'
;
import
{
EditorInput
}
from
'
vs/workbench/common/editor
'
;
import
{
SIDE_BAR_BACKGROUND
}
from
'
vs/workbench/common/theme
'
;
import
{
IEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
IEditorBreadcrumbs
,
IEditorGroupsService
}
from
'
vs/workbench/services/group/common/editorGroupsService
'
;
class
Item
extends
BreadcrumbsItem
{
private
readonly
_disposables
:
IDisposable
[]
=
[];
constructor
(
readonly
element
:
BreadcrumbElement
,
@
IInstantiationService
private
readonly
_instantiationService
:
IInstantiationService
)
{
super
();
}
dispose
():
void
{
dispose
(
this
.
_disposables
);
}
equals
(
other
:
BreadcrumbsItem
):
boolean
{
if
(
!
(
other
instanceof
Item
))
{
return
false
;
}
if
(
this
.
element
instanceof
FileElement
&&
other
.
element
instanceof
FileElement
)
{
return
isEqual
(
this
.
element
.
uri
,
other
.
element
.
uri
);
}
if
(
this
.
element
instanceof
TreeElement
&&
other
.
element
instanceof
TreeElement
)
{
return
this
.
element
.
id
===
other
.
element
.
id
;
}
return
false
;
}
render
(
container
:
HTMLElement
):
void
{
if
(
this
.
element
instanceof
FileElement
)
{
// file/folder
let
label
=
this
.
_instantiationService
.
createInstance
(
FileLabel
,
container
,
{});
label
.
setFile
(
this
.
element
.
uri
,
{
hidePath
:
true
,
fileKind
:
this
.
element
.
isFile
?
FileKind
.
FILE
:
FileKind
.
FOLDER
});
this
.
_disposables
.
push
(
label
);
}
else
if
(
this
.
element
instanceof
OutlineGroup
)
{
// provider
let
label
=
new
IconLabel
(
container
);
label
.
setValue
(
this
.
element
.
provider
.
displayName
);
this
.
_disposables
.
push
(
label
);
}
else
if
(
this
.
element
instanceof
OutlineElement
)
{
// symbol
let
label
=
new
IconLabel
(
container
);
label
.
setValue
(
this
.
element
.
symbol
.
name
);
this
.
_disposables
.
push
(
label
);
}
}
}
export
class
EditorBreadcrumbs
implements
IEditorBreadcrumbs
{
static
CK_BreadcrumbsVisible
=
new
RawContextKey
(
'
breadcrumbsVisible
'
,
false
);
static
CK_BreadcrumbsFocused
=
new
RawContextKey
(
'
breadcrumbsFocused
'
,
false
);
private
readonly
_ckBreadcrumbsVisible
:
IContextKey
<
boolean
>
;
private
readonly
_ckBreadcrumbsFocused
:
IContextKey
<
boolean
>
;
private
readonly
_cfEnabled
:
Config
<
boolean
>
;
private
readonly
_disposables
=
new
Array
<
IDisposable
>
();
private
readonly
_domNode
:
HTMLDivElement
;
private
readonly
_widget
:
BreadcrumbsWidget
;
private
_breadcrumbsDisposables
=
new
Array
<
IDisposable
>
();
constructor
(
container
:
HTMLElement
,
private
readonly
_editorGroup
:
EditorGroupView
,
@
IContextKeyService
private
readonly
_contextKeyService
:
IContextKeyService
,
@
IContextViewService
private
readonly
_contextViewService
:
IContextViewService
,
@
IEditorService
private
readonly
_editorService
:
IEditorService
,
@
IFileService
private
readonly
_fileService
:
IFileService
,
@
IWorkspaceContextService
private
readonly
_workspaceService
:
IWorkspaceContextService
,
@
IInstantiationService
private
readonly
_instantiationService
:
IInstantiationService
,
@
IThemeService
private
readonly
_themeService
:
IThemeService
,
@
IConfigurationService
configurationService
:
IConfigurationService
,
)
{
this
.
_domNode
=
document
.
createElement
(
'
div
'
);
dom
.
addClasses
(
this
.
_domNode
,
'
editor-breadcrumbs
'
,
'
show-file-icons
'
);
dom
.
append
(
container
,
this
.
_domNode
);
this
.
_widget
=
new
BreadcrumbsWidget
(
this
.
_domNode
);
this
.
_widget
.
onDidSelectItem
(
this
.
_onDidSelectItem
,
this
,
this
.
_disposables
);
this
.
_widget
.
onDidChangeFocus
(
val
=>
this
.
_ckBreadcrumbsFocused
.
set
(
val
),
undefined
,
this
.
_disposables
);
this
.
_disposables
.
push
(
attachBreadcrumbsStyler
(
this
.
_widget
,
this
.
_themeService
));
this
.
_cfEnabled
=
Config
.
create
(
configurationService
,
'
breadcrumbs.enabled
'
);
this
.
_disposables
.
push
(
this
.
_cfEnabled
.
onDidChange
(
value
=>
{
if
(
!
value
)
{
this
.
closeEditor
(
undefined
);
this
.
_editorGroup
.
relayout
();
}
else
if
(
this
.
_editorGroup
.
activeEditor
)
{
this
.
openEditor
(
this
.
_editorGroup
.
activeEditor
);
this
.
_editorGroup
.
relayout
();
}
}));
this
.
_ckBreadcrumbsVisible
=
EditorBreadcrumbs
.
CK_BreadcrumbsVisible
.
bindTo
(
this
.
_contextKeyService
);
this
.
_ckBreadcrumbsFocused
=
EditorBreadcrumbs
.
CK_BreadcrumbsFocused
.
bindTo
(
this
.
_contextKeyService
);
}
dispose
():
void
{
dispose
(
this
.
_disposables
);
this
.
_widget
.
dispose
();
this
.
_ckBreadcrumbsVisible
.
reset
();
this
.
_cfEnabled
.
dispose
();
}
getPreferredHeight
():
number
{
return
this
.
_cfEnabled
.
value
?
25
:
0
;
}
layout
(
dim
:
dom
.
Dimension
):
void
{
this
.
_domNode
.
style
.
width
=
`
${
dim
.
width
}
px`
;
this
.
_domNode
.
style
.
height
=
`
${
dim
.
height
}
px`
;
this
.
_widget
.
layout
(
dim
);
}
setActive
(
value
:
boolean
):
void
{
dom
.
toggleClass
(
this
.
_domNode
,
'
active
'
,
value
);
}
openEditor
(
input
:
EditorInput
):
void
{
if
(
!
this
.
_cfEnabled
.
value
)
{
// not enabled -> return early
return
;
}
this
.
_breadcrumbsDisposables
=
dispose
(
this
.
_breadcrumbsDisposables
);
let
uri
=
input
.
getResource
();
if
(
!
uri
||
!
this
.
_fileService
.
canHandleResource
(
uri
))
{
return
this
.
closeEditor
(
undefined
);
}
dom
.
toggleClass
(
this
.
_domNode
,
'
hidden
'
,
false
);
this
.
_ckBreadcrumbsVisible
.
set
(
true
);
let
control
=
this
.
_editorGroup
.
activeControl
.
getControl
()
as
ICodeEditor
;
let
model
=
new
EditorBreadcrumbsModel
(
input
.
getResource
(),
isCodeEditor
(
control
)
?
control
:
undefined
,
this
.
_workspaceService
);
let
listener
=
model
.
onDidUpdate
(
_
=>
this
.
_widget
.
setItems
(
model
.
getElements
().
map
(
element
=>
new
Item
(
element
,
this
.
_instantiationService
))));
this
.
_widget
.
setItems
(
model
.
getElements
().
map
(
element
=>
new
Item
(
element
,
this
.
_instantiationService
)));
this
.
_breadcrumbsDisposables
.
push
(
model
,
listener
);
}
closeEditor
(
input
:
EditorInput
):
void
{
this
.
_ckBreadcrumbsVisible
.
set
(
false
);
dom
.
toggleClass
(
this
.
_domNode
,
'
hidden
'
,
true
);
}
focus
():
void
{
this
.
_widget
.
domFocus
();
}
focusNext
():
void
{
this
.
_widget
.
focusNext
();
}
focusPrev
():
void
{
this
.
_widget
.
focusPrev
();
}
select
():
void
{
const
item
=
this
.
_widget
.
getFocused
();
if
(
item
)
{
this
.
_widget
.
setSelected
(
item
);
}
}
private
_onDidSelectItem
(
event
:
IBreadcrumbsItemEvent
):
void
{
if
(
!
event
.
item
)
{
return
;
}
this
.
_editorGroup
.
focus
();
this
.
_contextViewService
.
showContextView
({
getAnchor
()
{
return
event
.
node
;
},
render
:
(
container
:
HTMLElement
)
=>
{
dom
.
addClasses
(
container
,
'
monaco-workbench
'
,
'
show-file-icons
'
);
let
{
element
}
=
event
.
item
as
Item
;
let
ctor
:
IConstructorSignature2
<
HTMLElement
,
BreadcrumbElement
,
BreadcrumbsPicker
>
=
element
instanceof
FileElement
?
BreadcrumbsFilePicker
:
BreadcrumbsOutlinePicker
;
let
res
=
this
.
_instantiationService
.
createInstance
(
ctor
,
container
,
element
);
res
.
layout
({
width
:
250
,
height
:
300
});
res
.
onDidPickElement
(
data
=>
{
this
.
_contextViewService
.
hideContextView
();
if
(
!
data
)
{
return
;
}
if
(
URI
.
isUri
(
data
))
{
// open new editor
this
.
_editorService
.
openEditor
({
resource
:
data
});
}
else
if
(
data
instanceof
OutlineElement
)
{
let
resource
:
URI
;
let
candidate
=
data
.
parent
;
while
(
candidate
)
{
if
(
candidate
instanceof
OutlineModel
)
{
resource
=
candidate
.
textModel
.
uri
;
break
;
}
candidate
=
candidate
.
parent
;
}
this
.
_editorService
.
openEditor
({
resource
,
options
:
{
selection
:
Range
.
collapseToStart
(
data
.
symbol
.
selectionRange
)
}
});
}
});
return
res
;
},
onHide
:
()
=>
{
this
.
_widget
.
setSelected
(
undefined
);
this
.
_widget
.
setFocused
(
undefined
);
}
});
}
}
export
abstract
class
BreadcrumbsPicker
{
readonly
focus
:
dom
.
IFocusTracker
;
protected
readonly
_onDidPickElement
=
new
Emitter
<
any
>
();
readonly
onDidPickElement
:
Event
<
any
>
=
this
.
_onDidPickElement
.
event
;
protected
readonly
_disposables
=
new
Array
<
IDisposable
>
();
protected
readonly
_domNode
:
HTMLDivElement
;
protected
readonly
_tree
:
WorkbenchTree
;
constructor
(
container
:
HTMLElement
,
input
:
BreadcrumbElement
,
@
IInstantiationService
protected
readonly
_instantiationService
:
IInstantiationService
,
@
IThemeService
protected
readonly
_themeService
:
IThemeService
,
)
{
this
.
_domNode
=
document
.
createElement
(
'
div
'
);
this
.
_domNode
.
style
.
background
=
this
.
_themeService
.
getTheme
().
getColor
(
SIDE_BAR_BACKGROUND
).
toString
();
container
.
appendChild
(
this
.
_domNode
);
this
.
_tree
=
this
.
_instantiationService
.
createInstance
(
WorkbenchTree
,
this
.
_domNode
,
this
.
_completeTreeConfiguration
({
dataSource
:
undefined
}),
{});
debounceEvent
(
this
.
_tree
.
onDidChangeSelection
,
(
_last
,
cur
)
=>
cur
,
0
)(
this
.
_onDidChangeSelection
,
this
,
this
.
_disposables
);
this
.
focus
=
dom
.
trackFocus
(
this
.
_domNode
);
this
.
focus
.
onDidBlur
(
_
=>
this
.
_onDidPickElement
.
fire
(
undefined
),
undefined
,
this
.
_disposables
);
this
.
_tree
.
domFocus
();
this
.
_tree
.
setInput
(
this
.
_getInput
(
input
));
}
dispose
():
void
{
dispose
(
this
.
_disposables
);
this
.
_onDidPickElement
.
dispose
();
this
.
_tree
.
dispose
();
this
.
focus
.
dispose
();
}
layout
(
dim
:
dom
.
Dimension
)
{
this
.
_domNode
.
style
.
width
=
`
${
dim
.
width
}
px`
;
this
.
_domNode
.
style
.
height
=
`
${
dim
.
height
}
px`
;
this
.
_tree
.
layout
(
dim
.
height
,
dim
.
width
);
}
protected
abstract
_getInput
(
input
:
BreadcrumbElement
):
any
;
protected
abstract
_completeTreeConfiguration
(
config
:
ITreeConfiguration
):
ITreeConfiguration
;
protected
abstract
_onDidChangeSelection
(
e
:
any
):
void
;
}
export
class
FileDataSource
implements
IDataSource
{
private
readonly
_parents
=
new
WeakMap
<
IFileStat
,
IFileStat
>
();
constructor
(
@
IFileService
private
readonly
_fileService
:
IFileService
,
)
{
}
getId
(
tree
:
ITree
,
element
:
IFileStat
|
URI
):
string
{
return
URI
.
isUri
(
element
)
?
element
.
toString
()
:
element
.
resource
.
toString
();
}
hasChildren
(
tree
:
ITree
,
element
:
IFileStat
|
URI
):
boolean
{
return
URI
.
isUri
(
element
)
||
element
.
isDirectory
;
}
getChildren
(
tree
:
ITree
,
element
:
IFileStat
|
URI
):
TPromise
<
IFileStat
[]
>
{
return
this
.
_fileService
.
resolveFile
(
URI
.
isUri
(
element
)
?
element
:
element
.
resource
).
then
(
stat
=>
{
for
(
const
child
of
stat
.
children
)
{
this
.
_parents
.
set
(
child
,
stat
);
}
return
stat
.
children
;
});
}
getParent
(
tree
:
ITree
,
element
:
IFileStat
|
URI
):
TPromise
<
IFileStat
>
{
return
TPromise
.
as
(
URI
.
isUri
(
element
)
?
undefined
:
this
.
_parents
.
get
(
element
));
}
}
export
class
FileRenderer
implements
IRenderer
{
constructor
(
@
IInstantiationService
private
readonly
_instantiationService
:
IInstantiationService
,
)
{
}
getHeight
(
tree
:
ITree
,
element
:
any
):
number
{
return
22
;
}
getTemplateId
(
tree
:
ITree
,
element
:
any
):
string
{
return
'
FileStat
'
;
}
renderTemplate
(
tree
:
ITree
,
templateId
:
string
,
container
:
HTMLElement
)
{
return
this
.
_instantiationService
.
createInstance
(
FileLabel
,
container
,
{});
}
renderElement
(
tree
:
ITree
,
element
:
IFileStat
,
templateId
:
string
,
templateData
:
FileLabel
):
void
{
templateData
.
setFile
(
element
.
resource
,
{
hidePath
:
true
,
fileKind
:
element
.
isDirectory
?
FileKind
.
FOLDER
:
FileKind
.
FILE
,
fileDecorations
:
{
colors
:
true
,
badges
:
true
}
});
}
disposeTemplate
(
tree
:
ITree
,
templateId
:
string
,
templateData
:
FileLabel
):
void
{
templateData
.
dispose
();
}
}
export
class
FileSorter
implements
ISorter
{
compare
(
tree
:
ITree
,
a
:
IFileStat
,
b
:
IFileStat
):
number
{
if
(
a
.
isDirectory
===
b
.
isDirectory
)
{
// same type -> compare on names
return
compareFileNames
(
a
.
name
,
b
.
name
);
}
else
if
(
a
.
isDirectory
)
{
return
-
1
;
}
else
{
return
1
;
}
}
}
export
class
BreadcrumbsFilePicker
extends
BreadcrumbsPicker
{
protected
_getInput
(
input
:
BreadcrumbElement
):
any
{
let
{
uri
}
=
(
input
as
FileElement
);
return
dirname
(
uri
);
}
protected
_completeTreeConfiguration
(
config
:
ITreeConfiguration
):
ITreeConfiguration
{
// todo@joh reuse explorer implementations?
config
.
dataSource
=
this
.
_instantiationService
.
createInstance
(
FileDataSource
);
config
.
renderer
=
this
.
_instantiationService
.
createInstance
(
FileRenderer
);
config
.
sorter
=
new
FileSorter
();
return
config
;
}
protected
_onDidChangeSelection
(
e
:
ISelectionEvent
):
void
{
let
[
first
]
=
e
.
selection
;
let
stat
=
first
as
IFileStat
;
if
(
stat
&&
!
stat
.
isDirectory
)
{
this
.
_onDidPickElement
.
fire
(
stat
.
resource
);
}
}
}
export
class
BreadcrumbsOutlinePicker
extends
BreadcrumbsPicker
{
protected
_getInput
(
input
:
BreadcrumbElement
):
any
{
return
(
input
as
TreeElement
).
parent
;
}
protected
_completeTreeConfiguration
(
config
:
ITreeConfiguration
):
ITreeConfiguration
{
config
.
dataSource
=
this
.
_instantiationService
.
createInstance
(
OutlineDataSource
);
config
.
renderer
=
this
.
_instantiationService
.
createInstance
(
OutlineRenderer
);
config
.
controller
=
this
.
_instantiationService
.
createInstance
(
OutlineController
,
{});
config
.
sorter
=
new
OutlineItemComparator
();
return
config
;
}
protected
_onDidChangeSelection
(
e
:
ISelectionEvent
):
void
{
if
(
e
.
payload
&&
e
.
payload
.
didClickOnTwistie
)
{
return
;
}
let
[
first
]
=
e
.
selection
;
if
(
first
instanceof
OutlineElement
)
{
this
.
_onDidPickElement
.
fire
(
first
);
}
}
}
//#region config
abstract
class
Config
<
T
>
{
name
:
string
;
value
:
T
;
onDidChange
:
Event
<
T
>
;
abstract
dispose
():
void
;
static
create
<
T
>
(
service
:
IConfigurationService
,
name
:
string
):
Config
<
T
>
{
let
value
:
T
=
service
.
getValue
(
name
);
let
onDidChange
=
new
Emitter
<
T
>
();
let
listener
=
service
.
onDidChangeConfiguration
(
e
=>
{
if
(
e
.
affectsConfiguration
(
name
))
{
value
=
service
.
getValue
(
name
);
onDidChange
.
fire
(
value
);
}
});
return
{
name
,
get
value
()
{
return
value
;
},
onDidChange
:
onDidChange
.
event
,
dispose
():
void
{
listener
.
dispose
();
onDidChange
.
dispose
();
}
};
}
}
Registry
.
as
<
IConfigurationRegistry
>
(
Extensions
.
Configuration
).
registerConfiguration
({
id
:
'
breadcrumbs
'
,
title
:
localize
(
'
title
'
,
"
Breadcrumb Navigation
"
),
order
:
101
,
type
:
'
object
'
,
properties
:
{
'
breadcrumbs.enabled
'
:
{
'
description
'
:
localize
(
'
enabled
'
,
"
Enable/disable navigation breadcrumbss
"
),
'
type
'
:
'
boolean
'
,
'
default
'
:
false
}
}
});
//#endregion
//#region commands
KeybindingsRegistry
.
registerCommandAndKeybindingRule
({
id
:
'
breadcrumbs.focus
'
,
weight
:
KeybindingsRegistry
.
WEIGHT
.
workbenchContrib
(),
primary
:
KeyMod
.
CtrlCmd
|
KeyMod
.
Shift
|
KeyCode
.
US_DOT
,
when
:
EditorBreadcrumbs
.
CK_BreadcrumbsVisible
,
handler
(
accessor
)
{
let
groups
=
accessor
.
get
(
IEditorGroupsService
);
groups
.
activeGroup
.
breadcrumbs
.
focus
();
}
});
KeybindingsRegistry
.
registerCommandAndKeybindingRule
({
id
:
'
breadcrumbs.focusNext
'
,
weight
:
KeybindingsRegistry
.
WEIGHT
.
workbenchContrib
(),
primary
:
KeyCode
.
RightArrow
,
when
:
ContextKeyExpr
.
and
(
EditorBreadcrumbs
.
CK_BreadcrumbsVisible
,
EditorBreadcrumbs
.
CK_BreadcrumbsFocused
),
handler
(
accessor
)
{
let
groups
=
accessor
.
get
(
IEditorGroupsService
);
groups
.
activeGroup
.
breadcrumbs
.
focusNext
();
}
});
KeybindingsRegistry
.
registerCommandAndKeybindingRule
({
id
:
'
breadcrumbs.focusPrevious
'
,
weight
:
KeybindingsRegistry
.
WEIGHT
.
workbenchContrib
(),
primary
:
KeyCode
.
LeftArrow
,
when
:
ContextKeyExpr
.
and
(
EditorBreadcrumbs
.
CK_BreadcrumbsVisible
,
EditorBreadcrumbs
.
CK_BreadcrumbsFocused
),
handler
(
accessor
)
{
let
groups
=
accessor
.
get
(
IEditorGroupsService
);
groups
.
activeGroup
.
breadcrumbs
.
focusPrev
();
}
});
KeybindingsRegistry
.
registerCommandAndKeybindingRule
({
id
:
'
breadcrumbs.selectFocused
'
,
weight
:
KeybindingsRegistry
.
WEIGHT
.
workbenchContrib
(),
primary
:
KeyCode
.
Enter
,
secondary
:
[
KeyCode
.
UpArrow
,
KeyCode
.
Space
],
when
:
ContextKeyExpr
.
and
(
EditorBreadcrumbs
.
CK_BreadcrumbsVisible
,
EditorBreadcrumbs
.
CK_BreadcrumbsFocused
),
handler
(
accessor
)
{
let
groups
=
accessor
.
get
(
IEditorGroupsService
);
groups
.
activeGroup
.
breadcrumbs
.
select
();
}
});
KeybindingsRegistry
.
registerCommandAndKeybindingRule
({
id
:
'
breadcrumbs.selectEditor
'
,
weight
:
KeybindingsRegistry
.
WEIGHT
.
workbenchContrib
(),
primary
:
KeyCode
.
Escape
,
when
:
ContextKeyExpr
.
and
(
EditorBreadcrumbs
.
CK_BreadcrumbsVisible
,
EditorBreadcrumbs
.
CK_BreadcrumbsFocused
),
handler
(
accessor
)
{
let
groups
=
accessor
.
get
(
IEditorGroupsService
);
groups
.
activeGroup
.
activeControl
.
focus
();
}
});
//#endregion
src/vs/workbench/browser/parts/editor/editorBreadcrumbsModel.ts
0 → 100644
浏览文件 @
c49edf91
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
equals
}
from
'
vs/base/common/arrays
'
;
import
{
TimeoutTimer
}
from
'
vs/base/common/async
'
;
import
{
CancellationTokenSource
}
from
'
vs/base/common/cancellation
'
;
import
{
size
}
from
'
vs/base/common/collections
'
;
import
{
onUnexpectedError
}
from
'
vs/base/common/errors
'
;
import
{
debounceEvent
,
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
dispose
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
*
as
paths
from
'
vs/base/common/paths
'
;
import
{
isEqual
}
from
'
vs/base/common/resources
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
ICodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
IPosition
}
from
'
vs/editor/common/core/position
'
;
import
{
DocumentSymbolProviderRegistry
}
from
'
vs/editor/common/modes
'
;
import
{
OutlineElement
,
OutlineGroup
,
OutlineModel
}
from
'
vs/editor/contrib/documentSymbols/outlineModel
'
;
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
export
class
FileElement
{
constructor
(
readonly
uri
:
URI
,
readonly
isFile
:
boolean
)
{
}
}
export
type
BreadcrumbElement
=
FileElement
|
OutlineGroup
|
OutlineElement
;
export
class
EditorBreadcrumbsModel
{
private
readonly
_disposables
:
IDisposable
[]
=
[];
private
readonly
_fileElements
:
FileElement
[]
=
[];
private
_outlineElements
:
(
OutlineGroup
|
OutlineElement
)[]
=
[];
private
_outlineDisposables
:
IDisposable
[]
=
[];
private
_onDidUpdate
=
new
Emitter
<
this
>
();
readonly
onDidUpdate
:
Event
<
this
>
=
this
.
_onDidUpdate
.
event
;
constructor
(
private
readonly
_uri
:
URI
,
private
readonly
_editor
:
ICodeEditor
|
undefined
,
@
IWorkspaceContextService
workspaceService
:
IWorkspaceContextService
,
)
{
this
.
_fileElements
=
EditorBreadcrumbsModel
.
_getFileElements
(
this
.
_uri
,
workspaceService
);
this
.
_bindToEditor
();
this
.
_onDidUpdate
.
fire
(
this
);
}
dispose
():
void
{
dispose
(
this
.
_disposables
);
}
getElements
():
ReadonlyArray
<
BreadcrumbElement
>
{
return
[].
concat
(
this
.
_fileElements
,
this
.
_outlineElements
);
}
private
static
_getFileElements
(
uri
:
URI
,
workspaceService
:
IWorkspaceContextService
):
FileElement
[]
{
let
result
:
FileElement
[]
=
[];
let
workspace
=
workspaceService
.
getWorkspaceFolder
(
uri
);
let
path
=
uri
.
path
;
while
(
path
!==
'
/
'
)
{
if
(
workspace
&&
isEqual
(
workspace
.
uri
,
uri
))
{
break
;
}
result
.
push
(
new
FileElement
(
uri
,
result
.
length
===
0
));
path
=
paths
.
dirname
(
path
);
uri
=
uri
.
with
({
path
});
}
return
result
.
reverse
();
}
private
_bindToEditor
():
void
{
if
(
!
this
.
_editor
)
{
return
;
}
// update as model changes
this
.
_disposables
.
push
(
DocumentSymbolProviderRegistry
.
onDidChange
(
_
=>
this
.
_updateOutline
()));
this
.
_disposables
.
push
(
this
.
_editor
.
onDidChangeModel
(
_
=>
this
.
_updateOutline
()));
this
.
_disposables
.
push
(
this
.
_editor
.
onDidChangeModelLanguage
(
_
=>
this
.
_updateOutline
()));
this
.
_disposables
.
push
(
debounceEvent
(
this
.
_editor
.
onDidChangeModelContent
,
_
=>
_
,
350
)(
_
=>
this
.
_updateOutline
(
true
)));
this
.
_updateOutline
();
// stop when editor dies
this
.
_disposables
.
push
(
this
.
_editor
.
onDidDispose
(()
=>
this
.
_outlineDisposables
=
dispose
(
this
.
_outlineDisposables
)));
}
private
_updateOutline
(
didChangeContent
?:
boolean
):
void
{
this
.
_outlineDisposables
=
dispose
(
this
.
_outlineDisposables
);
if
(
!
didChangeContent
)
{
this
.
_updateOutlineElements
([]);
}
const
buffer
=
this
.
_editor
.
getModel
();
if
(
!
buffer
||
!
DocumentSymbolProviderRegistry
.
has
(
buffer
)
||
!
isEqual
(
buffer
.
uri
,
this
.
_uri
))
{
return
;
}
const
source
=
new
CancellationTokenSource
();
this
.
_outlineDisposables
.
push
({
dispose
:
()
=>
{
source
.
cancel
();
source
.
dispose
();
}
});
OutlineModel
.
create
(
buffer
,
source
.
token
).
then
(
model
=>
{
this
.
_updateOutlineElements
(
this
.
_getOutlineElements
(
model
,
this
.
_editor
.
getPosition
()));
const
timeout
=
new
TimeoutTimer
();
const
lastVersionId
=
buffer
.
getVersionId
();
this
.
_outlineDisposables
.
push
(
this
.
_editor
.
onDidChangeCursorPosition
(
_
=>
{
timeout
.
cancelAndSet
(()
=>
{
if
(
!
buffer
.
isDisposed
()
&&
lastVersionId
===
buffer
.
getVersionId
())
{
this
.
_updateOutlineElements
(
this
.
_getOutlineElements
(
model
,
this
.
_editor
.
getPosition
()));
}
},
150
);
}));
this
.
_outlineDisposables
.
push
(
timeout
);
}).
catch
(
err
=>
{
this
.
_updateOutlineElements
([]);
onUnexpectedError
(
err
);
});
}
private
_getOutlineElements
(
model
:
OutlineModel
,
position
:
IPosition
):
(
OutlineGroup
|
OutlineElement
)[]
{
if
(
!
model
)
{
return
[];
}
let
item
:
OutlineGroup
|
OutlineElement
=
model
.
getItemEnclosingPosition
(
position
);
let
chain
:
(
OutlineGroup
|
OutlineElement
)[]
=
[];
while
(
item
)
{
chain
.
push
(
item
);
let
parent
=
item
.
parent
;
if
(
parent
instanceof
OutlineModel
)
{
break
;
}
if
(
parent
instanceof
OutlineGroup
&&
size
(
parent
.
parent
.
children
)
===
1
)
{
break
;
}
item
=
parent
;
}
return
chain
.
reverse
();
}
private
_updateOutlineElements
(
elements
:
(
OutlineGroup
|
OutlineElement
)[]):
void
{
if
(
!
equals
(
elements
,
this
.
_outlineElements
,
EditorBreadcrumbsModel
.
_outlineElementEquals
))
{
this
.
_outlineElements
=
elements
;
this
.
_onDidUpdate
.
fire
(
this
);
}
}
private
static
_outlineElementEquals
(
a
:
OutlineGroup
|
OutlineElement
,
b
:
OutlineGroup
|
OutlineElement
):
boolean
{
if
(
a
===
b
)
{
return
true
;
}
else
if
(
!
a
||
!
b
)
{
return
false
;
}
else
{
return
a
.
id
===
b
.
id
;
}
}
}
src/vs/workbench/browser/parts/editor/editorGroupView.ts
浏览文件 @
c49edf91
...
...
@@ -19,7 +19,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
import
{
IThemeService
,
registerThemingParticipant
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
editorBackground
,
contrastBorder
}
from
'
vs/platform/theme/common/colorRegistry
'
;
import
{
Themable
,
EDITOR_GROUP_HEADER_TABS_BORDER
,
EDITOR_GROUP_HEADER_TABS_BACKGROUND
,
EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND
,
EDITOR_GROUP_EMPTY_BACKGROUND
,
EDITOR_GROUP_FOCUSED_EMPTY_BORDER
}
from
'
vs/workbench/common/theme
'
;
import
{
IMoveEditorOptions
,
ICopyEditorOptions
,
ICloseEditorsFilter
,
IGroupChangeEvent
,
GroupChangeKind
,
EditorsOrder
,
GroupsOrder
}
from
'
vs/workbench/services/group/common/editorGroupsService
'
;
import
{
IMoveEditorOptions
,
ICopyEditorOptions
,
ICloseEditorsFilter
,
IGroupChangeEvent
,
GroupChangeKind
,
EditorsOrder
,
GroupsOrder
,
IEditorBreadcrumbs
}
from
'
vs/workbench/services/group/common/editorGroupsService
'
;
import
{
TabsTitleControl
}
from
'
vs/workbench/browser/parts/editor/tabsTitleControl
'
;
import
{
EditorControl
}
from
'
vs/workbench/browser/parts/editor/editorControl
'
;
import
{
IProgressService
}
from
'
vs/platform/progress/common/progress
'
;
...
...
@@ -46,6 +46,7 @@ import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'
import
{
StandardMouseEvent
}
from
'
vs/base/browser/mouseEvent
'
;
import
{
fillInContextMenuActions
}
from
'
vs/platform/actions/browser/menuItemActionItem
'
;
import
{
IContextMenuService
}
from
'
vs/platform/contextview/browser/contextView
'
;
import
{
EditorBreadcrumbs
}
from
'
vs/workbench/browser/parts/editor/editorBreadcrumbs
'
;
export
class
EditorGroupView
extends
Themable
implements
IEditorGroupView
{
...
...
@@ -104,6 +105,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
private
titleContainer
:
HTMLElement
;
private
titleAreaControl
:
TitleControl
;
private
breadcrumbsContainer
:
HTMLElement
;
private
breadcrumbsControl
:
EditorBreadcrumbs
;
private
progressBar
:
ProgressBar
;
private
editorContainer
:
HTMLElement
;
...
...
@@ -190,6 +194,14 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Title control
this
.
createTitleAreaControl
();
// Breadcrumbs container
this
.
breadcrumbsContainer
=
document
.
createElement
(
'
div
'
);
addClass
(
this
.
breadcrumbsContainer
,
'
editor-breadcrumbs
'
);
this
.
element
.
appendChild
(
this
.
breadcrumbsContainer
);
// Breadcrumbs control
this
.
createEditorBreadcrumbs
();
// Editor container
this
.
editorContainer
=
document
.
createElement
(
'
div
'
);
addClass
(
this
.
editorContainer
,
'
editor-container
'
);
...
...
@@ -397,6 +409,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
}
private
createEditorBreadcrumbs
():
void
{
if
(
this
.
breadcrumbsControl
)
{
this
.
breadcrumbsControl
.
dispose
();
clearNode
(
this
.
breadcrumbsContainer
);
}
this
.
breadcrumbsControl
=
this
.
scopedInstantiationService
.
createInstance
(
EditorBreadcrumbs
,
this
.
breadcrumbsContainer
,
this
);
}
private
restoreEditors
(
from
:
IEditorGroupView
|
ISerializedEditorGroup
):
TPromise
<
void
>
{
if
(
this
.
_group
.
count
===
0
)
{
return
TPromise
.
as
(
void
0
);
// nothing to show
...
...
@@ -593,6 +615,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return
this
.
_label
;
}
get
breadcrumbs
():
IEditorBreadcrumbs
{
return
this
.
breadcrumbsControl
;
}
get
disposed
():
boolean
{
return
this
.
_disposed
;
}
...
...
@@ -618,6 +644,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Update title control
this
.
titleAreaControl
.
setActive
(
isActive
);
this
.
breadcrumbsControl
.
setActive
(
isActive
);
// Update styles
this
.
updateStyles
();
...
...
@@ -789,6 +817,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Show in title control after editor control because some actions depend on it
this
.
titleAreaControl
.
openEditor
(
editor
);
this
.
breadcrumbsControl
.
openEditor
(
editor
);
return
openEditorPromise
;
}
...
...
@@ -956,8 +986,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this
.
doCloseInactiveEditor
(
editor
);
}
// Forward to title control
// Forward to title control
& breadcrumbs
this
.
titleAreaControl
.
closeEditor
(
editor
);
this
.
breadcrumbsControl
.
closeEditor
(
editor
);
}
private
doCloseActiveEditor
(
focusNext
=
this
.
accessor
.
activeGroup
===
this
,
fromError
?:
boolean
):
void
{
...
...
@@ -1345,7 +1376,15 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Forward to controls
this
.
titleAreaControl
.
layout
(
new
Dimension
(
this
.
dimension
.
width
,
EDITOR_TITLE_HEIGHT
));
this
.
editorControl
.
layout
(
new
Dimension
(
this
.
dimension
.
width
,
this
.
dimension
.
height
-
EDITOR_TITLE_HEIGHT
));
this
.
breadcrumbsControl
.
layout
(
new
Dimension
(
this
.
dimension
.
width
,
this
.
breadcrumbsControl
.
getPreferredHeight
()));
this
.
editorControl
.
layout
(
new
Dimension
(
this
.
dimension
.
width
,
this
.
dimension
.
height
-
(
EDITOR_TITLE_HEIGHT
+
this
.
breadcrumbsControl
.
getPreferredHeight
())));
}
relayout
():
void
{
if
(
this
.
dimension
)
{
const
{
width
,
height
}
=
this
.
dimension
;
this
.
layout
(
width
,
height
);
}
}
toJSON
():
ISerializedEditorGroup
{
...
...
@@ -1365,6 +1404,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this
.
titleAreaControl
.
dispose
();
this
.
breadcrumbsControl
.
dispose
();
super
.
dispose
();
}
}
...
...
src/vs/workbench/browser/parts/editor/media/editorbreadcrumbs.css
0 → 100644
浏览文件 @
c49edf91
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench
>
.part.editor
>
.content
.editor-group-container
:not
(
.active
)
.editor-breadcrumbs
{
opacity
:
.8
;
}
.monaco-workbench
>
.part.editor
>
.content
.editor-group-container
.editor-breadcrumbs
.monaco-breadcrumbs
.monaco-breadcrumb-item
:nth-child
(
2
)
{
/*first-child is the style-element*/
padding-left
:
8px
;
}
src/vs/workbench/parts/outline/electron-browser/outlinePanel.css
浏览文件 @
c49edf91
...
...
@@ -76,59 +76,6 @@
color
:
inherit
!important
;
}
.monaco-workbench
.outline-panel
.outline-element
{
display
:
flex
;
flex
:
1
;
flex-flow
:
row
nowrap
;
align-items
:
center
;
}
.monaco-workbench
.outline-panel
.outline-element
.outline-element-icon
{
padding-right
:
3px
;
}
.monaco-workbench
.outline-panel.no-icons
.outline-element
.outline-element-icon
{
display
:
none
;
}
.monaco-workbench
.outline-panel
.outline-element
.outline-element-label
{
text-overflow
:
ellipsis
;
overflow
:
hidden
;
color
:
var
(
--outline-element-color
);
}
.monaco-workbench
.outline-panel
.outline-element
.outline-element-label
.monaco-highlighted-label
.highlight
{
font-weight
:
bold
;
}
.monaco-workbench
.outline-panel
.outline-element
.outline-element-detail
{
visibility
:
hidden
;
flex
:
1
;
flex-basis
:
10%
;
opacity
:
0.8
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
font-size
:
90%
;
padding-left
:
4px
;
padding-top
:
3px
;
}
.monaco-workbench
.outline-panel
.monaco-tree-row.focused
.outline-element
.outline-element-detail
{
visibility
:
inherit
;
}
.monaco-workbench
.outline-panel
.outline-element
.outline-element-decoration
{
opacity
:
0.75
;
font-size
:
90%
;
font-weight
:
600
;
padding
:
0
12px
0
5px
;
margin-left
:
auto
;
text-align
:
center
;
color
:
var
(
--outline-element-color
);
}
.monaco-workbench
.outline-panel
.outline-element
.outline-element-decoration.bubble
{
font-family
:
octicons
;
font-size
:
14px
;
opacity
:
0.4
;
}
src/vs/workbench/services/group/common/editorGroupsService.ts
浏览文件 @
c49edf91
...
...
@@ -312,6 +312,13 @@ export interface IGroupChangeEvent {
editorIndex
?:
number
;
}
export
interface
IEditorBreadcrumbs
{
focus
():
void
;
focusNext
():
void
;
focusPrev
():
void
;
select
():
void
;
}
export
interface
IEditorGroup
{
/**
...
...
@@ -332,6 +339,11 @@ export interface IEditorGroup {
*/
readonly
label
:
string
;
/**
*
*/
readonly
breadcrumbs
:
IEditorBreadcrumbs
;
/**
* The active control is the currently visible control of the group.
*/
...
...
@@ -476,4 +488,4 @@ export interface IEditorGroup {
* Invoke a function in the context of the services of this group.
*/
invokeWithinContext
<
T
>
(
fn
:
(
accessor
:
ServicesAccessor
)
=>
T
):
T
;
}
\ No newline at end of file
}
src/vs/workbench/test/browser/parts/editor/editorBreadcrumbModel.test.ts
0 → 100644
浏览文件 @
c49edf91
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
Workspace
,
WorkspaceFolder
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
EditorBreadcrumbsModel
,
FileElement
}
from
'
vs/workbench/browser/parts/editor/editorBreadcrumbsModel
'
;
import
{
TestContextService
}
from
'
vs/workbench/test/workbenchTestServices
'
;
suite
(
'
Breadcrumb Model
'
,
function
()
{
const
workspaceService
=
new
TestContextService
(
new
Workspace
(
'
ffff
'
,
'
Test
'
,
[
new
WorkspaceFolder
({
uri
:
URI
.
parse
(
'
foo:/bar/baz/ws
'
),
name
:
'
ws
'
,
index
:
0
})]));
test
(
'
only uri, inside workspace
'
,
function
()
{
let
model
=
new
EditorBreadcrumbsModel
(
URI
.
parse
(
'
foo:/bar/baz/ws/some/path/file.ts
'
),
undefined
,
workspaceService
);
let
elements
=
model
.
getElements
();
assert
.
equal
(
elements
.
length
,
3
);
let
[
one
,
two
,
three
]
=
elements
as
FileElement
[];
assert
.
equal
(
one
.
isFile
,
false
);
assert
.
equal
(
two
.
isFile
,
false
);
assert
.
equal
(
three
.
isFile
,
true
);
assert
.
equal
(
one
.
uri
.
toString
(),
'
foo:/bar/baz/ws/some
'
);
assert
.
equal
(
two
.
uri
.
toString
(),
'
foo:/bar/baz/ws/some/path
'
);
assert
.
equal
(
three
.
uri
.
toString
(),
'
foo:/bar/baz/ws/some/path/file.ts
'
);
});
test
(
'
only uri, outside workspace
'
,
function
()
{
let
model
=
new
EditorBreadcrumbsModel
(
URI
.
parse
(
'
foo:/outside/file.ts
'
),
undefined
,
workspaceService
);
let
elements
=
model
.
getElements
();
assert
.
equal
(
elements
.
length
,
2
);
let
[
one
,
two
]
=
elements
as
FileElement
[];
assert
.
equal
(
one
.
isFile
,
false
);
assert
.
equal
(
two
.
isFile
,
true
);
assert
.
equal
(
one
.
uri
.
toString
(),
'
foo:/outside
'
);
assert
.
equal
(
two
.
uri
.
toString
(),
'
foo:/outside/file.ts
'
);
});
});
src/vs/workbench/test/workbenchTestServices.ts
浏览文件 @
c49edf91
...
...
@@ -67,7 +67,7 @@ import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensi
import
{
IKeybindingService
}
from
'
vs/platform/keybinding/common/keybinding
'
;
import
{
IDecorationsService
,
IResourceDecorationChangeEvent
,
IDecoration
,
IDecorationData
,
IDecorationsProvider
}
from
'
vs/workbench/services/decorations/browser/decorations
'
;
import
{
IDisposable
,
toDisposable
,
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IEditorGroupsService
,
IEditorGroup
,
GroupsOrder
,
GroupsArrangement
,
GroupDirection
,
IAddGroupOptions
,
IMergeGroupOptions
,
IMoveEditorOptions
,
ICopyEditorOptions
,
IEditorReplacement
,
IGroupChangeEvent
,
EditorsOrder
,
IFindGroupScope
,
EditorGroupLayout
}
from
'
vs/workbench/services/group/common/editorGroupsService
'
;
import
{
IEditorGroupsService
,
IEditorGroup
,
GroupsOrder
,
GroupsArrangement
,
GroupDirection
,
IAddGroupOptions
,
IMergeGroupOptions
,
IMoveEditorOptions
,
ICopyEditorOptions
,
IEditorReplacement
,
IGroupChangeEvent
,
EditorsOrder
,
IFindGroupScope
,
EditorGroupLayout
,
IEditorBreadcrumbs
}
from
'
vs/workbench/services/group/common/editorGroupsService
'
;
import
{
IEditorService
,
IOpenEditorOverrideHandler
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
ICodeEditorService
}
from
'
vs/editor/browser/services/codeEditorService
'
;
import
{
ICodeEditor
,
IDiffEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
...
...
@@ -583,6 +583,7 @@ export class TestEditorGroup implements IEditorGroupView {
constructor
(
public
id
:
number
)
{
}
group
:
EditorGroup
=
void
0
;
breadcrumbs
:
IEditorBreadcrumbs
;
activeControl
:
IEditor
;
activeEditor
:
IEditorInput
;
previewEditor
:
IEditorInput
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录