Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
17348329
V
vscode
项目概览
掘金者说
/
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,发现更多精彩内容 >>
提交
17348329
编写于
3月 23, 2017
作者:
J
Joao Moreno
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
⚡
list traits shouldn't splice
上级
0ba01095
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
140 addition
and
100 deletion
+140
-100
src/vs/base/browser/ui/list/listWidget.ts
src/vs/base/browser/ui/list/listWidget.ts
+140
-100
未找到文件。
src/vs/base/browser/ui/list/listWidget.ts
浏览文件 @
17348329
...
...
@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import
'
vs/css!./list
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
IDisposable
,
dispose
,
empty
as
EmptyDisposable
,
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
isNumber
}
from
'
vs/base/common/types
'
;
import
{
range
}
from
'
vs/base/common/arrays
'
;
import
{
once
}
from
'
vs/base/common/functional
'
;
import
{
memoize
}
from
'
vs/base/common/decorators
'
;
import
*
as
DOM
from
'
vs/base/browser/dom
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
...
...
@@ -35,48 +36,83 @@ class CombinedSpliceable<T> implements ISpliceable<T> {
}
}
interface
ITraitTemplateData
<
D
>
{
interface
ITraitChangeEvent
{
indexes
:
number
[];
}
interface
ITraitTemplateData
{
container
:
HTMLElement
;
data
:
D
;
elementDisposable
:
IDisposable
;
}
interface
ITraitChangeEvent
{
indexes
:
number
[];
interface
IRenderedElement
{
templateData
:
ITraitTemplateData
;
index
:
number
;
}
class
TraitRenderer
<
T
,
D
>
implements
IRenderer
<
T
,
ITraitTemplateData
<
D
>
>
class
TraitRenderer
<
T
,
D
>
implements
IRenderer
<
T
,
ITraitTemplateData
>
{
constructor
(
private
controller
:
Trait
<
T
>
,
private
renderer
:
IRenderer
<
T
,
D
>
)
{
}
private
rendered
:
IRenderedElement
[]
=
[];
constructor
(
private
trait
:
Trait
<
T
>
)
{
}
get
templateId
():
string
{
return
this
.
renderer
.
templateId
;
return
`template:
${
this
.
trait
.
trait
}
`
;
}
renderTemplate
(
container
:
HTMLElement
):
ITraitTemplateData
{
const
elementDisposable
=
EmptyDisposable
;
return
{
container
,
elementDisposable
};
}
renderElement
(
element
:
T
,
index
:
number
,
templateData
:
ITraitTemplateData
):
void
{
templateData
.
elementDisposable
.
dispose
();
const
rendered
=
{
index
,
templateData
};
this
.
rendered
.
push
(
rendered
);
templateData
.
elementDisposable
=
toDisposable
(
once
(()
=>
this
.
rendered
.
splice
(
this
.
rendered
.
indexOf
(
rendered
),
1
)));
this
.
trait
.
renderIndex
(
index
,
templateData
.
container
);
}
renderTemplate
(
container
:
HTMLElement
):
ITraitTemplateData
<
D
>
{
const
data
=
this
.
renderer
.
renderTemplate
(
container
);
return
{
container
,
data
};
renderIndexes
(
indexes
:
number
[]):
void
{
this
.
rendered
.
filter
(({
index
})
=>
indexes
.
indexOf
(
index
)
>
-
1
)
.
forEach
(({
index
,
templateData
})
=>
this
.
trait
.
renderIndex
(
index
,
templateData
.
container
));
}
renderElement
(
element
:
T
,
index
:
number
,
templateData
:
ITraitTemplateData
<
D
>
):
void
{
this
.
controller
.
renderElement
(
element
,
index
,
templateData
.
container
);
splice
(
start
:
number
,
deleteCount
:
number
):
void
{
for
(
let
i
=
0
;
i
<
deleteCount
;
i
++
)
{
const
key
=
`key_
${
start
+
i
}
`
;
const
data
=
this
.
rendered
[
key
];
this
.
renderer
.
renderElement
(
element
,
index
,
templateData
.
data
);
if
(
data
)
{
data
.
elementDisposable
.
dispose
();
}
}
}
disposeTemplate
(
templateData
:
ITraitTemplateData
<
D
>
):
void
{
return
this
.
renderer
.
disposeTemplate
(
templateData
.
data
);
disposeTemplate
(
templateData
:
ITraitTemplateData
):
void
{
templateData
.
elementDisposable
.
dispose
(
);
}
}
class
Trait
<
T
>
implements
ISpliceable
<
boolean
>
,
IDisposable
{
/**
* Sorted indexes which have this trait.
*/
private
indexes
:
number
[];
private
_onChange
=
new
Emitter
<
ITraitChangeEvent
>
();
get
onChange
()
{
return
this
.
_onChange
.
event
;
}
get
onChange
():
Event
<
ITraitChangeEvent
>
{
return
this
.
_onChange
.
event
;
}
get
trait
():
string
{
return
this
.
_trait
;
}
@
memoize
get
renderer
():
TraitRenderer
<
T
,
any
>
{
return
new
TraitRenderer
<
T
,
any
>
(
this
);
}
constructor
(
private
_trait
:
string
)
{
this
.
indexes
=
[];
...
...
@@ -91,10 +127,11 @@ class Trait<T> implements ISpliceable<boolean>, IDisposable {
...
this
.
indexes
.
filter
(
i
=>
i
>=
end
).
map
(
i
=>
i
+
diff
)
];
this
.
renderer
.
splice
(
start
,
deleteCount
);
this
.
set
(
indexes
);
}
render
Element
(
element
:
T
,
index
:
number
,
container
:
HTMLElement
):
void
{
render
Index
(
index
:
number
,
container
:
HTMLElement
):
void
{
DOM
.
toggleClass
(
container
,
this
.
_trait
,
this
.
contains
(
index
));
}
...
...
@@ -107,6 +144,10 @@ class Trait<T> implements ISpliceable<boolean>, IDisposable {
set
(
indexes
:
number
[]):
number
[]
{
const
result
=
this
.
indexes
;
this
.
indexes
=
indexes
;
const
toRender
=
disjunction
(
result
,
indexes
);
this
.
renderer
.
renderIndexes
(
toRender
);
this
.
_onChange
.
fire
({
indexes
});
return
result
;
}
...
...
@@ -119,10 +160,6 @@ class Trait<T> implements ISpliceable<boolean>, IDisposable {
return
this
.
indexes
.
some
(
i
=>
i
===
index
);
}
wrapRenderer
<
D
>
(
renderer
:
IRenderer
<
T
,
D
>
):
IRenderer
<
T
,
ITraitTemplateData
<
D
>>
{
return
new
TraitRenderer
<
T
,
D
>
(
this
,
renderer
);
}
dispose
()
{
this
.
indexes
=
null
;
this
.
_onChange
=
dispose
(
this
.
_onChange
);
...
...
@@ -137,8 +174,8 @@ class FocusTrait<T> extends Trait<T> {
super
(
'
focused
'
);
}
render
Element
(
element
:
T
,
index
:
number
,
container
:
HTMLElement
):
void
{
super
.
render
Element
(
element
,
index
,
container
);
render
Index
(
index
:
number
,
container
:
HTMLElement
):
void
{
super
.
render
Index
(
index
,
container
);
container
.
setAttribute
(
'
role
'
,
'
treeitem
'
);
container
.
setAttribute
(
'
id
'
,
this
.
getDomId
(
index
));
}
...
...
@@ -233,6 +270,18 @@ class KeyboardController<T> implements IDisposable {
}
}
function
isSelectionSingleChangeEvent
(
event
:
IListMouseEvent
<
any
>
):
boolean
{
return
platform
.
isMacintosh
?
event
.
altKey
:
event
.
ctrlKey
;
}
function
isSelectionRangeChangeEvent
(
event
:
IListMouseEvent
<
any
>
):
boolean
{
return
event
.
shiftKey
;
}
function
isSelectionChangeEvent
(
event
:
IListMouseEvent
<
any
>
):
boolean
{
return
isSelectionSingleChangeEvent
(
event
)
||
isSelectionRangeChangeEvent
(
event
);
}
class
MouseController
<
T
>
implements
IDisposable
{
private
disposables
:
IDisposable
[];
...
...
@@ -268,46 +317,57 @@ class MouseController<T> implements IDisposable {
this
.
disposables
.
push
(
view
.
addListener
(
TouchEventType
.
Tap
,
e
=>
this
.
onPointer
(
e
)));
}
private
onMouseDown
(
e
:
IListMouseEvent
<
T
>
)
{
if
(
platform
.
isMacintosh
?
e
.
altKey
:
e
.
ctrlKey
)
{
return
this
.
onPointer
(
e
);
}
private
onMouseDown
(
e
:
IListMouseEvent
<
T
>
):
void
{
e
.
preventDefault
();
e
.
stopPropagation
();
this
.
view
.
domNode
.
focus
();
let
reference
=
this
.
list
.
getFocus
()[
0
];
reference
=
reference
===
undefined
?
this
.
list
.
getSelection
()[
0
]
:
reference
;
if
(
isSelectionRangeChangeEvent
(
e
))
{
return
this
.
changeSelection
(
e
,
reference
);
}
const
focus
=
e
.
index
;
this
.
list
.
setFocus
([
focus
]);
if
(
isSelectionChangeEvent
(
e
))
{
return
this
.
changeSelection
(
e
,
reference
);
}
}
private
onPointer
(
e
:
IListMouseEvent
<
T
>
)
{
private
onPointer
(
e
:
IListMouseEvent
<
T
>
)
:
void
{
e
.
preventDefault
();
e
.
stopPropagation
();
this
.
view
.
domNode
.
focus
();
const
focus
=
e
.
index
;
if
(
isSelectionChangeEvent
(
e
))
{
return
;
}
if
(
e
.
shiftKey
)
{
const
oldFocus
=
this
.
list
.
getFocus
()[
0
];
const
focus
=
this
.
list
.
getFocus
();
this
.
list
.
setSelection
(
focus
);
this
.
list
.
open
(
focus
);
}
if
(
oldFocus
!==
undefined
)
{
const
min
=
Math
.
min
(
oldFocus
,
focus
);
const
max
=
Math
.
max
(
oldFocus
,
focus
);
const
rangeSelection
=
range
(
max
+
1
,
min
);
const
selection
=
this
.
list
.
getSelection
();
const
contiguousRange
=
getContiguousRangeContaining
(
disjunction
(
selection
,
[
oldFocus
]),
oldFocus
);
private
changeSelection
(
e
:
IListMouseEvent
<
T
>
,
reference
:
number
|
undefined
):
void
{
const
focus
=
e
.
index
;
if
(
contiguousRange
.
length
===
0
)
{
return
;
}
if
(
isSelectionRangeChangeEvent
(
e
)
&&
reference
!==
undefined
)
{
const
min
=
Math
.
min
(
reference
,
focus
);
const
max
=
Math
.
max
(
reference
,
focus
);
const
rangeSelection
=
range
(
max
+
1
,
min
);
const
selection
=
this
.
list
.
getSelection
();
const
contiguousRange
=
getContiguousRangeContaining
(
disjunction
(
selection
,
[
reference
]),
reference
);
const
newSelection
=
disjunction
(
rangeSelection
,
relativeComplement
(
selection
,
contiguousRange
));
this
.
list
.
setSelection
(
newSelection
)
;
if
(
contiguousRange
.
length
===
0
)
{
return
;
}
return
;
}
this
.
list
.
setFocus
([
focus
]);
const
newSelection
=
disjunction
(
rangeSelection
,
relativeComplement
(
selection
,
contiguousRange
));
this
.
list
.
setSelection
(
newSelection
);
if
(
platform
.
isMacintosh
?
e
.
altKey
:
e
.
ctrlKey
)
{
}
else
if
(
isSelectionSingleChangeEvent
(
e
)
)
{
const
selection
=
this
.
list
.
getSelection
();
const
newSelection
=
selection
.
filter
(
i
=>
i
!==
focus
);
...
...
@@ -316,9 +376,6 @@ class MouseController<T> implements IDisposable {
}
else
{
this
.
list
.
setSelection
(
newSelection
);
}
}
else
{
this
.
list
.
setSelection
([
focus
]);
this
.
list
.
open
([
focus
]);
}
}
...
...
@@ -389,33 +446,6 @@ function disjunction(one: number[], other: number[]): number[] {
return
result
;
}
/**
* Given two sorted collections of numbers, returns the exclusive
* disjunction between them (XOR).
*/
function
exclusiveDisjunction
(
one
:
number
[],
other
:
number
[]):
number
[]
{
const
result
=
[];
let
i
=
0
,
j
=
0
;
while
(
i
<
one
.
length
||
j
<
other
.
length
)
{
if
(
i
>=
one
.
length
)
{
result
.
push
(
other
[
j
++
]);
}
else
if
(
j
>=
other
.
length
)
{
result
.
push
(
one
[
i
++
]);
}
else
if
(
one
[
i
]
===
other
[
j
])
{
i
++
;
j
++
;
continue
;
}
else
if
(
one
[
i
]
<
other
[
j
])
{
result
.
push
(
one
[
i
++
]);
}
else
{
result
.
push
(
other
[
j
++
]);
}
}
return
result
;
}
/**
* Given two sorted collections of numbers, returns the relative
* complement between them (XOR).
...
...
@@ -445,6 +475,30 @@ function relativeComplement(one: number[], other: number[]): number[] {
const
numericSort
=
(
a
:
number
,
b
:
number
)
=>
a
-
b
;
class
PipelineRenderer
<
T
>
implements
IRenderer
<
T
,
any
>
{
constructor
(
private
_templateId
:
string
,
private
renderers
:
IRenderer
<
T
,
any
>
[]
)
{
}
get
templateId
():
string
{
return
this
.
_templateId
;
}
renderTemplate
(
container
:
HTMLElement
):
any
[]
{
return
this
.
renderers
.
map
(
r
=>
r
.
renderTemplate
(
container
));
}
renderElement
(
element
:
T
,
index
:
number
,
templateData
:
any
[]):
void
{
this
.
renderers
.
forEach
((
r
,
i
)
=>
r
.
renderElement
(
element
,
index
,
templateData
[
i
]));
}
disposeTemplate
(
templateData
:
any
[]):
void
{
this
.
renderers
.
forEach
((
r
,
i
)
=>
r
.
disposeTemplate
(
templateData
[
i
]));
}
}
export
class
List
<
T
>
implements
ISpliceable
<
T
>
,
IDisposable
{
private
static
InstanceCount
=
0
;
...
...
@@ -494,11 +548,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
this
.
selection
=
new
Trait
(
'
selected
'
);
this
.
eventBufferer
=
new
EventBufferer
();
renderers
=
renderers
.
map
(
r
=>
{
r
=
this
.
focus
.
wrapRenderer
(
r
);
r
=
this
.
selection
.
wrapRenderer
(
r
);
return
r
;
});
renderers
=
renderers
.
map
(
r
=>
new
PipelineRenderer
(
r
.
templateId
,
[
this
.
focus
.
renderer
,
this
.
selection
.
renderer
,
r
]));
this
.
view
=
new
ListView
(
container
,
delegate
,
renderers
,
options
);
this
.
view
.
domNode
.
setAttribute
(
'
role
'
,
'
tree
'
);
...
...
@@ -561,12 +611,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
setSelection
(
indexes
:
number
[]):
void
{
indexes
=
indexes
.
sort
(
numericSort
);
this
.
eventBufferer
.
bufferEvents
(()
=>
{
const
oldIndexes
=
this
.
selection
.
set
(
indexes
);
const
diffIndexes
=
exclusiveDisjunction
(
oldIndexes
,
indexes
);
diffIndexes
.
forEach
(
i
=>
this
.
view
.
splice
(
i
,
1
,
[
this
.
view
.
element
(
i
)]));
});
this
.
selection
.
set
(
indexes
);
}
selectNext
(
n
=
1
,
loop
=
false
):
void
{
...
...
@@ -596,12 +641,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
setFocus
(
indexes
:
number
[]):
void
{
indexes
=
indexes
.
sort
(
numericSort
);
this
.
eventBufferer
.
bufferEvents
(()
=>
{
const
oldIndexes
=
this
.
focus
.
set
(
indexes
);
const
diffIndexes
=
exclusiveDisjunction
(
oldIndexes
,
indexes
);
diffIndexes
.
forEach
(
i
=>
this
.
view
.
splice
(
i
,
1
,
[
this
.
view
.
element
(
i
)]));
});
this
.
focus
.
set
(
indexes
);
}
focusNext
(
n
=
1
,
loop
=
false
):
void
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录