Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
44cbf5af
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,发现更多精彩内容 >>
提交
44cbf5af
编写于
12月 13, 2018
作者:
M
Matt Bierner
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Strict null check code lens
上级
82916c8f
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
88 addition
and
63 deletion
+88
-63
src/tsconfig.strictNullChecks.json
src/tsconfig.strictNullChecks.json
+2
-0
src/vs/editor/contrib/codelens/codelensController.ts
src/vs/editor/contrib/codelens/codelensController.ts
+9
-9
src/vs/editor/contrib/codelens/codelensWidget.ts
src/vs/editor/contrib/codelens/codelensWidget.ts
+50
-33
src/vs/editor/contrib/documentSymbols/outlineModel.ts
src/vs/editor/contrib/documentSymbols/outlineModel.ts
+1
-1
src/vs/editor/contrib/find/findModel.ts
src/vs/editor/contrib/find/findModel.ts
+1
-1
src/vs/editor/contrib/indentation/indentation.ts
src/vs/editor/contrib/indentation/indentation.ts
+1
-1
src/vs/workbench/common/editor/editorGroup.ts
src/vs/workbench/common/editor/editorGroup.ts
+22
-16
src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts
...rkbench/parts/preferences/browser/preferencesRenderers.ts
+1
-1
src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts
...orkbench/parts/snippets/electron-browser/insertSnippet.ts
+1
-1
未找到文件。
src/tsconfig.strictNullChecks.json
浏览文件 @
44cbf5af
...
...
@@ -186,6 +186,8 @@
"./vs/editor/contrib/codeAction/codeActionTrigger.ts"
,
"./vs/editor/contrib/codeAction/lightBulbWidget.ts"
,
"./vs/editor/contrib/codelens/codelens.ts"
,
"./vs/editor/contrib/codelens/codelensController.ts"
,
"./vs/editor/contrib/codelens/codelensWidget.ts"
,
"./vs/editor/contrib/colorPicker/color.ts"
,
"./vs/editor/contrib/colorPicker/colorDetector.ts"
,
"./vs/editor/contrib/colorPicker/colorPickerModel.ts"
,
...
...
src/vs/editor/contrib/codelens/codelensController.ts
浏览文件 @
44cbf5af
...
...
@@ -27,9 +27,9 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
private
_globalToDispose
:
IDisposable
[];
private
_localToDispose
:
IDisposable
[];
private
_lenses
:
CodeLens
[];
private
_currentFindCodeLensSymbolsPromise
:
CancelablePromise
<
ICodeLensData
[]
>
;
private
_currentFindCodeLensSymbolsPromise
:
CancelablePromise
<
ICodeLensData
[]
>
|
null
;
private
_modelChangeCounter
:
number
;
private
_currentResolveCodeLensSymbolsPromise
:
CancelablePromise
<
any
>
;
private
_currentResolveCodeLensSymbolsPromise
:
CancelablePromise
<
any
>
|
null
;
private
_detectVisibleLenses
:
RunOnceScheduler
;
constructor
(
...
...
@@ -176,7 +176,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
scrollState
.
restore
(
this
.
_editor
);
}
else
{
// No accessors available
this
.
_disposeAllLenses
(
null
,
null
);
this
.
_disposeAllLenses
(
void
0
,
void
0
);
}
}));
this
.
_localToDispose
.
push
(
this
.
_editor
.
onDidChangeConfiguration
(
e
=>
{
...
...
@@ -187,11 +187,11 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
}
}));
this
.
_localToDispose
.
push
(
this
.
_editor
.
onMouseUp
(
e
=>
{
if
(
e
.
target
.
type
===
editorBrowser
.
MouseTargetType
.
CONTENT_WIDGET
&&
e
.
target
.
element
.
tagName
===
'
A
'
)
{
if
(
e
.
target
.
type
===
editorBrowser
.
MouseTargetType
.
CONTENT_WIDGET
&&
e
.
target
.
element
&&
e
.
target
.
element
.
tagName
===
'
A
'
)
{
for
(
const
lens
of
this
.
_lenses
)
{
let
command
=
lens
.
getCommand
(
e
.
target
.
element
as
HTMLLinkElement
);
if
(
command
)
{
this
.
_commandService
.
executeCommand
(
command
.
id
,
...
command
.
arguments
).
catch
(
err
=>
this
.
_notificationService
.
error
(
err
));
this
.
_commandService
.
executeCommand
(
command
.
id
,
...
(
command
.
arguments
||
[])
).
catch
(
err
=>
this
.
_notificationService
.
error
(
err
));
break
;
}
}
...
...
@@ -200,7 +200,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
scheduler
.
schedule
();
}
private
_disposeAllLenses
(
decChangeAccessor
:
IModelDecorationsChangeAccessor
,
viewZoneChangeAccessor
:
editorBrowser
.
IViewZoneChangeAccessor
):
void
{
private
_disposeAllLenses
(
decChangeAccessor
:
IModelDecorationsChangeAccessor
|
undefined
,
viewZoneChangeAccessor
:
editorBrowser
.
IViewZoneChangeAccessor
|
undefined
):
void
{
let
helper
=
new
CodeLensHelper
();
this
.
_lenses
.
forEach
((
lens
)
=>
lens
.
dispose
(
helper
,
viewZoneChangeAccessor
));
if
(
decChangeAccessor
)
{
...
...
@@ -210,13 +210,13 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
}
private
_renderCodeLensSymbols
(
symbols
:
ICodeLensData
[]):
void
{
if
(
!
this
.
_editor
.
get
Model
())
{
if
(
!
this
.
_editor
.
has
Model
())
{
return
;
}
let
maxLineNumber
=
this
.
_editor
.
getModel
().
getLineCount
();
let
groups
:
ICodeLensData
[][]
=
[];
let
lastGroup
:
ICodeLensData
[];
let
lastGroup
:
ICodeLensData
[]
|
undefined
;
for
(
let
symbol
of
symbols
)
{
let
line
=
symbol
.
symbol
.
range
.
startLineNumber
;
...
...
@@ -307,7 +307,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
const
promises
=
toResolve
.
map
((
request
,
i
)
=>
{
const
resolvedSymbols
=
new
Array
<
ICodeLensSymbol
>
(
request
.
length
);
const
resolvedSymbols
=
new
Array
<
ICodeLensSymbol
|
undefined
|
null
>
(
request
.
length
);
const
promises
=
request
.
map
((
request
,
i
)
=>
{
if
(
typeof
request
.
provider
.
resolveCodeLens
===
'
function
'
)
{
return
Promise
.
resolve
(
request
.
provider
.
resolveCodeLens
(
model
,
request
.
symbol
,
token
)).
then
(
symbol
=>
{
...
...
src/vs/editor/contrib/codelens/codelensWidget.ts
浏览文件 @
44cbf5af
...
...
@@ -95,9 +95,9 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget {
}
}
withCommands
(
symbols
:
ICodeLensSymbol
[]
):
void
{
withCommands
(
inSymbols
:
Array
<
ICodeLensSymbol
|
undefined
|
null
>
):
void
{
this
.
_commands
=
Object
.
create
(
null
);
symbols
=
coalesce
(
s
ymbols
);
const
symbols
=
coalesce
(
inS
ymbols
);
if
(
isFalsyOrEmpty
(
symbols
))
{
this
.
_domNode
.
innerHTML
=
'
no commands
'
;
return
;
...
...
@@ -105,16 +105,18 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget {
let
html
:
string
[]
=
[];
for
(
let
i
=
0
;
i
<
symbols
.
length
;
i
++
)
{
let
command
=
symbols
[
i
].
command
;
let
title
=
escape
(
command
.
title
);
let
part
:
string
;
if
(
command
.
id
)
{
part
=
`<a id=
${
i
}
>
${
title
}
</a>`
;
this
.
_commands
[
i
]
=
command
;
}
else
{
part
=
`<span>
${
title
}
</span>`
;
const
command
=
symbols
[
i
].
command
;
if
(
command
)
{
const
title
=
escape
(
command
.
title
);
let
part
:
string
;
if
(
command
.
id
)
{
part
=
`<a id=
${
i
}
>
${
title
}
</a>`
;
this
.
_commands
[
i
]
=
command
;
}
else
{
part
=
`<span>
${
title
}
</span>`
;
}
html
.
push
(
part
);
}
html
.
push
(
part
);
}
this
.
_domNode
.
innerHTML
=
html
.
join
(
'
<span> | </span>
'
);
...
...
@@ -136,6 +138,9 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget {
}
setSymbolRange
(
range
:
Range
):
void
{
if
(
!
this
.
_editor
.
hasModel
())
{
return
;
}
const
lineNumber
=
range
.
startLineNumber
;
const
column
=
this
.
_editor
.
getModel
().
getLineFirstNonWhitespaceColumn
(
lineNumber
);
this
.
_widgetPosition
=
{
...
...
@@ -206,7 +211,7 @@ export class CodeLens {
this
.
_data
=
data
;
this
.
_decorationIds
=
new
Array
<
string
>
(
this
.
_data
.
length
);
let
range
:
Range
;
let
range
:
Range
|
undefined
;
this
.
_data
.
forEach
((
codeLensData
,
i
)
=>
{
helper
.
addDecoration
({
...
...
@@ -222,16 +227,18 @@ export class CodeLens {
}
});
this
.
_contentWidget
=
new
CodeLensContentWidget
(
editor
,
range
);
this
.
_viewZone
=
new
CodeLensViewZone
(
range
.
startLineNumber
-
1
,
updateCallback
);
if
(
range
)
{
this
.
_contentWidget
=
new
CodeLensContentWidget
(
editor
,
range
);
this
.
_viewZone
=
new
CodeLensViewZone
(
range
.
startLineNumber
-
1
,
updateCallback
);
this
.
_viewZoneId
=
viewZoneChangeAccessor
.
addZone
(
this
.
_viewZone
);
this
.
_editor
.
addContentWidget
(
this
.
_contentWidget
);
this
.
_viewZoneId
=
viewZoneChangeAccessor
.
addZone
(
this
.
_viewZone
);
this
.
_editor
.
addContentWidget
(
this
.
_contentWidget
);
}
}
dispose
(
helper
:
CodeLensHelper
,
viewZoneChangeAccessor
:
editorBrowser
.
IViewZoneChangeAccessor
):
void
{
dispose
(
helper
:
CodeLensHelper
,
viewZoneChangeAccessor
?
:
editorBrowser
.
IViewZoneChangeAccessor
):
void
{
while
(
this
.
_decorationIds
.
length
)
{
helper
.
removeDecoration
(
this
.
_decorationIds
.
pop
());
helper
.
removeDecoration
(
this
.
_decorationIds
.
pop
()
!
);
}
if
(
viewZoneChangeAccessor
)
{
viewZoneChangeAccessor
.
removeZone
(
this
.
_viewZoneId
);
...
...
@@ -240,16 +247,20 @@ export class CodeLens {
}
isValid
():
boolean
{
if
(
!
this
.
_editor
.
hasModel
())
{
return
false
;
}
const
model
=
this
.
_editor
.
getModel
();
return
this
.
_decorationIds
.
some
((
id
,
i
)
=>
{
const
range
=
this
.
_editor
.
getModel
()
.
getDecorationRange
(
id
);
const
range
=
model
.
getDecorationRange
(
id
);
const
symbol
=
this
.
_data
[
i
].
symbol
;
return
range
&&
Range
.
isEmpty
(
symbol
.
range
)
===
range
.
isEmpty
(
);
return
!!
(
range
&&
Range
.
isEmpty
(
symbol
.
range
)
===
range
.
isEmpty
()
);
});
}
updateCodeLensSymbols
(
data
:
ICodeLensData
[],
helper
:
CodeLensHelper
):
void
{
while
(
this
.
_decorationIds
.
length
)
{
helper
.
removeDecoration
(
this
.
_decorationIds
.
pop
());
helper
.
removeDecoration
(
this
.
_decorationIds
.
pop
()
!
);
}
this
.
_data
=
data
;
this
.
_decorationIds
=
new
Array
<
string
>
(
this
.
_data
.
length
);
...
...
@@ -261,7 +272,7 @@ export class CodeLens {
});
}
computeIfNecessary
(
model
:
ITextModel
):
ICodeLensData
[]
{
computeIfNecessary
(
model
:
ITextModel
):
ICodeLensData
[]
|
null
{
this
.
_contentWidget
.
updateVisibility
();
// trigger the fade in
if
(
!
this
.
_contentWidget
.
isVisible
())
{
return
null
;
...
...
@@ -269,12 +280,15 @@ export class CodeLens {
// Read editor current state
for
(
let
i
=
0
;
i
<
this
.
_decorationIds
.
length
;
i
++
)
{
this
.
_data
[
i
].
symbol
.
range
=
model
.
getDecorationRange
(
this
.
_decorationIds
[
i
]);
const
range
=
model
.
getDecorationRange
(
this
.
_decorationIds
[
i
]);
if
(
range
)
{
this
.
_data
[
i
].
symbol
.
range
=
range
;
}
}
return
this
.
_data
;
}
updateCommands
(
symbols
:
ICodeLensSymbol
[]
):
void
{
updateCommands
(
symbols
:
Array
<
ICodeLensSymbol
|
undefined
|
null
>
):
void
{
this
.
_contentWidget
.
withCommands
(
symbols
);
}
...
...
@@ -287,22 +301,25 @@ export class CodeLens {
}
getLineNumber
():
number
{
const
range
=
this
.
_editor
.
getModel
().
getDecorationRange
(
this
.
_decorationIds
[
0
]);
if
(
range
)
{
return
range
.
startLineNumber
;
if
(
this
.
_editor
.
hasModel
())
{
const
range
=
this
.
_editor
.
getModel
().
getDecorationRange
(
this
.
_decorationIds
[
0
]);
if
(
range
)
{
return
range
.
startLineNumber
;
}
}
return
-
1
;
}
update
(
viewZoneChangeAccessor
:
editorBrowser
.
IViewZoneChangeAccessor
):
void
{
if
(
this
.
isValid
())
{
if
(
this
.
isValid
()
&&
this
.
_editor
.
hasModel
()
)
{
const
range
=
this
.
_editor
.
getModel
().
getDecorationRange
(
this
.
_decorationIds
[
0
]);
if
(
range
)
{
this
.
_viewZone
.
afterLineNumber
=
range
.
startLineNumber
-
1
;
viewZoneChangeAccessor
.
layoutZone
(
this
.
_viewZoneId
);
this
.
_viewZone
.
afterLineNumber
=
range
.
startLineNumber
-
1
;
viewZoneChangeAccessor
.
layoutZone
(
this
.
_viewZoneId
);
this
.
_contentWidget
.
setSymbolRange
(
range
);
this
.
_editor
.
layoutContentWidget
(
this
.
_contentWidget
);
this
.
_contentWidget
.
setSymbolRange
(
range
);
this
.
_editor
.
layoutContentWidget
(
this
.
_contentWidget
);
}
}
}
}
...
...
src/vs/editor/contrib/documentSymbols/outlineModel.ts
浏览文件 @
44cbf5af
...
...
@@ -49,7 +49,7 @@ export abstract class TreeElement {
return
id
;
}
static
getElementById
(
id
:
string
,
element
:
TreeElement
):
TreeElement
{
static
getElementById
(
id
:
string
,
element
:
TreeElement
):
TreeElement
|
undefined
{
if
(
!
id
)
{
return
undefined
;
}
...
...
src/vs/editor/contrib/find/findModel.ts
浏览文件 @
44cbf5af
...
...
@@ -131,7 +131,7 @@ export class FindModelBoundToEditorModel {
// The find model is disposed during a find state changed event
return
;
}
if
(
!
this
.
_editor
.
get
Model
())
{
if
(
!
this
.
_editor
.
has
Model
())
{
// The find model will be disposed momentarily
return
;
}
...
...
src/vs/editor/contrib/indentation/indentation.ts
浏览文件 @
44cbf5af
...
...
@@ -461,7 +461,7 @@ export class AutoIndentOnPaste implements IEditorContribution {
}
// no model
if
(
!
this
.
editor
.
get
Model
())
{
if
(
!
this
.
editor
.
has
Model
())
{
return
;
}
...
...
src/vs/workbench/common/editor/editorGroup.ts
浏览文件 @
44cbf5af
...
...
@@ -44,7 +44,7 @@ export interface ISerializedEditorGroup {
id
:
number
;
editors
:
ISerializedEditorInput
[];
mru
:
number
[];
preview
:
number
;
preview
?
:
number
;
}
export
function
isSerializedEditorGroup
(
obj
?:
any
):
obj
is
ISerializedEditorGroup
{
...
...
@@ -94,8 +94,8 @@ export class EditorGroup extends Disposable {
private
mru
:
EditorInput
[]
=
[];
private
mapResourceToEditorCount
:
ResourceMap
<
number
>
=
new
ResourceMap
<
number
>
();
private
preview
:
EditorInput
;
// editor in preview state
private
active
:
EditorInput
;
// editor in active state
private
preview
:
EditorInput
|
null
;
// editor in preview state
private
active
:
EditorInput
|
null
;
// editor in active state
private
editorOpenPositioning
:
'
left
'
|
'
right
'
|
'
first
'
|
'
last
'
;
...
...
@@ -136,9 +136,9 @@ export class EditorGroup extends Disposable {
return
mru
?
this
.
mru
.
slice
(
0
)
:
this
.
editors
.
slice
(
0
);
}
getEditor
(
index
:
number
):
EditorInput
;
getEditor
(
resource
:
URI
):
EditorInput
;
getEditor
(
arg1
:
any
):
EditorInput
{
getEditor
(
index
:
number
):
EditorInput
|
null
;
getEditor
(
resource
:
URI
):
EditorInput
|
null
;
getEditor
(
arg1
:
any
):
EditorInput
|
null
{
if
(
typeof
arg1
===
'
number
'
)
{
return
this
.
editors
[
arg1
];
}
...
...
@@ -159,7 +159,7 @@ export class EditorGroup extends Disposable {
return
null
;
}
get
activeEditor
():
EditorInput
{
get
activeEditor
():
EditorInput
|
null
{
return
this
.
active
;
}
...
...
@@ -167,7 +167,7 @@ export class EditorGroup extends Disposable {
return
this
.
matches
(
this
.
active
,
editor
);
}
get
previewEditor
():
EditorInput
{
get
previewEditor
():
EditorInput
|
null
{
return
this
.
preview
;
}
...
...
@@ -310,7 +310,7 @@ export class EditorGroup extends Disposable {
}
}
closeEditor
(
editor
:
EditorInput
,
openNext
=
true
):
number
{
closeEditor
(
editor
:
EditorInput
,
openNext
=
true
):
number
|
undefined
{
const
event
=
this
.
doCloseEditor
(
editor
,
openNext
,
false
);
if
(
event
)
{
...
...
@@ -322,7 +322,7 @@ export class EditorGroup extends Disposable {
return
void
0
;
}
private
doCloseEditor
(
editor
:
EditorInput
,
openNext
:
boolean
,
replaced
:
boolean
):
EditorCloseEvent
{
private
doCloseEditor
(
editor
:
EditorInput
,
openNext
:
boolean
,
replaced
:
boolean
):
EditorCloseEvent
|
null
{
const
index
=
this
.
indexOf
(
editor
);
if
(
index
===
-
1
)
{
return
null
;
// not found
...
...
@@ -384,7 +384,9 @@ export class EditorGroup extends Disposable {
// Optimize: close all non active editors first to produce less upstream work
this
.
mru
.
filter
(
e
=>
!
this
.
matches
(
e
,
this
.
active
)).
forEach
(
e
=>
this
.
closeEditor
(
e
));
this
.
closeEditor
(
this
.
active
);
if
(
this
.
active
)
{
this
.
closeEditor
(
this
.
active
);
}
}
moveEditor
(
editor
:
EditorInput
,
toIndex
:
number
):
void
{
...
...
@@ -455,7 +457,9 @@ export class EditorGroup extends Disposable {
this
.
_onDidEditorUnpin
.
fire
(
editor
);
// Close old preview editor if any
this
.
closeEditor
(
oldPreview
);
if
(
oldPreview
)
{
this
.
closeEditor
(
oldPreview
);
}
}
isPinned
(
editor
:
EditorInput
):
boolean
;
...
...
@@ -538,7 +542,7 @@ export class EditorGroup extends Disposable {
}
}
indexOf
(
candidate
:
EditorInput
,
editors
=
this
.
editors
):
number
{
indexOf
(
candidate
:
EditorInput
|
null
,
editors
=
this
.
editors
):
number
{
if
(
!
candidate
)
{
return
-
1
;
}
...
...
@@ -591,7 +595,7 @@ export class EditorGroup extends Disposable {
this
.
mru
.
unshift
(
editor
);
}
private
matches
(
editorA
:
EditorInput
,
editorB
:
EditorInput
):
boolean
{
private
matches
(
editorA
:
EditorInput
|
null
,
editorB
:
EditorInput
|
null
):
boolean
{
return
!!
editorA
&&
!!
editorB
&&
editorA
.
matches
(
editorB
);
}
...
...
@@ -615,7 +619,7 @@ export class EditorGroup extends Disposable {
// from mru, active and preview if any.
let
serializableEditors
:
EditorInput
[]
=
[];
let
serializedEditors
:
ISerializedEditorInput
[]
=
[];
let
serializablePreviewIndex
:
number
;
let
serializablePreviewIndex
:
number
|
undefined
;
this
.
editors
.
forEach
(
e
=>
{
let
factory
=
registry
.
getEditorInputFactory
(
e
.
getTypeId
());
if
(
factory
)
{
...
...
@@ -667,6 +671,8 @@ export class EditorGroup extends Disposable {
}));
this
.
mru
=
data
.
mru
.
map
(
i
=>
this
.
editors
[
i
]);
this
.
active
=
this
.
mru
[
0
];
this
.
preview
=
this
.
editors
[
data
.
preview
];
if
(
typeof
data
.
preview
===
'
number
'
)
{
this
.
preview
=
this
.
editors
[
data
.
preview
];
}
}
}
src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts
浏览文件 @
44cbf5af
...
...
@@ -117,7 +117,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
}
private
onModelChanged
():
void
{
if
(
!
this
.
editor
.
get
Model
())
{
if
(
!
this
.
editor
.
has
Model
())
{
// model could have been disposed during the delay
return
;
}
...
...
src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts
浏览文件 @
44cbf5af
...
...
@@ -65,7 +65,7 @@ class InsertSnippetAction extends EditorAction {
const
modeService
=
accessor
.
get
(
IModeService
);
const
snippetService
=
accessor
.
get
(
ISnippetsService
);
if
(
!
editor
.
get
Model
())
{
if
(
!
editor
.
has
Model
())
{
return
undefined
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录