Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
dc31fa21
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,发现更多精彩内容 >>
提交
dc31fa21
编写于
1月 19, 2018
作者:
J
Johannes Rieken
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
support interleaving file and text changes, basically rewrite bulk edit...
上级
519b4723
变更
23
显示空白变更内容
内联
并排
Showing
23 changed file
with
481 addition
and
566 deletion
+481
-566
src/vs/editor/browser/services/bulkEdit.ts
src/vs/editor/browser/services/bulkEdit.ts
+167
-226
src/vs/editor/common/modes.ts
src/vs/editor/common/modes.ts
+23
-15
src/vs/editor/contrib/quickFix/quickFixCommands.ts
src/vs/editor/contrib/quickFix/quickFixCommands.ts
+2
-7
src/vs/editor/contrib/quickFix/test/quickFix.test.ts
src/vs/editor/contrib/quickFix/test/quickFix.test.ts
+2
-2
src/vs/editor/contrib/rename/rename.ts
src/vs/editor/contrib/rename/rename.ts
+3
-5
src/vs/monaco.d.ts
src/vs/monaco.d.ts
+8
-16
src/vs/platform/progress/common/progress.ts
src/vs/platform/progress/common/progress.ts
+6
-0
src/vs/vscode.d.ts
src/vs/vscode.d.ts
+27
-29
src/vs/workbench/api/electron-browser/mainThreadEditors.ts
src/vs/workbench/api/electron-browser/mainThreadEditors.ts
+13
-40
src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts
...kbench/api/electron-browser/mainThreadLanguageFeatures.ts
+3
-15
src/vs/workbench/api/node/extHost.protocol.ts
src/vs/workbench/api/node/extHost.protocol.ts
+28
-25
src/vs/workbench/api/node/extHostApiCommands.ts
src/vs/workbench/api/node/extHostApiCommands.ts
+1
-5
src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts
src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts
+7
-7
src/vs/workbench/api/node/extHostLanguageFeatures.ts
src/vs/workbench/api/node/extHostLanguageFeatures.ts
+4
-4
src/vs/workbench/api/node/extHostTextEditors.ts
src/vs/workbench/api/node/extHostTextEditors.ts
+13
-30
src/vs/workbench/api/node/extHostTypeConverters.ts
src/vs/workbench/api/node/extHostTypeConverters.ts
+22
-14
src/vs/workbench/api/node/extHostTypes.ts
src/vs/workbench/api/node/extHostTypes.ts
+45
-57
src/vs/workbench/parts/search/browser/replaceService.ts
src/vs/workbench/parts/search/browser/replaceService.ts
+10
-8
src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts
...ectron-browser/api/extHostDocumentSaveParticipant.test.ts
+18
-12
src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts
...test/electron-browser/api/extHostLanguageFeatures.test.ts
+3
-2
src/vs/workbench/test/electron-browser/api/extHostTextEditors.test.ts
...ench/test/electron-browser/api/extHostTextEditors.test.ts
+8
-7
src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts
.../workbench/test/electron-browser/api/extHostTypes.test.ts
+42
-8
src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts
...bench/test/electron-browser/api/mainThreadEditors.test.ts
+26
-32
未找到文件。
src/vs/editor/browser/services/bulkEdit.ts
浏览文件 @
dc31fa21
...
...
@@ -5,75 +5,46 @@
'
use strict
'
;
import
*
as
nls
from
'
vs/nls
'
;
import
{
flatten
}
from
'
vs/base/common/arrays
'
;
import
{
IStringDictionary
,
forEach
,
values
,
groupBy
,
size
}
from
'
vs/base/common/collections
'
;
import
{
IDisposable
,
dispose
,
IReference
}
from
'
vs/base/common/lifecycle
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
ITextModelService
,
ITextEditorModel
}
from
'
vs/editor/common/services/resolverService
'
;
import
{
IFileService
,
IFileChange
}
from
'
vs/platform/files/common/files
'
;
import
{
IFileService
}
from
'
vs/platform/files/common/files
'
;
import
{
EditOperation
}
from
'
vs/editor/common/core/editOperation
'
;
import
{
Range
,
IRange
}
from
'
vs/editor/common/core/range
'
;
import
{
Selection
,
ISelection
}
from
'
vs/editor/common/core/selection
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
Selection
}
from
'
vs/editor/common/core/selection
'
;
import
{
IIdentifiedSingleEditOperation
,
ITextModel
,
EndOfLineSequence
}
from
'
vs/editor/common/model
'
;
import
{
IProgressRunner
}
from
'
vs/platform/progress/common/progress
'
;
import
{
IProgressRunner
,
emptyProgressRunner
,
IProgress
}
from
'
vs/platform/progress/common/progress
'
;
import
{
ICodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
IResourceRename
,
IResourceCreate
}
from
'
vs/editor/common/modes
'
;
import
{
optional
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
ResourceTextEdit
,
ResourceFileEdit
,
isResourceFileEdit
}
from
'
vs/editor/common/modes
'
;
import
{
getPathLabel
}
from
'
vs/base/common/labels
'
;
export
interface
IResourceFileEdit
{
readonly
renamedResources
:
{
from
:
URI
,
to
}[];
readonly
createdResources
:
{
uri
:
URI
,
contents
:
string
}[];
readonly
deletedResources
:
URI
[];
}
export
interface
IResourceEdit
{
resource
:
URI
;
range
?:
IRange
;
newText
:
string
;
newEol
?:
EndOfLineSequence
;
}
interface
IRecording
{
stop
():
void
;
hasChanged
(
resource
:
URI
):
boolean
;
allChanges
():
IFileChange
[];
}
class
ChangeRecorder
{
abstract
class
IRecording
{
private
_fileService
:
IFileService
;
constructor
(
fileService
?:
IFileService
)
{
this
.
_fileService
=
fileService
;
}
public
start
():
IRecording
{
const
changes
:
IStringDictionary
<
IFileChange
[]
>
=
Object
.
create
(
null
);
static
start
(
fileService
:
IFileService
):
IRecording
{
const
_changes
=
new
Set
<
string
>
();
let
stop
:
IDisposable
;
if
(
this
.
_fileService
)
{
stop
=
this
.
_fileService
.
onFileChanges
((
event
)
=>
{
event
.
changes
.
forEach
(
change
=>
{
const
key
=
String
(
change
.
resource
);
let
array
=
changes
[
key
];
if
(
!
array
)
{
changes
[
key
]
=
array
=
[]
;
if
(
fileService
)
{
// watch only when there is a fileservice available
stop
=
fileService
.
onFileChanges
(
event
=>
{
for
(
const
change
of
event
.
changes
)
{
_changes
.
add
(
change
.
resource
.
toString
())
;
}
array
.
push
(
change
);
});
});
}
return
{
stop
:
()
=>
{
return
stop
&&
stop
.
dispose
();
},
hasChanged
:
(
resource
:
URI
)
=>
!!
changes
[
resource
.
toString
()],
allChanges
:
()
=>
flatten
(
values
(
changes
))
stop
()
{
return
dispose
(
stop
);
},
hasChanged
(
resource
)
{
return
_changes
.
has
(
resource
.
toString
());
}
};
}
abstract
stop
():
void
;
abstract
hasChanged
(
resource
:
URI
):
boolean
;
}
class
EditTask
implements
IDisposable
{
...
...
@@ -91,14 +62,21 @@ class EditTask implements IDisposable {
this
.
_edits
=
[];
}
public
addEdit
(
edit
:
IResourceEdit
):
void
{
dispose
()
{
if
(
this
.
_model
)
{
this
.
_modelReference
.
dispose
();
this
.
_modelReference
=
null
;
}
}
addEdit
(
resourceEdit
:
ResourceTextEdit
):
void
{
if
(
typeof
edit
.
newEol
===
'
number
'
)
{
for
(
const
edit
of
resourceEdit
.
edits
)
{
if
(
typeof
edit
.
eol
===
'
number
'
)
{
// honor eol-change
this
.
_newEol
=
edit
.
newE
ol
;
this
.
_newEol
=
edit
.
e
ol
;
}
if
(
edit
.
range
||
edit
.
newText
)
{
if
(
edit
.
range
||
edit
.
text
)
{
// create edit operation
let
range
:
Range
;
if
(
!
edit
.
range
)
{
...
...
@@ -106,11 +84,12 @@ class EditTask implements IDisposable {
}
else
{
range
=
Range
.
lift
(
edit
.
range
);
}
this
.
_edits
.
push
(
EditOperation
.
replaceMove
(
range
,
edit
.
newText
));
this
.
_edits
.
push
(
EditOperation
.
replaceMove
(
range
,
edit
.
text
));
}
}
}
public
apply
():
void
{
apply
():
void
{
if
(
this
.
_edits
.
length
>
0
)
{
this
.
_edits
=
this
.
_edits
.
map
((
value
,
index
)
=>
({
value
,
index
})).
sort
((
a
,
b
)
=>
{
...
...
@@ -167,16 +146,10 @@ class EditTask implements IDisposable {
return
[
this
.
_endCursorSelection
];
}
public
getEndCursorSelection
():
Selection
{
getEndCursorSelection
():
Selection
{
return
this
.
_endCursorSelection
;
}
dispose
()
{
if
(
this
.
_model
)
{
this
.
_modelReference
.
dispose
();
this
.
_modelReference
=
null
;
}
}
}
class
SourceModelEditTask
extends
EditTask
{
...
...
@@ -196,46 +169,42 @@ class SourceModelEditTask extends EditTask {
class
BulkEditModel
implements
IDisposable
{
private
_textModelResolverService
:
ITextModelService
;
private
_numberOfResourcesToModify
:
number
=
0
;
private
_edits
:
IStringDictionary
<
IResourceEdit
[]
>
=
Object
.
create
(
null
);
private
_edits
=
new
Map
<
string
,
ResourceTextEdit
[]
>
();
private
_tasks
:
EditTask
[];
private
_sourceModel
:
URI
;
private
_sourceSelections
:
Selection
[];
private
_sourceModelTask
:
SourceModelEditTask
;
private
_progress
:
IProgress
<
void
>
;
constructor
(
textModelResolverService
:
ITextModelService
,
sourceModel
:
URI
,
sourceSelections
:
Selection
[],
edits
:
IResourceEdit
[],
private
progress
:
IProgressRunner
,
private
renames
:
IResourceRename
[],
private
creates
:
IResourceCreate
[],
private
deletes
:
URI
[],
private
fileService
:
IFileService
editor
:
ICodeEditor
,
edits
:
ResourceTextEdit
[],
progress
:
IProgress
<
void
>
)
{
this
.
_textModelResolverService
=
textModelResolverService
;
this
.
_sourceModel
=
sourceModel
;
this
.
_sourceSelections
=
sourceSelections
;
this
.
_sourceModelTask
=
null
;
this
.
_numberOfResourcesToModify
+=
this
.
renames
.
length
+
this
.
deletes
.
length
+
this
.
creates
.
length
;
this
.
_sourceModel
=
editor
?
editor
.
getModel
().
uri
:
undefined
;
this
.
_sourceSelections
=
editor
?
editor
.
getSelections
()
:
undefined
;
this
.
_sourceModelTask
=
undefined
;
this
.
_progress
=
progress
;
for
(
let
edit
of
edits
)
{
this
.
_addEdit
(
edit
);
edits
.
forEach
(
this
.
addEdit
,
this
);
}
dispose
():
void
{
this
.
_tasks
=
dispose
(
this
.
_tasks
);
}
private
_addEdit
(
edit
:
IResource
Edit
):
void
{
let
array
=
this
.
_edits
[
edit
.
resource
.
toString
()]
;
addEdit
(
edit
:
ResourceText
Edit
):
void
{
let
array
=
this
.
_edits
.
get
(
edit
.
resource
.
toString
())
;
if
(
!
array
)
{
this
.
_edits
[
edit
.
resource
.
toString
()]
=
array
=
[];
this
.
_
numberOfResourcesToModify
+=
1
;
array
=
[];
this
.
_
edits
.
set
(
edit
.
resource
.
toString
(),
array
)
;
}
array
.
push
(
edit
);
}
public
async
prepare
():
TPromise
<
BulkEditModel
>
{
async
prepare
():
TPromise
<
BulkEditModel
>
{
if
(
this
.
_tasks
)
{
throw
new
Error
(
'
illegal state - already prepared
'
);
...
...
@@ -244,42 +213,25 @@ class BulkEditModel implements IDisposable {
this
.
_tasks
=
[];
const
promises
:
TPromise
<
any
>
[]
=
[];
if
(
this
.
progress
)
{
this
.
progress
.
total
(
this
.
_numberOfResourcesToModify
*
2
);
}
await
TPromise
.
join
(
this
.
renames
.
map
(
rename
=>
this
.
fileService
.
moveFile
(
rename
.
from
,
rename
.
to
)));
await
TPromise
.
join
(
this
.
creates
.
map
(
create
=>
this
.
fileService
.
createFile
(
create
.
uri
,
create
.
contents
)));
await
TPromise
.
join
(
this
.
deletes
.
map
(
uri
=>
this
.
fileService
.
del
(
uri
)));
forEach
(
this
.
_edits
,
entry
=>
{
const
promise
=
this
.
_textModelResolverService
.
createModelReference
(
URI
.
parse
(
entry
.
key
)).
then
(
ref
=>
{
this
.
_edits
.
forEach
((
value
,
key
)
=>
{
const
promise
=
this
.
_textModelResolverService
.
createModelReference
(
URI
.
parse
(
key
)).
then
(
ref
=>
{
const
model
=
ref
.
object
;
if
(
!
model
||
!
model
.
textEditorModel
)
{
throw
new
Error
(
`Cannot load file
${
entry
.
key
}
`
);
throw
new
Error
(
`Cannot load file
${
key
}
`
);
}
const
textEditorModel
=
model
.
textEditorModel
;
let
task
:
EditTask
;
if
(
this
.
_sourceModel
&&
textEditorModel
.
uri
.
toString
()
===
this
.
_sourceModel
.
toString
())
{
if
(
this
.
_sourceModel
&&
model
.
textEditorModel
.
uri
.
toString
()
===
this
.
_sourceModel
.
toString
())
{
this
.
_sourceModelTask
=
new
SourceModelEditTask
(
ref
,
this
.
_sourceSelections
);
task
=
this
.
_sourceModelTask
;
}
else
{
task
=
new
EditTask
(
ref
);
}
entry
.
value
.
forEach
(
edit
=>
task
.
addEdit
(
edit
));
value
.
forEach
(
edit
=>
task
.
addEdit
(
edit
));
this
.
_tasks
.
push
(
task
);
if
(
this
.
progress
)
{
this
.
progress
.
worked
(
1
);
}
this
.
_progress
.
report
(
undefined
);
});
promises
.
push
(
promise
);
});
...
...
@@ -289,147 +241,136 @@ class BulkEditModel implements IDisposable {
return
this
;
}
public
apply
():
Selection
{
this
.
_tasks
.
forEach
(
task
=>
this
.
applyTask
(
task
));
let
r
:
Selection
=
null
;
if
(
this
.
_sourceModelTask
)
{
r
=
this
.
_sourceModelTask
.
getEndCursorSelection
();
}
return
r
;
}
private
applyTask
(
task
:
EditTask
):
void
{
apply
():
Selection
{
for
(
const
task
of
this
.
_tasks
)
{
task
.
apply
();
if
(
this
.
progress
)
{
this
.
progress
.
worked
(
1
);
}
this
.
_progress
.
report
(
undefined
);
}
dispose
():
void
{
this
.
_tasks
=
dispose
(
this
.
_tasks
)
;
return
this
.
_sourceModelTask
?
this
.
_sourceModelTask
.
getEndCursorSelection
()
:
undefined
;
}
}
export
interface
BulkEdit
{
progress
(
progress
:
IProgressRunner
):
void
;
add
(
edit
:
IResourceEdit
[]):
void
;
addRename
(
edit
:
IResourceRename
[]):
void
;
addCreate
(
edit
:
IResourceCreate
[]):
void
;
addDelete
(
edit
:
URI
[]):
void
;
finish
():
TPromise
<
ISelection
>
;
ariaMessage
():
string
;
}
export
type
Edit
=
ResourceFileEdit
|
ResourceTextEdit
;
export
function
bulkEdit
(
textModelResolverService
:
ITextModelService
,
editor
:
ICodeEditor
,
edits
:
IResourceEdit
[],
fileService
:
IFileService
,
resourceFileEdits
?:
IResourceFileEdit
):
TPromise
<
any
>
{
let
bulk
=
createBulkEdit
(
textModelResolverService
,
editor
,
fileService
);
bulk
.
add
(
edits
);
bulk
.
addRename
(
resourceFileEdits
.
renamedResources
);
bulk
.
addCreate
(
resourceFileEdits
.
createdResources
);
bulk
.
addDelete
(
resourceFileEdits
.
deletedResources
);
bulk
.
progress
(
null
);
return
bulk
.
finish
();
}
export
class
BulkEdit
{
export
function
createBulkEdit
(
textModelResolverService
:
ITextModelService
,
editor
?:
ICodeEditor
,
fileService
?:
IFileService
):
BulkEdit
{
static
perform
(
edits
:
Edit
[],
textModelService
:
ITextModelService
,
fileService
:
IFileService
,
editor
:
ICodeEditor
):
TPromise
<
any
>
{
const
edit
=
new
BulkEdit
(
editor
,
null
,
textModelService
,
fileService
);
edit
.
add
(
edits
);
return
edit
.
perform
();
}
let
all
:
IResourceEdit
[]
=
[];
const
renames
:
IResourceRename
[]
=
[];
const
creates
:
IResourceCreate
[]
=
[];
const
deletes
:
URI
[]
=
[];
let
recording
=
new
ChangeRecorder
(
fileService
).
start
();
let
progressRunner
:
IProgressRunner
;
private
_edits
:
Edit
[]
=
[];
private
_editor
:
ICodeEditor
;
private
_progress
:
IProgressRunner
;
function
progress
(
progress
:
IProgressRunner
)
{
progressRunner
=
progress
;
constructor
(
editor
:
ICodeEditor
,
progress
:
IProgressRunner
,
@
ITextModelService
private
_textModelService
:
ITextModelService
,
@
optional
(
IFileService
)
private
_fileService
:
IFileService
)
{
this
.
_editor
=
editor
;
this
.
_progress
=
progress
||
emptyProgressRunner
;
}
function
add
(
edits
:
IResourceEdit
[]):
void
{
all
.
push
(...
edits
);
add
(
edits
:
Edit
[]
|
Edit
):
void
{
if
(
Array
.
isArray
(
edits
))
{
this
.
_edits
.
push
(...
edits
);
}
else
{
this
.
_edits
.
push
(
edits
);
}
function
addRename
(
edits
:
IResourceRename
[]):
void
{
renames
.
push
(...
edits
);
}
function
addCreate
(
edits
:
IResourceCreate
[]):
void
{
creates
.
push
(...
edits
);
ariaMessage
():
string
{
const
editCount
=
this
.
_edits
.
reduce
((
prev
,
cur
)
=>
isResourceFileEdit
(
cur
)
?
prev
:
prev
+
cur
.
edits
.
length
,
0
);
const
resourceCount
=
this
.
_edits
.
length
;
if
(
editCount
===
0
)
{
return
nls
.
localize
(
'
summary.0
'
,
"
Made no edits
"
);
}
else
if
(
editCount
>
1
&&
resourceCount
>
1
)
{
return
nls
.
localize
(
'
summary.nm
'
,
"
Made {0} text edits in {1} files
"
,
editCount
,
resourceCount
);
}
else
{
return
nls
.
localize
(
'
summary.n0
'
,
"
Made {0} text edits in one file
"
,
editCount
,
resourceCount
);
}
}
function
addDelete
(
edits
:
URI
[]):
void
{
deletes
.
push
(...
edits
);
async
perform
():
TPromise
<
Selection
>
{
let
seen
=
new
Set
<
string
>
();
let
total
=
0
;
const
groups
:
Edit
[][]
=
[];
let
group
:
Edit
[];
for
(
const
edit
of
this
.
_edits
)
{
if
(
!
group
||
isResourceFileEdit
(
group
[
0
])
===
isResourceFileEdit
(
edit
))
{
group
=
[];
groups
.
push
(
group
);
}
group
.
push
(
edit
);
function
getConcurrentEdits
()
{
let
names
:
string
[];
for
(
let
edit
of
all
)
{
if
(
recording
.
hasChanged
(
edit
.
resource
))
{
if
(
!
names
)
{
names
=
[];
if
(
isResourceFileEdit
(
edit
))
{
total
+=
1
;
}
else
if
(
!
seen
.
has
(
edit
.
resource
.
toString
()))
{
seen
.
add
(
edit
.
resource
.
toString
());
total
+=
2
;
}
names
.
push
(
edit
.
resource
.
fsPath
);
}
// define total work and progress callback
// for child operations
this
.
_progress
.
total
(
total
);
let
progress
:
IProgress
<
void
>
=
{
report
:
_
=>
this
.
_progress
.
worked
(
1
)
};
// do it. return the last selection computed
// by a text change (can be undefined then)
let
res
:
Selection
=
undefined
;
for
(
const
group
of
groups
)
{
if
(
isResourceFileEdit
(
group
[
0
]))
{
await
this
.
_performFileEdits
(
<
ResourceFileEdit
[]
>
group
,
progress
);
}
else
{
res
=
await
this
.
_performTextEdits
(
<
ResourceTextEdit
[]
>
group
,
progress
)
||
res
;
}
if
(
names
)
{
return
nls
.
localize
(
'
conflict
'
,
"
These files have changed in the meantime: {0}
"
,
names
.
join
(
'
,
'
));
}
return
undefined
;
return
res
;
}
function
finish
():
TPromise
<
ISelection
>
{
private
async
_performFileEdits
(
edits
:
ResourceFileEdit
[],
progress
:
IProgress
<
void
>
)
{
for
(
const
edit
of
edits
)
{
if
(
all
.
length
===
0
&&
renames
.
length
===
0
&&
creates
.
length
===
0
&&
deletes
.
length
===
0
)
{
return
TPromise
.
as
(
undefined
);
}
progress
.
report
(
undefined
);
let
concurrentEdits
=
getConcurrentEdits
();
if
(
concurrentEdits
)
{
return
TPromise
.
wrapError
<
ISelection
>
(
new
Error
(
concurrentEdits
));
if
(
edit
.
newUri
&&
edit
.
oldUri
)
{
await
this
.
_fileService
.
moveFile
(
edit
.
oldUri
,
edit
.
newUri
,
false
);
}
else
if
(
!
edit
.
newUri
&&
edit
.
oldUri
)
{
await
this
.
_fileService
.
del
(
edit
.
oldUri
,
true
);
}
else
if
(
edit
.
newUri
&&
!
edit
.
oldUri
)
{
await
this
.
_fileService
.
createFile
(
edit
.
newUri
,
undefined
,
{
overwrite
:
false
});
}
}
let
uri
:
URI
;
let
selections
:
Selection
[];
if
(
editor
&&
editor
.
getModel
())
{
uri
=
editor
.
getModel
().
uri
;
selections
=
editor
.
getSelections
();
}
const
model
=
new
BulkEditModel
(
textModelResolverService
,
uri
,
selections
,
all
,
progressRunner
,
renames
,
creates
,
deletes
,
fileService
);
private
async
_performTextEdits
(
edits
:
ResourceTextEdit
[],
progress
:
IProgress
<
void
>
):
TPromise
<
Selection
>
{
return
model
.
prepare
().
then
(
async
_
=>
{
const
recording
=
IRecording
.
start
(
this
.
_fileService
);
const
model
=
new
BulkEditModel
(
this
.
_textModelService
,
this
.
_editor
,
edits
,
progress
);
let
concurrentEdits
=
getConcurrentEdits
();
if
(
concurrentEdits
)
{
throw
new
Error
(
concurrentEdits
);
}
await
model
.
prepare
();
const
conflicts
=
edits
.
filter
(
edit
=>
recording
.
hasChanged
(
edit
.
resource
))
.
map
(
edit
=>
getPathLabel
(
edit
.
resource
));
recording
.
stop
();
const
result
=
await
model
.
apply
();
if
(
conflicts
.
length
>
0
)
{
model
.
dispose
();
return
result
;
});
throw
new
Error
(
nls
.
localize
(
'
conflict
'
,
"
These files have changed in the meantime: {0}
"
,
conflicts
.
join
(
'
,
'
)));
}
function
ariaMessage
():
string
{
let
editCount
=
all
.
length
;
let
resourceCount
=
size
(
groupBy
(
all
,
edit
=>
edit
.
resource
.
toString
()));
if
(
editCount
===
0
)
{
return
nls
.
localize
(
'
summary.0
'
,
"
Made no edits
"
);
}
else
if
(
editCount
>
1
&&
resourceCount
>
1
)
{
return
nls
.
localize
(
'
summary.nm
'
,
"
Made {0} text edits in {1} files
"
,
editCount
,
resourceCount
);
}
else
{
return
nls
.
localize
(
'
summary.n0
'
,
"
Made {0} text edits in one file
"
,
editCount
,
resourceCount
);
}
const
selection
=
await
model
.
apply
();
model
.
dispose
();
return
selection
;
}
return
{
progress
,
add
,
addRename
,
addCreate
,
addDelete
,
finish
,
ariaMessage
};
}
src/vs/editor/common/modes.ts
浏览文件 @
dc31fa21
...
...
@@ -17,6 +17,7 @@ import { TokenizationRegistryImpl } from 'vs/editor/common/modes/tokenizationReg
import
{
Color
}
from
'
vs/base/common/color
'
;
import
{
IMarkerData
}
from
'
vs/platform/markers/common/markers
'
;
import
*
as
model
from
'
vs/editor/common/model
'
;
import
{
isObject
}
from
'
vs/base/common/types
'
;
/**
* Open ended enum at runtime
...
...
@@ -816,29 +817,36 @@ export interface DocumentColorProvider {
provideColorPresentations
(
model
:
model
.
ITextModel
,
colorInfo
:
IColorInformation
,
token
:
CancellationToken
):
IColorPresentation
[]
|
Thenable
<
IColorPresentation
[]
>
;
}
export
interface
IResourceEdit
{
resource
:
URI
;
range
:
IRange
;
newText
:
string
;
/**
* @internal
*/
export
function
isResourceFileEdit
(
thing
:
any
):
thing
is
ResourceFileEdit
{
return
isObject
(
thing
)
&&
(
Boolean
((
<
ResourceFileEdit
>
thing
).
newUri
)
||
Boolean
((
<
ResourceFileEdit
>
thing
).
oldUri
));
}
/**
* @internal
*/
export
function
isResourceTextEdit
(
thing
:
any
):
thing
is
ResourceTextEdit
{
return
isObject
(
thing
)
&&
(
<
ResourceTextEdit
>
thing
).
resource
&&
Array
.
isArray
((
<
ResourceTextEdit
>
thing
).
edits
);
}
export
interface
IResourceRename
{
readonly
from
:
URI
;
readonly
to
:
URI
;
export
interface
ResourceFileEdit
{
oldUri
:
URI
;
newUri
:
URI
;
}
export
interface
IResourceCreate
{
readonly
uri
:
URI
;
readonly
contents
:
string
;
export
interface
ResourceTextEdit
{
resource
:
URI
;
modelVersionId
?:
number
;
edits
:
TextEdit
[];
}
export
interface
WorkspaceEdit
{
edits
:
IResourceEdit
[];
renamedResources
?:
IResourceRename
[];
createdResources
?:
IResourceCreate
[];
deletedResources
?:
URI
[];
rejectReason
?:
string
;
edits
:
Array
<
ResourceTextEdit
|
ResourceFileEdit
>
;
rejectReason
?:
string
;
// TODO@joh, move to rename
}
export
interface
RenameProvider
{
provideRenameEdits
(
model
:
model
.
ITextModel
,
position
:
Position
,
newName
:
string
,
token
:
CancellationToken
):
WorkspaceEdit
|
Thenable
<
WorkspaceEdit
>
;
}
...
...
src/vs/editor/contrib/quickFix/quickFixCommands.ts
浏览文件 @
dc31fa21
...
...
@@ -22,10 +22,9 @@ import { LightBulbWidget } from './lightBulbWidget';
import
{
QuickFixModel
,
QuickFixComputeEvent
}
from
'
./quickFixModel
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
CodeAction
}
from
'
vs/editor/common/modes
'
;
import
{
b
ulkEdit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
B
ulkEdit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
IFileService
}
from
'
vs/platform/files/common/files
'
;
import
{
ITextModelService
}
from
'
vs/editor/common/services/resolverService
'
;
import
URI
from
'
vs/base/common/uri
'
;
export
class
QuickFixController
implements
IEditorContribution
{
...
...
@@ -113,11 +112,7 @@ export class QuickFixController implements IEditorContribution {
private
async
_onApplyCodeAction
(
action
:
CodeAction
):
TPromise
<
void
>
{
if
(
action
.
edit
)
{
await
bulkEdit
(
this
.
_textModelService
,
this
.
_editor
,
action
.
edit
.
edits
,
this
.
_fileService
,
{
createdResources
:
action
.
edit
.
createdResources
.
map
(
create
=>
({
uri
:
URI
.
revive
(
create
.
uri
),
contents
:
create
.
contents
})),
renamedResources
:
action
.
edit
.
renamedResources
.
map
(
rename
=>
({
from
:
URI
.
revive
(
rename
.
from
),
to
:
URI
.
revive
(
rename
.
to
)
})),
deletedResources
:
action
.
edit
.
deletedResources
.
map
(
URI
.
revive
)
});
await
BulkEdit
.
perform
(
action
.
edit
.
edits
,
this
.
_textModelService
,
this
.
_fileService
,
this
.
_editor
);
}
if
(
action
.
command
)
{
...
...
src/vs/editor/contrib/quickFix/test/quickFix.test.ts
浏览文件 @
dc31fa21
...
...
@@ -8,7 +8,7 @@ import * as assert from 'assert';
import
URI
from
'
vs/base/common/uri
'
;
import
Severity
from
'
vs/base/common/severity
'
;
import
{
TextModel
}
from
'
vs/editor/common/model/textModel
'
;
import
{
CodeActionProviderRegistry
,
LanguageIdentifier
,
CodeActionProvider
,
Command
,
WorkspaceEdit
,
IResource
Edit
}
from
'
vs/editor/common/modes
'
;
import
{
CodeActionProviderRegistry
,
LanguageIdentifier
,
CodeActionProvider
,
Command
,
WorkspaceEdit
,
ResourceText
Edit
}
from
'
vs/editor/common/modes
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
getCodeActions
}
from
'
vs/editor/contrib/quickFix/quickFix
'
;
...
...
@@ -57,7 +57,7 @@ suite('QuickFix', () => {
bcd
:
{
diagnostics
:
[],
edit
:
new
class
implements
WorkspaceEdit
{
edits
:
IResource
Edit
[];
edits
:
ResourceText
Edit
[];
},
title
:
'
abc
'
}
...
...
src/vs/editor/contrib/rename/rename.ts
浏览文件 @
dc31fa21
...
...
@@ -18,7 +18,7 @@ import { registerEditorAction, registerEditorContribution, ServicesAccessor, Edi
import
{
IEditorContribution
}
from
'
vs/editor/common/editorCommon
'
;
import
{
ITextModel
}
from
'
vs/editor/common/model
'
;
import
{
EditorContextKeys
}
from
'
vs/editor/common/editorContextKeys
'
;
import
{
create
BulkEdit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
BulkEdit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
ICodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
RenameInputField
from
'
./renameInputField
'
;
import
{
ITextModelService
}
from
'
vs/editor/common/services/resolverService
'
;
...
...
@@ -147,9 +147,7 @@ class RenameController implements IEditorContribution {
this
.
_renameInputVisible
.
reset
();
this
.
editor
.
focus
();
// start recording of file changes so that we can figure out if a file that
// is to be renamed conflicts with another (concurrent) modification
const
edit
=
createBulkEdit
(
this
.
_textModelResolverService
,
<
ICodeEditor
>
this
.
editor
,
this
.
_fileService
);
const
edit
=
new
BulkEdit
(
this
.
editor
,
null
,
this
.
_textModelResolverService
,
this
.
_fileService
);
const
state
=
new
EditorState
(
this
.
editor
,
CodeEditorStateFlag
.
Position
|
CodeEditorStateFlag
.
Value
|
CodeEditorStateFlag
.
Selection
|
CodeEditorStateFlag
.
Scroll
);
const
renameOperation
=
rename
(
this
.
editor
.
getModel
(),
this
.
editor
.
getPosition
(),
newName
).
then
(
result
=>
{
...
...
@@ -163,7 +161,7 @@ class RenameController implements IEditorContribution {
}
edit
.
add
(
result
.
edits
);
return
edit
.
finish
().
then
(
selection
=>
{
return
edit
.
perform
().
then
(
selection
=>
{
if
(
selection
)
{
this
.
editor
.
setSelection
(
selection
);
}
...
...
src/vs/monaco.d.ts
浏览文件 @
dc31fa21
...
...
@@ -4907,27 +4907,19 @@ declare module monaco.languages {
provideColorPresentations
(
model
:
editor
.
ITextModel
,
colorInfo
:
IColorInformation
,
token
:
CancellationToken
):
IColorPresentation
[]
|
Thenable
<
IColorPresentation
[]
>
;
}
export
interface
IResourceEdit
{
resource
:
Uri
;
range
:
IRange
;
newText
:
string
;
}
export
interface
IResourceRename
{
readonly
from
:
Uri
;
readonly
to
:
Uri
;
export
interface
ResourceFileEdit
{
oldUri
:
Uri
;
newUri
:
Uri
;
}
export
interface
IResourceCreate
{
readonly
uri
:
Uri
;
readonly
contents
:
string
;
export
interface
ResourceTextEdit
{
resource
:
Uri
;
modelVersionId
?:
number
;
edits
:
TextEdit
[];
}
export
interface
WorkspaceEdit
{
edits
:
IResourceEdit
[];
renamedResources
?:
IResourceRename
[];
createdResources
?:
IResourceCreate
[];
deletedResources
?:
Uri
[];
edits
:
Array
<
ResourceTextEdit
|
ResourceFileEdit
>
;
rejectReason
?:
string
;
}
...
...
src/vs/platform/progress/common/progress.ts
浏览文件 @
dc31fa21
...
...
@@ -31,6 +31,12 @@ export interface IProgressRunner {
done
():
void
;
}
export
const
emptyProgressRunner
:
IProgressRunner
=
Object
.
freeze
({
total
()
{
},
worked
()
{
},
done
()
{
}
});
export
interface
IProgress
<
T
>
{
report
(
item
:
T
):
void
;
}
...
...
src/vs/vscode.d.ts
浏览文件 @
dc31fa21
...
...
@@ -2430,29 +2430,6 @@ declare module 'vscode' {
*/
readonly
size
:
number
;
/**
* Renames a given resource in the workspace.
*
* @param from Uri of current resource.
* @param to Uri of renamed resource.
*/
renameResource
(
from
:
Uri
,
to
:
Uri
):
void
;
/**
* Create a new resource in the workspace.
*
* @param uri Uri of resource to create.
* @param contents New file contents.
*/
createResource
(
uri
:
Uri
,
contents
:
String
):
void
;
/**
* Delete a given resource in the workspace.
*
* @param uri Uri of resource to delete.
*/
deleteResource
(
uri
:
Uri
):
void
;
/**
* Replace the given range with given text for the given resource.
*
...
...
@@ -2510,19 +2487,40 @@ declare module 'vscode' {
entries
():
[
Uri
,
TextEdit
[]][];
/**
* Get all resource rename edits.
* Renames a given resource in the workspace.
*
* @param from Uri of current resource.
* @param to Uri of renamed resource.
*/
renameResource
(
from
:
Uri
,
to
:
Uri
):
void
;
/**
* Create a new resource in the workspace.
*
* @param uri Uri of resource to create.
*/
createResource
(
uri
:
Uri
):
void
;
/**
* Delete a given resource in the workspace.
*
* @param uri Uri of resource to delete.
*/
readonly
renamedResources
:
{
from
:
Uri
,
to
:
Uri
}[]
;
deleteResource
(
uri
:
Uri
):
void
;
/**
* Get all resource create edits.
* Get the resource edits for this workspace edit.
*
* @returns A array of uri-tuples in which a rename-edit
* is represented as `[from, to]`, a delete-operation as `[from, null]`,
* and a create-operation as `[null, to]`;
*/
re
adonly
createdResources
:
{
uri
:
Uri
,
contents
:
string
}
[];
re
sourceEdits
():
[
Uri
,
Uri
]
[];
/**
*
Get all resource delete edits.
*
*/
readonly
deletedResources
:
Uri
[];
allEntries
():
([
Uri
,
TextEdit
[]]
|
[
Uri
,
Uri
])
[];
}
/**
...
...
src/vs/workbench/api/electron-browser/mainThreadEditors.ts
浏览文件 @
dc31fa21
...
...
@@ -15,17 +15,18 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import
{
IEditorGroupService
}
from
'
vs/workbench/services/group/common/groupService
'
;
import
{
Position
as
EditorPosition
,
ITextEditorOptions
}
from
'
vs/platform/editor/common/editor
'
;
import
{
MainThreadTextEditor
}
from
'
./mainThreadEditor
'
;
import
{
ITextEditorConfigurationUpdate
,
TextEditorRevealType
,
IApplyEditsOptions
,
IUndoStopOptions
,
IResourceFileEdit
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
ITextEditorConfigurationUpdate
,
TextEditorRevealType
,
IApplyEditsOptions
,
IUndoStopOptions
,
WorkspaceEditDto
,
reviveWorkspaceEditDto
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
MainThreadDocumentsAndEditors
}
from
'
./mainThreadDocumentsAndEditors
'
;
import
{
equals
as
objectEquals
}
from
'
vs/base/common/objects
'
;
import
{
ExtHostContext
,
MainThreadEditorsShape
,
ExtHostEditorsShape
,
ITextDocumentShowOptions
,
ITextEditorPositionData
,
IExtHostContext
,
IWorkspaceResourceEdit
}
from
'
../node/extHost.protocol
'
;
import
{
ExtHostContext
,
MainThreadEditorsShape
,
ExtHostEditorsShape
,
ITextDocumentShowOptions
,
ITextEditorPositionData
,
IExtHostContext
}
from
'
../node/extHost.protocol
'
;
import
{
IRange
}
from
'
vs/editor/common/core/range
'
;
import
{
ISelection
}
from
'
vs/editor/common/core/selection
'
;
import
{
ITextModelService
}
from
'
vs/editor/common/services/resolverService
'
;
import
{
IFileService
}
from
'
vs/platform/files/common/files
'
;
import
{
bulkEdit
,
IResource
Edit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
Bulk
Edit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
IModelService
}
from
'
vs/editor/common/services/modelService
'
;
import
{
isCodeEditor
,
ICodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
isResourceFileEdit
}
from
'
vs/editor/common/modes
'
;
export
class
MainThreadEditors
implements
MainThreadEditorsShape
{
...
...
@@ -210,40 +211,22 @@ export class MainThreadEditors implements MainThreadEditorsShape {
return
TPromise
.
as
(
this
.
_documentsAndEditors
.
getEditor
(
id
).
applyEdits
(
modelVersionId
,
edits
,
opts
));
}
$tryApplyWorkspaceEdit
(
workspaceResourceEdits
:
IWorkspaceResourceEdit
[],
resourceFileEdits
?:
IResourceFileEdit
):
TPromise
<
boolean
>
{
$tryApplyWorkspaceEdit
(
dto
:
WorkspaceEditDto
):
TPromise
<
boolean
>
{
const
{
edits
}
=
reviveWorkspaceEditDto
(
dto
);
// First check if loaded models were not changed in the meantime
for
(
let
i
=
0
,
len
=
workspaceResourceEdits
.
length
;
i
<
len
;
i
++
)
{
const
workspaceResourceEdit
=
workspaceResourceEdits
[
i
];
if
(
workspaceResourceEdit
.
modelVersionId
)
{
const
uri
=
URI
.
revive
(
workspaceResourceEdit
.
resource
);
let
model
=
this
.
_modelService
.
getModel
(
uri
);
if
(
model
&&
model
.
getVersionId
()
!==
workspaceResourceEdit
.
modelVersionId
)
{
for
(
let
i
=
0
,
len
=
edits
.
length
;
i
<
len
;
i
++
)
{
const
edit
=
edits
[
i
];
if
(
!
isResourceFileEdit
(
edit
)
&&
edit
.
modelVersionId
)
{
let
model
=
this
.
_modelService
.
getModel
(
edit
.
resource
);
if
(
model
&&
model
.
getVersionId
()
!==
edit
.
modelVersionId
)
{
// model changed in the meantime
return
TPromise
.
as
(
false
);
}
}
}
// Convert to shape expected by bulkEdit below
let
resourceEdits
:
IResourceEdit
[]
=
[];
for
(
let
i
=
0
,
len
=
workspaceResourceEdits
.
length
;
i
<
len
;
i
++
)
{
const
workspaceResourceEdit
=
workspaceResourceEdits
[
i
];
const
uri
=
URI
.
revive
(
workspaceResourceEdit
.
resource
);
const
edits
=
workspaceResourceEdit
.
edits
;
for
(
let
j
=
0
,
lenJ
=
edits
.
length
;
j
<
lenJ
;
j
++
)
{
const
edit
=
edits
[
j
];
resourceEdits
.
push
({
resource
:
uri
,
newText
:
edit
.
newText
,
newEol
:
edit
.
newEol
,
range
:
edit
.
range
});
}
}
let
codeEditor
:
ICodeEditor
;
let
editor
=
this
.
_workbenchEditorService
.
getActiveEditor
();
if
(
editor
)
{
...
...
@@ -253,17 +236,7 @@ export class MainThreadEditors implements MainThreadEditorsShape {
}
}
return
bulkEdit
(
this
.
_textModelResolverService
,
codeEditor
,
resourceEdits
,
this
.
_fileService
,
resourceFileEdits
?
{
renamedResources
:
resourceFileEdits
.
renamedResources
.
map
(
entry
=>
({
from
:
URI
.
revive
(
entry
.
from
),
to
:
URI
.
revive
(
entry
.
to
)
})),
createdResources
:
resourceFileEdits
.
createdResources
.
map
(
entry
=>
({
uri
:
URI
.
revive
(
entry
.
uri
),
contents
:
entry
.
contents
})),
deletedResources
:
resourceFileEdits
.
deletedResources
.
map
(
URI
.
revive
)
}
:
undefined
).
then
(()
=>
true
);
return
BulkEdit
.
perform
(
edits
,
this
.
_textModelResolverService
,
this
.
_fileService
,
codeEditor
).
then
(()
=>
true
);
}
$tryInsertSnippet
(
id
:
string
,
template
:
string
,
ranges
:
IRange
[],
opts
:
IUndoStopOptions
):
TPromise
<
boolean
>
{
...
...
src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts
浏览文件 @
dc31fa21
...
...
@@ -15,7 +15,7 @@ import { wireCancellationToken } from 'vs/base/common/async';
import
{
CancellationToken
}
from
'
vs/base/common/cancellation
'
;
import
{
Position
as
EditorPosition
}
from
'
vs/editor/common/core/position
'
;
import
{
Range
as
EditorRange
}
from
'
vs/editor/common/core/range
'
;
import
{
ExtHostContext
,
MainThreadLanguageFeaturesShape
,
ExtHostLanguageFeaturesShape
,
MainContext
,
IExtHostContext
,
ISerializedLanguageConfiguration
,
ISerializedRegExp
,
ISerializedIndentationRule
,
ISerializedOnEnterRule
,
LocationDto
,
SymbolInformationDto
,
WorkspaceEditDto
,
ResourceEditDto
,
CodeAction
Dto
}
from
'
../node/extHost.protocol
'
;
import
{
ExtHostContext
,
MainThreadLanguageFeaturesShape
,
ExtHostLanguageFeaturesShape
,
MainContext
,
IExtHostContext
,
ISerializedLanguageConfiguration
,
ISerializedRegExp
,
ISerializedIndentationRule
,
ISerializedOnEnterRule
,
LocationDto
,
SymbolInformationDto
,
CodeActionDto
,
reviveWorkspaceEdit
Dto
}
from
'
../node/extHost.protocol
'
;
import
{
LanguageConfigurationRegistry
}
from
'
vs/editor/common/modes/languageConfigurationRegistry
'
;
import
{
LanguageConfiguration
,
IndentationRule
,
OnEnterRule
}
from
'
vs/editor/common/modes/languageConfiguration
'
;
import
{
IHeapService
}
from
'
./mainThreadHeapService
'
;
...
...
@@ -86,21 +86,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
}
private
static
_reviveResourceEditDto
(
data
:
ResourceEditDto
):
modes
.
IResourceEdit
{
data
.
resource
=
URI
.
revive
(
data
.
resource
);
return
<
modes
.
IResourceEdit
>
data
;
}
private
static
_reviveWorkspaceEditDto
(
data
:
WorkspaceEditDto
):
modes
.
WorkspaceEdit
{
if
(
data
&&
data
.
edits
)
{
data
.
edits
.
forEach
(
MainThreadLanguageFeatures
.
_reviveResourceEditDto
);
}
return
<
modes
.
WorkspaceEdit
>
data
;
}
private
static
_reviveCodeActionDto
(
data
:
CodeActionDto
[]):
modes
.
CodeAction
[]
{
if
(
data
)
{
data
.
forEach
(
code
=>
MainThreadLanguageFeatures
.
_
reviveWorkspaceEditDto
(
code
.
edit
));
data
.
forEach
(
code
=>
reviveWorkspaceEditDto
(
code
.
edit
));
}
return
<
modes
.
CodeAction
[]
>
data
;
}
...
...
@@ -266,7 +254,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerRenameSupport
(
handle
:
number
,
selector
:
vscode
.
DocumentSelector
):
void
{
this
.
_registrations
[
handle
]
=
modes
.
RenameProviderRegistry
.
register
(
toLanguageSelector
(
selector
),
<
modes
.
RenameProvider
>
{
provideRenameEdits
:
(
model
:
ITextModel
,
position
:
EditorPosition
,
newName
:
string
,
token
:
CancellationToken
):
Thenable
<
modes
.
WorkspaceEdit
>
=>
{
return
wireCancellationToken
(
token
,
this
.
_proxy
.
$provideRenameEdits
(
handle
,
model
.
uri
,
position
,
newName
)).
then
(
MainThreadLanguageFeatures
.
_
reviveWorkspaceEditDto
);
return
wireCancellationToken
(
token
,
this
.
_proxy
.
$provideRenameEdits
(
handle
,
model
.
uri
,
position
,
newName
)).
then
(
reviveWorkspaceEditDto
);
}
});
}
...
...
src/vs/workbench/api/node/extHost.protocol.ts
浏览文件 @
dc31fa21
...
...
@@ -14,7 +14,7 @@ import {
import
*
as
vscode
from
'
vscode
'
;
import
{
UriComponents
}
from
'
vs/base/common/uri
'
;
import
URI
,
{
UriComponents
}
from
'
vs/base/common/uri
'
;
import
Severity
from
'
vs/base/common/severity
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
...
...
@@ -52,7 +52,7 @@ import { IStat, IFileChange } from 'vs/platform/files/common/files';
import
{
ConfigurationScope
}
from
'
vs/platform/configuration/common/configurationRegistry
'
;
import
{
ParsedArgs
}
from
'
vs/platform/environment/common/environment
'
;
import
{
CommentRule
,
CharacterPair
,
EnterAction
}
from
'
vs/editor/common/modes/languageConfiguration
'
;
import
{
EndOfLineSequence
,
ISingleEditOperation
}
from
'
vs/editor/common/model
'
;
import
{
ISingleEditOperation
}
from
'
vs/editor/common/model
'
;
export
interface
IEnvironment
{
isExtensionDevelopmentDebug
:
boolean
;
...
...
@@ -191,8 +191,6 @@ export interface IApplyEditsOptions extends IUndoStopOptions {
setEndOfLine
:
EndOfLine
;
}
export
interface
ITextDocumentShowOptions
{
position
?:
EditorPosition
;
preserveFocus
?:
boolean
;
...
...
@@ -200,22 +198,6 @@ export interface ITextDocumentShowOptions {
selection
?:
IRange
;
}
export
interface
IWorkspaceResourceEdit
{
resource
:
UriComponents
;
modelVersionId
?:
number
;
edits
:
{
range
?:
IRange
;
newText
:
string
;
newEol
?:
EndOfLineSequence
;
}[];
}
export
interface
IResourceFileEdit
{
renamedResources
:
{
from
:
UriComponents
,
to
:
UriComponents
}[];
createdResources
:
{
uri
:
UriComponents
,
contents
:
string
}[];
deletedResources
:
UriComponents
[];
}
export
interface
MainThreadEditorsShape
extends
IDisposable
{
$tryShowTextDocument
(
resource
:
UriComponents
,
options
:
ITextDocumentShowOptions
):
TPromise
<
string
>
;
$registerTextEditorDecorationType
(
key
:
string
,
options
:
editorCommon
.
IDecorationRenderOptions
):
void
;
...
...
@@ -228,7 +210,7 @@ export interface MainThreadEditorsShape extends IDisposable {
$tryRevealRange
(
id
:
string
,
range
:
IRange
,
revealType
:
TextEditorRevealType
):
TPromise
<
void
>
;
$trySetSelections
(
id
:
string
,
selections
:
ISelection
[]):
TPromise
<
void
>
;
$tryApplyEdits
(
id
:
string
,
modelVersionId
:
number
,
edits
:
ISingleEditOperation
[],
opts
:
IApplyEditsOptions
):
TPromise
<
boolean
>
;
$tryApplyWorkspaceEdit
(
workspace
ResourceEdits
:
IWorkspaceResourceEdit
[],
resourceFileEdits
?:
IResourceFileEdit
):
TPromise
<
boolean
>
;
$tryApplyWorkspaceEdit
(
workspace
EditDto
:
WorkspaceEditDto
):
TPromise
<
boolean
>
;
$tryInsertSnippet
(
id
:
string
,
template
:
string
,
selections
:
IRange
[],
opts
:
IUndoStopOptions
):
TPromise
<
boolean
>
;
$getDiffInformation
(
id
:
string
):
TPromise
<
editorCommon
.
ILineChange
[]
>
;
}
...
...
@@ -622,17 +604,38 @@ export interface WorkspaceSymbolsDto extends IdObject {
symbols
:
SymbolInformationDto
[];
}
export
interface
ResourceEditDto
{
export
interface
ResourceFileEditDto
{
oldUri
:
UriComponents
;
newUri
:
UriComponents
;
}
export
interface
ResourceTextEditDto
{
resource
:
UriComponents
;
range
:
IRange
;
newText
:
string
;
modelVersionId
?:
number
;
edits
:
modes
.
TextEdit
[]
;
}
export
interface
WorkspaceEditDto
{
edits
:
ResourceEditDto
[];
edits
:
(
ResourceFileEditDto
|
ResourceTextEditDto
)[];
// todo@joh reject should go into rename
rejectReason
?:
string
;
}
export
function
reviveWorkspaceEditDto
(
data
:
WorkspaceEditDto
):
modes
.
WorkspaceEdit
{
if
(
data
&&
data
.
edits
)
{
for
(
const
edit
of
data
.
edits
)
{
if
(
typeof
(
<
ResourceTextEditDto
>
edit
).
resource
===
'
object
'
)
{
(
<
ResourceTextEditDto
>
edit
).
resource
=
URI
.
revive
((
<
ResourceTextEditDto
>
edit
).
resource
);
}
else
{
(
<
ResourceFileEditDto
>
edit
).
newUri
=
URI
.
revive
((
<
ResourceFileEditDto
>
edit
).
newUri
);
(
<
ResourceFileEditDto
>
edit
).
oldUri
=
URI
.
revive
((
<
ResourceFileEditDto
>
edit
).
oldUri
);
}
}
}
return
<
modes
.
WorkspaceEdit
>
data
;
}
export
interface
CodeActionDto
{
title
:
string
;
edit
?:
WorkspaceEditDto
;
...
...
src/vs/workbench/api/node/extHostApiCommands.ts
浏览文件 @
dc31fa21
...
...
@@ -344,11 +344,7 @@ export class ExtHostApiCommands {
if
(
value
.
rejectReason
)
{
return
TPromise
.
wrapError
<
types
.
WorkspaceEdit
>
(
new
Error
(
value
.
rejectReason
));
}
let
workspaceEdit
=
new
types
.
WorkspaceEdit
();
for
(
let
edit
of
value
.
edits
)
{
workspaceEdit
.
replace
(
edit
.
resource
,
typeConverters
.
toRange
(
edit
.
range
),
edit
.
newText
);
}
return
workspaceEdit
;
return
typeConverters
.
WorkspaceEdit
.
to
(
value
);
});
}
...
...
src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts
浏览文件 @
dc31fa21
...
...
@@ -8,7 +8,7 @@ import Event from 'vs/base/common/event';
import
URI
,
{
UriComponents
}
from
'
vs/base/common/uri
'
;
import
{
sequence
,
always
}
from
'
vs/base/common/async
'
;
import
{
illegalState
}
from
'
vs/base/common/errors
'
;
import
{
ExtHostDocumentSaveParticipantShape
,
MainThreadEditorsShape
,
IWorkspaceResourceEdit
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
ExtHostDocumentSaveParticipantShape
,
MainThreadEditorsShape
,
ResourceTextEditDto
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
TextEdit
}
from
'
vs/workbench/api/node/extHostTypes
'
;
import
{
fromRange
,
TextDocumentSaveReason
,
EndOfLine
}
from
'
vs/workbench/api/node/extHostTypeConverters
'
;
import
{
ExtHostDocuments
}
from
'
vs/workbench/api/node/extHostDocuments
'
;
...
...
@@ -142,7 +142,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
}).
then
(
values
=>
{
let
workspaceResourceEdit
:
IWorkspaceResourceEdit
=
{
const
resourceEdit
:
ResourceTextEditDto
=
{
resource
:
document
.
uri
,
edits
:
[]
};
...
...
@@ -150,10 +150,10 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
for
(
const
value
of
values
)
{
if
(
Array
.
isArray
(
value
)
&&
(
<
vscode
.
TextEdit
[]
>
value
).
every
(
e
=>
e
instanceof
TextEdit
))
{
for
(
const
{
newText
,
newEol
,
range
}
of
value
)
{
workspaceR
esourceEdit
.
edits
.
push
({
r
esourceEdit
.
edits
.
push
({
range
:
range
&&
fromRange
(
range
),
newText
,
newE
ol
:
EndOfLine
.
from
(
newEol
)
text
:
newText
,
e
ol
:
EndOfLine
.
from
(
newEol
)
});
}
}
...
...
@@ -161,12 +161,12 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
// apply edits if any and if document
// didn't change somehow in the meantime
if
(
workspaceR
esourceEdit
.
edits
.
length
===
0
)
{
if
(
r
esourceEdit
.
edits
.
length
===
0
)
{
return
undefined
;
}
if
(
version
===
document
.
version
)
{
return
this
.
_mainThreadEditors
.
$tryApplyWorkspaceEdit
(
[
workspaceResourceEdit
]
);
return
this
.
_mainThreadEditors
.
$tryApplyWorkspaceEdit
(
{
edits
:
[
resourceEdit
]
}
);
}
// TODO@joh bubble this to listener?
...
...
src/vs/workbench/api/node/extHostLanguageFeatures.ts
浏览文件 @
dc31fa21
...
...
@@ -17,7 +17,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import
{
ExtHostCommands
,
CommandsConverter
}
from
'
vs/workbench/api/node/extHostCommands
'
;
import
{
ExtHostDiagnostics
,
DiagnosticCollection
}
from
'
vs/workbench/api/node/extHostDiagnostics
'
;
import
{
asWinJsPromise
}
from
'
vs/base/common/async
'
;
import
{
MainContext
,
MainThreadLanguageFeaturesShape
,
ExtHostLanguageFeaturesShape
,
ObjectIdentifier
,
IRawColorInfo
,
IMainContext
,
IdObject
,
ISerializedRegExp
,
ISerializedIndentationRule
,
ISerializedOnEnterRule
,
ISerializedLanguageConfiguration
,
SymbolInformationDto
,
SuggestResultDto
,
WorkspaceSymbolsDto
,
SuggestionDto
}
from
'
./extHost.protocol
'
;
import
{
MainContext
,
MainThreadLanguageFeaturesShape
,
ExtHostLanguageFeaturesShape
,
ObjectIdentifier
,
IRawColorInfo
,
IMainContext
,
IdObject
,
ISerializedRegExp
,
ISerializedIndentationRule
,
ISerializedOnEnterRule
,
ISerializedLanguageConfiguration
,
SymbolInformationDto
,
SuggestResultDto
,
WorkspaceSymbolsDto
,
SuggestionDto
,
CodeActionDto
}
from
'
./extHost.protocol
'
;
import
{
regExpLeadsToEndlessLoop
}
from
'
vs/base/common/strings
'
;
import
{
IPosition
}
from
'
vs/editor/common/core/position
'
;
import
{
IRange
}
from
'
vs/editor/common/core/range
'
;
...
...
@@ -255,7 +255,7 @@ class ReferenceAdapter {
}
}
export
interface
CustomCodeAction
extends
modes
.
CodeAction
{
export
interface
CustomCodeAction
extends
CodeActionDto
{
_isSynthetic
?:
boolean
;
}
...
...
@@ -273,7 +273,7 @@ class CodeActionAdapter {
this
.
_provider
=
provider
;
}
provideCodeActions
(
resource
:
URI
,
range
:
IRange
):
TPromise
<
modes
.
CodeAction
[]
>
{
provideCodeActions
(
resource
:
URI
,
range
:
IRange
):
TPromise
<
CodeActionDto
[]
>
{
const
doc
=
this
.
_documents
.
getDocumentData
(
resource
).
document
;
const
ran
=
<
vscode
.
Range
>
TypeConverters
.
toRange
(
range
);
...
...
@@ -943,7 +943,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return
this
.
_createDisposable
(
handle
);
}
$provideCodeActions
(
handle
:
number
,
resource
:
UriComponents
,
range
:
IRange
):
TPromise
<
modes
.
CodeAction
[]
>
{
$provideCodeActions
(
handle
:
number
,
resource
:
UriComponents
,
range
:
IRange
):
TPromise
<
CodeActionDto
[]
>
{
return
this
.
_withAdapter
(
handle
,
CodeActionAdapter
,
adapter
=>
adapter
.
provideCodeActions
(
URI
.
revive
(
resource
),
range
));
}
...
...
src/vs/workbench/api/node/extHostTextEditors.ts
浏览文件 @
dc31fa21
...
...
@@ -12,7 +12,7 @@ import * as TypeConverters from './extHostTypeConverters';
import
{
TextEditorDecorationType
,
ExtHostTextEditor
}
from
'
./extHostTextEditor
'
;
import
{
ExtHostDocumentsAndEditors
}
from
'
./extHostDocumentsAndEditors
'
;
import
{
Position
as
EditorPosition
}
from
'
vs/platform/editor/common/editor
'
;
import
{
MainContext
,
MainThreadEditorsShape
,
ExtHostEditorsShape
,
ITextDocumentShowOptions
,
ITextEditorPositionData
,
IResolvedTextEditorConfiguration
,
ISelectionChangeEvent
,
IMainContext
,
IWorkspaceResourceEdit
}
from
'
./extHost.protocol
'
;
import
{
MainContext
,
MainThreadEditorsShape
,
ExtHostEditorsShape
,
ITextDocumentShowOptions
,
ITextEditorPositionData
,
IResolvedTextEditorConfiguration
,
ISelectionChangeEvent
,
IMainContext
,
WorkspaceEditDto
}
from
'
./extHost.protocol
'
;
import
*
as
vscode
from
'
vscode
'
;
export
class
ExtHostEditors
implements
ExtHostEditorsShape
{
...
...
@@ -92,40 +92,23 @@ export class ExtHostEditors implements ExtHostEditorsShape {
applyWorkspaceEdit
(
edit
:
vscode
.
WorkspaceEdit
):
TPromise
<
boolean
>
{
let
workspaceResourceEdits
:
IWorkspaceResourceEdit
[]
=
[];
let
entries
=
edit
.
entries
();
for
(
let
entry
of
entries
)
{
let
[
uri
,
edits
]
=
entry
;
const
dto
:
WorkspaceEditDto
=
{
edits
:
[]
};
for
(
let
entry
of
edit
.
allEntries
())
{
let
[
uri
,
uriOrEdits
]
=
entry
;
if
(
Array
.
isArray
(
uriOrEdits
))
{
let
doc
=
this
.
_extHostDocumentsAndEditors
.
getDocument
(
uri
.
toString
());
let
docVersion
:
number
=
undefined
;
if
(
doc
)
{
docVersion
=
doc
.
version
;
}
let
workspaceResourceEdit
:
IWorkspaceResourceEdit
=
{
dto
.
edits
.
push
({
resource
:
uri
,
modelVersionId
:
docVersion
,
edits
:
[]
};
for
(
let
edit
of
edits
)
{
workspaceResourceEdit
.
edits
.
push
({
newText
:
edit
.
newText
,
newEol
:
TypeConverters
.
EndOfLine
.
from
(
edit
.
newEol
),
range
:
edit
.
range
&&
TypeConverters
.
fromRange
(
edit
.
range
)
modelVersionId
:
doc
&&
doc
.
version
,
edits
:
uriOrEdits
.
map
(
TypeConverters
.
TextEdit
.
from
)
});
}
else
{
dto
.
edits
.
push
({
oldUri
:
uri
,
newUri
:
uriOrEdits
});
}
workspaceResourceEdits
.
push
(
workspaceResourceEdit
);
}
return
this
.
_proxy
.
$tryApplyWorkspaceEdit
(
workspaceResourceEdits
,
{
createdResources
:
edit
.
createdResources
,
renamedResources
:
edit
.
renamedResources
,
deletedResources
:
edit
.
deletedResources
});
return
this
.
_proxy
.
$tryApplyWorkspaceEdit
(
dto
);
}
// --- called from main thread
...
...
src/vs/workbench/api/node/extHostTypeConverters.ts
浏览文件 @
dc31fa21
...
...
@@ -20,6 +20,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
import
*
as
htmlContent
from
'
vs/base/common/htmlContent
'
;
import
{
IRelativePattern
}
from
'
vs/base/common/glob
'
;
import
{
LanguageSelector
,
LanguageFilter
}
from
'
vs/editor/common/modes/languageSelector
'
;
import
{
WorkspaceEditDto
,
ResourceTextEditDto
,
ResourceFileEditDto
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
export
interface
PositionLike
{
line
:
number
;
...
...
@@ -229,28 +230,35 @@ export const TextEdit = {
export
namespace
WorkspaceEdit
{
export
function
from
(
value
:
vscode
.
WorkspaceEdit
):
modes
.
WorkspaceEdit
{
const
result
:
modes
.
WorkspaceEdit
=
{
edits
:
[],
renamedResources
:
value
.
renamedResources
,
createdResources
:
value
.
createdResources
,
deletedResources
:
value
.
deletedResources
edits
:
[]
};
for
(
let
entry
of
value
.
e
ntries
())
{
let
[
uri
,
text
Edits
]
=
entry
;
for
(
let
textEdit
of
textEdits
)
{
result
.
edits
.
push
({
resource
:
uri
,
newText
:
textEdit
.
newText
,
range
:
fromRange
(
textEdit
.
range
)
});
for
(
const
entry
of
value
.
allE
ntries
())
{
const
[
uri
,
uriOr
Edits
]
=
entry
;
if
(
Array
.
isArray
(
uriOrEdits
)
)
{
// text edits
result
.
edits
.
push
({
resource
:
uri
,
edits
:
uriOrEdits
.
map
(
TextEdit
.
from
)
});
}
else
{
// resource edits
result
.
edits
.
push
({
oldUri
:
uri
,
newUri
:
uriOrEdits
});
}
}
return
result
;
}
export
function
to
(
value
:
modes
.
WorkspaceEdit
)
{
export
function
to
(
value
:
WorkspaceEditDto
)
{
const
result
=
new
types
.
WorkspaceEdit
();
for
(
const
edit
of
value
.
edits
)
{
result
.
replace
(
edit
.
resource
,
toRange
(
edit
.
range
),
edit
.
newText
);
if
(
Array
.
isArray
((
<
ResourceTextEditDto
>
edit
).
edits
))
{
result
.
set
(
URI
.
revive
((
<
ResourceTextEditDto
>
edit
).
resource
),
<
types
.
TextEdit
[]
>
(
<
ResourceTextEditDto
>
edit
).
edits
.
map
(
TextEdit
.
to
)
);
}
else
{
result
.
renameResource
(
URI
.
revive
((
<
ResourceFileEditDto
>
edit
).
oldUri
),
URI
.
revive
((
<
ResourceFileEditDto
>
edit
).
newUri
)
);
}
}
return
result
;
}
...
...
src/vs/workbench/api/node/extHostTypes.ts
浏览文件 @
dc31fa21
...
...
@@ -491,44 +491,28 @@ export class TextEdit {
}
}
export
class
WorkspaceEdit
{
export
class
WorkspaceEdit
implements
vscode
.
WorkspaceEdit
{
private
_values
:
[
URI
,
TextEdit
[]][]
=
[];
private
readonly
_resourcesCreated
:
{
uri
:
URI
,
contents
:
string
}[]
=
[];
private
readonly
_resourcesDeleted
:
URI
[]
=
[];
private
readonly
_resourcesRenamed
:
{
from
:
URI
,
to
:
URI
}[]
=
[];
private
_index
=
new
Map
<
string
,
number
>
();
private
_clock
:
number
=
0
;
private
_validResources
=
new
Set
<
URI
>
();
private
_invalidResources
=
new
Set
<
URI
>
();
private
_resourceEdits
:
[
number
/*time*/
,
URI
,
URI
][]
=
[];
private
_textEdits
:
[
URI
,
TextEdit
[]][]
=
[];
private
_textEditsIndex
=
new
Map
<
string
,
[
number
/*index*/
,
number
/*time*/
]
>
();
createResource
(
uri
:
URI
,
contents
:
string
):
void
{
if
(
this
.
_invalidResources
.
has
(
uri
))
{
throw
illegalArgument
(
'
Cannot create already deleted resource
'
);
}
this
.
_resourcesCreated
.
push
({
uri
:
uri
,
contents
:
contents
});
this
.
_validResources
.
add
(
uri
);
createResource
(
uri
:
vscode
.
Uri
):
void
{
this
.
renameResource
(
undefined
,
uri
);
}
deleteResource
(
uri
:
URI
):
void
{
if
(
this
.
_validResources
.
has
(
uri
))
{
throw
illegalArgument
(
'
Cannot delete newly created resource
'
);
}
this
.
_resourcesDeleted
.
push
(
uri
);
this
.
_invalidResources
.
add
(
uri
);
deleteResource
(
uri
:
vscode
.
Uri
):
void
{
this
.
renameResource
(
uri
,
undefined
);
}
renameResource
(
uri
:
URI
,
newUri
:
URI
):
void
{
if
(
this
.
_validResources
.
has
(
uri
))
{
throw
illegalArgument
(
'
Cannot delete newly created resource
'
);
}
if
(
this
.
_invalidResources
.
has
(
newUri
))
{
throw
illegalArgument
(
'
Cannot create already deleted resource
'
);
renameResource
(
from
:
vscode
.
Uri
,
to
:
vscode
.
Uri
):
void
{
this
.
_resourceEdits
.
push
([
this
.
_clock
++
,
from
,
to
]);
}
this
.
_resourcesRenamed
.
push
({
from
:
uri
,
to
:
newUri
});
this
.
_invalidResources
.
add
(
uri
);
this
.
_validResources
.
add
(
newUri
);
resourceEdits
():
[
vscode
.
Uri
,
vscode
.
Uri
][]
{
return
this
.
_resourceEdits
.
map
(([,
oldUri
,
newUri
])
=>
(
<
[
vscode
.
Uri
,
vscode
.
Uri
]
>
[
oldUri
,
newUri
])
);
}
replace
(
uri
:
URI
,
range
:
Range
,
newText
:
string
):
void
{
...
...
@@ -550,50 +534,54 @@ export class WorkspaceEdit {
}
has
(
uri
:
URI
):
boolean
{
return
this
.
_
i
ndex
.
has
(
uri
.
toString
());
return
this
.
_
textEditsI
ndex
.
has
(
uri
.
toString
());
}
set
(
uri
:
URI
,
edits
:
TextEdit
[]):
void
{
if
(
this
.
_invalidResources
.
has
(
uri
))
{
throw
illegalArgument
(
'
Cannot modify already deleted resource
'
);
}
this
.
_validResources
.
add
(
uri
);
const
idx
=
this
.
_index
.
get
(
uri
.
toString
());
if
(
typeof
idx
===
'
undefined
'
)
{
let
newLen
=
this
.
_values
.
push
([
uri
,
edits
]);
this
.
_index
.
set
(
uri
.
toString
(),
newLen
-
1
);
if
(
!
this
.
_textEditsIndex
.
has
(
uri
.
toString
()))
{
let
newLen
=
this
.
_textEdits
.
push
([
uri
,
edits
]);
this
.
_textEditsIndex
.
set
(
uri
.
toString
(),
[
newLen
-
1
,
this
.
_clock
++
]);
}
else
{
this
.
_values
[
idx
][
1
]
=
edits
;
const
[
idx
]
=
this
.
_textEditsIndex
.
get
(
uri
.
toString
());
this
.
_textEdits
[
idx
][
1
]
=
edits
;
}
}
get
(
uri
:
URI
):
TextEdit
[]
{
let
idx
=
this
.
_index
.
get
(
uri
.
toString
());
return
typeof
idx
!==
'
undefined
'
&&
this
.
_values
[
idx
][
1
];
}
entries
():
[
URI
,
TextEdit
[]][]
{
return
this
.
_values
;
}
get
createdResources
():
{
uri
:
URI
,
contents
:
string
}[]
{
return
this
.
_resourcesCreated
;
if
(
!
this
.
_textEditsIndex
.
has
(
uri
.
toString
()))
{
return
undefined
;
}
get
deletedResources
():
URI
[]
{
return
this
.
_resourcesDeleted
;
const
[
idx
]
=
this
.
_textEditsIndex
.
get
(
uri
.
toString
());
return
this
.
_textEdits
[
idx
][
1
];
}
get
renamedResources
():
{
from
:
URI
,
to
:
URI
}[]
{
return
this
.
_resourcesRenamed
;
entries
():
[
URI
,
TextEdit
[]][]
{
// todo@joh - make this immutable
return
this
.
_textEdits
;
}
allEntries
():
([
URI
,
TextEdit
[]]
|
[
URI
,
URI
])[]
{
// use the 'time' the we have assigned when inserting
// the operation and use that order in the resulting
// array
const
res
:
([
URI
,
TextEdit
[]]
|
[
URI
,
URI
])[]
=
[];
this
.
_textEditsIndex
.
forEach
(
value
=>
{
const
[
index
,
time
]
=
value
;
res
[
time
]
=
this
.
_textEdits
[
index
];
});
this
.
_resourceEdits
.
forEach
(
value
=>
{
const
[
time
,
oldUri
,
newUri
]
=
value
;
res
[
time
]
=
[
oldUri
,
newUri
];
});
return
res
;
}
get
size
():
number
{
return
this
.
_
values
.
length
+
this
.
_resourcesCreated
.
length
+
this
.
_resourcesRenamed
.
length
+
this
.
_resourcesDeleted
.
length
;
return
this
.
_
textEdits
.
length
+
this
.
_resourceEdits
.
length
;
}
toJSON
():
any
{
return
this
.
_
value
s
;
return
this
.
_
textEdit
s
;
}
}
...
...
src/vs/workbench/parts/search/browser/replaceService.ts
浏览文件 @
dc31fa21
...
...
@@ -15,7 +15,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import
{
IModelService
}
from
'
vs/editor/common/services/modelService
'
;
import
{
IModeService
}
from
'
vs/editor/common/services/modeService
'
;
import
{
Match
,
FileMatch
,
FileMatchOrMatch
,
ISearchWorkbenchService
}
from
'
vs/workbench/parts/search/common/searchModel
'
;
import
{
BulkEdit
,
IResourceEdit
,
createBulkEdit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
BulkEdit
}
from
'
vs/editor/browser/services/bulkEdit
'
;
import
{
IProgressRunner
}
from
'
vs/platform/progress/common/progress
'
;
import
{
IDiffEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
ITextModelService
,
ITextModelContentProvider
}
from
'
vs/editor/common/services/resolverService
'
;
...
...
@@ -24,6 +24,7 @@ import { ScrollType } from 'vs/editor/common/editorCommon';
import
{
ITextModel
}
from
'
vs/editor/common/model
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IFileService
}
from
'
vs/platform/files/common/files
'
;
import
{
ResourceTextEdit
}
from
'
vs/editor/common/modes
'
;
const
REPLACE_PREVIEW
=
'
replacePreview
'
;
...
...
@@ -103,8 +104,7 @@ export class ReplaceService implements IReplaceService {
public
replace
(
match
:
FileMatchOrMatch
,
progress
?:
IProgressRunner
,
resource
?:
URI
):
TPromise
<
any
>
;
public
replace
(
arg
:
any
,
progress
:
IProgressRunner
=
null
,
resource
:
URI
=
null
):
TPromise
<
any
>
{
let
bulkEdit
:
BulkEdit
=
createBulkEdit
(
this
.
textModelResolverService
,
null
,
this
.
fileService
);
bulkEdit
.
progress
(
progress
);
let
bulkEdit
=
new
BulkEdit
(
null
,
progress
,
this
.
textModelResolverService
,
this
.
fileService
);
if
(
arg
instanceof
Match
)
{
let
match
=
<
Match
>
arg
;
...
...
@@ -126,7 +126,7 @@ export class ReplaceService implements IReplaceService {
});
}
return
bulkEdit
.
finish
();
return
bulkEdit
.
perform
();
}
public
openReplacePreview
(
element
:
FileMatchOrMatch
,
preserveFocus
?:
boolean
,
sideBySide
?:
boolean
,
pinned
?:
boolean
):
TPromise
<
any
>
{
...
...
@@ -174,12 +174,14 @@ export class ReplaceService implements IReplaceService {
});
}
private
createEdit
(
match
:
Match
,
text
:
string
,
resource
:
URI
=
null
):
IResource
Edit
{
private
createEdit
(
match
:
Match
,
text
:
string
,
resource
:
URI
=
null
):
ResourceText
Edit
{
let
fileMatch
:
FileMatch
=
match
.
parent
();
let
resourceEdit
:
IResource
Edit
=
{
let
resourceEdit
:
ResourceText
Edit
=
{
resource
:
resource
!==
null
?
resource
:
fileMatch
.
resource
(),
edits
:
[{
range
:
match
.
range
(),
newText
:
text
text
:
text
}]
};
return
resourceEdit
;
}
...
...
src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts
浏览文件 @
dc31fa21
...
...
@@ -10,7 +10,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import
{
ExtHostDocuments
}
from
'
vs/workbench/api/node/extHostDocuments
'
;
import
{
ExtHostDocumentsAndEditors
}
from
'
vs/workbench/api/node/extHostDocumentsAndEditors
'
;
import
{
TextDocumentSaveReason
,
TextEdit
,
Position
,
EndOfLine
}
from
'
vs/workbench/api/node/extHostTypes
'
;
import
{
MainThreadEditorsShape
,
IWorkspaceResourceEdit
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
MainThreadEditorsShape
,
WorkspaceEditDto
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
ExtHostDocumentSaveParticipant
}
from
'
vs/workbench/api/node/extHostDocumentSaveParticipant
'
;
import
{
SingleProxyRPCProtocol
}
from
'
./testRPCProtocol
'
;
import
{
SaveReason
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
...
...
@@ -18,6 +18,7 @@ import * as vscode from 'vscode';
import
{
mock
}
from
'
vs/workbench/test/electron-browser/api/mock
'
;
import
{
IExtensionDescription
}
from
'
vs/platform/extensions/common/extensions
'
;
import
{
NullLogService
}
from
'
vs/platform/log/common/log
'
;
import
{
isResourceTextEdit
,
ResourceTextEdit
}
from
'
vs/editor/common/modes
'
;
suite
(
'
ExtHostDocumentSaveParticipant
'
,
()
=>
{
...
...
@@ -262,10 +263,10 @@ suite('ExtHostDocumentSaveParticipant', () => {
test
(
'
event delivery, pushEdits sync
'
,
()
=>
{
let
edits
:
IWorkspaceResourceEdit
[]
;
let
dto
:
WorkspaceEditDto
;
const
participant
=
new
ExtHostDocumentSaveParticipant
(
nullLogService
,
documents
,
new
class
extends
mock
<
MainThreadEditorsShape
>
()
{
$tryApplyWorkspaceEdit
(
_edits
:
IWorkspaceResourceEdit
[]
)
{
edits
=
_edits
;
$tryApplyWorkspaceEdit
(
_edits
:
WorkspaceEditDto
)
{
dto
=
_edits
;
return
TPromise
.
as
(
true
);
}
});
...
...
@@ -278,16 +279,17 @@ suite('ExtHostDocumentSaveParticipant', () => {
return
participant
.
$participateInSave
(
resource
,
SaveReason
.
EXPLICIT
).
then
(()
=>
{
sub
.
dispose
();
assert
.
equal
(
edits
.
length
,
1
);
assert
.
equal
(
edits
[
0
].
edits
.
length
,
2
);
assert
.
equal
(
dto
.
edits
.
length
,
1
);
assert
.
ok
(
isResourceTextEdit
(
dto
.
edits
[
0
]));
assert
.
equal
((
<
ResourceTextEdit
>
dto
.
edits
[
0
]).
edits
.
length
,
2
);
});
});
test
(
'
event delivery, concurrent change
'
,
()
=>
{
let
edits
:
IWorkspaceResourceEdit
[]
;
let
edits
:
WorkspaceEditDto
;
const
participant
=
new
ExtHostDocumentSaveParticipant
(
nullLogService
,
documents
,
new
class
extends
mock
<
MainThreadEditorsShape
>
()
{
$tryApplyWorkspaceEdit
(
_edits
:
IWorkspaceResourceEdit
[]
)
{
$tryApplyWorkspaceEdit
(
_edits
:
WorkspaceEditDto
)
{
edits
=
_edits
;
return
TPromise
.
as
(
true
);
}
...
...
@@ -321,16 +323,20 @@ suite('ExtHostDocumentSaveParticipant', () => {
test
(
'
event delivery, two listeners -> two document states
'
,
()
=>
{
const
participant
=
new
ExtHostDocumentSaveParticipant
(
nullLogService
,
documents
,
new
class
extends
mock
<
MainThreadEditorsShape
>
()
{
$tryApplyWorkspaceEdit
(
_edits
:
IWorkspaceResourceEdit
[]
)
{
$tryApplyWorkspaceEdit
(
dto
:
WorkspaceEditDto
)
{
for
(
const
{
resource
,
edits
}
of
_edits
)
{
for
(
const
edit
of
dto
.
edits
)
{
if
(
!
isResourceTextEdit
(
edit
))
{
continue
;
}
const
{
resource
,
edits
}
=
edit
;
const
uri
=
URI
.
revive
(
resource
);
for
(
const
{
newT
ext
,
range
}
of
edits
)
{
for
(
const
{
t
ext
,
range
}
of
edits
)
{
documents
.
$acceptModelChanged
(
uri
.
toString
(),
{
changes
:
[{
range
,
text
,
rangeLength
:
undefined
,
text
:
newText
}],
eol
:
undefined
,
versionId
:
documents
.
getDocumentData
(
uri
).
version
+
1
...
...
src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts
浏览文件 @
dc31fa21
...
...
@@ -24,7 +24,7 @@ import { IHeapService } from 'vs/workbench/api/electron-browser/mainThreadHeapSe
import
{
ExtHostDocuments
}
from
'
vs/workbench/api/node/extHostDocuments
'
;
import
{
ExtHostDocumentsAndEditors
}
from
'
vs/workbench/api/node/extHostDocumentsAndEditors
'
;
import
{
getDocumentSymbols
}
from
'
vs/editor/contrib/quickOpen/quickOpen
'
;
import
{
DocumentSymbolProviderRegistry
,
DocumentHighlightKind
,
Hover
}
from
'
vs/editor/common/modes
'
;
import
{
DocumentSymbolProviderRegistry
,
DocumentHighlightKind
,
Hover
,
ResourceTextEdit
}
from
'
vs/editor/common/modes
'
;
import
{
getCodeLensData
}
from
'
vs/editor/contrib/codelens/codelens
'
;
import
{
getDefinitionsAtPosition
,
getImplementationsAtPosition
,
getTypeDefinitionsAtPosition
}
from
'
vs/editor/contrib/goToDeclaration/goToDeclaration
'
;
import
{
getHover
}
from
'
vs/editor/contrib/hover/getHover
'
;
...
...
@@ -812,7 +812,8 @@ suite('ExtHostLanguageFeatures', function () {
return
rpcProtocol
.
sync
().
then
(()
=>
{
return
rename
(
model
,
new
EditorPosition
(
1
,
1
),
'
newName
'
).
then
(
value
=>
{
assert
.
equal
(
value
.
edits
.
length
,
2
);
// least relevant renamer
assert
.
equal
(
value
.
edits
.
length
,
1
);
// least relevant renamer
assert
.
equal
((
<
ResourceTextEdit
[]
>
value
.
edits
)[
0
].
edits
.
length
,
2
);
// least relevant renamer
});
});
});
...
...
src/vs/workbench/test/electron-browser/api/extHostTextEditors.test.ts
浏览文件 @
dc31fa21
...
...
@@ -7,25 +7,26 @@
import
*
as
assert
from
'
assert
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
*
as
extHostTypes
from
'
vs/workbench/api/node/extHostTypes
'
;
import
{
MainContext
,
MainThreadEditorsShape
,
IWorkspaceResourceEdit
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
MainContext
,
MainThreadEditorsShape
,
WorkspaceEditDto
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
mock
}
from
'
vs/workbench/test/electron-browser/api/mock
'
;
import
{
ExtHostDocumentsAndEditors
}
from
'
vs/workbench/api/node/extHostDocumentsAndEditors
'
;
import
{
SingleProxyRPCProtocol
,
TestRPCProtocol
}
from
'
vs/workbench/test/electron-browser/api/testRPCProtocol
'
;
import
{
ExtHostEditors
}
from
'
vs/workbench/api/node/extHostTextEditors
'
;
import
{
ResourceTextEdit
}
from
'
vs/editor/common/modes
'
;
suite
(
'
ExtHostTextEditors.applyWorkspaceEdit
'
,
()
=>
{
const
resource
=
URI
.
parse
(
'
foo:bar
'
);
let
editors
:
ExtHostEditors
;
let
workspaceResourceEdits
:
IWorkspaceResourceEdit
[]
;
let
workspaceResourceEdits
:
WorkspaceEditDto
;
setup
(()
=>
{
workspaceResourceEdits
=
null
;
let
rpcProtocol
=
new
TestRPCProtocol
();
rpcProtocol
.
set
(
MainContext
.
MainThreadEditors
,
new
class
extends
mock
<
MainThreadEditorsShape
>
()
{
$tryApplyWorkspaceEdit
(
_workspaceResourceEdits
:
IWorkspaceResourceEdit
[]
):
TPromise
<
boolean
>
{
$tryApplyWorkspaceEdit
(
_workspaceResourceEdits
:
WorkspaceEditDto
):
TPromise
<
boolean
>
{
workspaceResourceEdits
=
_workspaceResourceEdits
;
return
TPromise
.
as
(
true
);
}
...
...
@@ -48,8 +49,8 @@ suite('ExtHostTextEditors.applyWorkspaceEdit', () => {
let
edit
=
new
extHostTypes
.
WorkspaceEdit
();
edit
.
replace
(
resource
,
new
extHostTypes
.
Range
(
0
,
0
,
0
,
0
),
'
hello
'
);
return
editors
.
applyWorkspaceEdit
(
edit
).
then
((
result
)
=>
{
assert
.
equal
(
workspaceResourceEdits
.
length
,
1
);
assert
.
equal
(
workspaceResourceEdits
[
0
]
.
modelVersionId
,
1337
);
assert
.
equal
(
workspaceResourceEdits
.
edits
.
length
,
1
);
assert
.
equal
(
(
<
ResourceTextEdit
>
workspaceResourceEdits
.
edits
[
0
])
.
modelVersionId
,
1337
);
});
});
...
...
@@ -57,8 +58,8 @@ suite('ExtHostTextEditors.applyWorkspaceEdit', () => {
let
edit
=
new
extHostTypes
.
WorkspaceEdit
();
edit
.
replace
(
URI
.
parse
(
'
foo:bar2
'
),
new
extHostTypes
.
Range
(
0
,
0
,
0
,
0
),
'
hello
'
);
return
editors
.
applyWorkspaceEdit
(
edit
).
then
((
result
)
=>
{
assert
.
equal
(
workspaceResourceEdits
.
length
,
1
);
assert
.
ok
(
typeof
workspaceResourceEdits
[
0
]
.
modelVersionId
===
'
undefined
'
);
assert
.
equal
(
workspaceResourceEdits
.
edits
.
length
,
1
);
assert
.
ok
(
typeof
(
<
ResourceTextEdit
>
workspaceResourceEdits
.
edits
[
0
])
.
modelVersionId
===
'
undefined
'
);
});
});
...
...
src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts
浏览文件 @
dc31fa21
...
...
@@ -362,17 +362,51 @@ suite('ExtHostTypes', function () {
});
test
(
'
WorkspaceEdit should fail when editing deleted resource
'
,
()
=>
{
const
resource
=
URI
.
parse
(
'
file:///a.ts
'
);
// test('WorkspaceEdit should fail when editing deleted resource', () => {
// const resource = URI.parse('file:///a.ts');
// const edit = new types.WorkspaceEdit();
// edit.deleteResource(resource);
// try {
// edit.insert(resource, new types.Position(0, 0), '');
// assert.fail(false, 'Should disallow edit of deleted resource');
// } catch {
// // expected
// }
// });
test
(
'
WorkspaceEdit - keep order of text and file changes
'
,
function
()
{
const
edit
=
new
types
.
WorkspaceEdit
();
edit
.
deleteResource
(
resource
);
try
{
edit
.
insert
(
resource
,
new
types
.
Position
(
0
,
0
),
''
);
assert
.
fail
(
false
,
'
Should disallow edit of deleted resource
'
);
}
catch
{
// expected
edit
.
replace
(
URI
.
parse
(
'
foo:a
'
),
new
types
.
Range
(
1
,
1
,
1
,
1
),
'
foo
'
);
edit
.
renameResource
(
URI
.
parse
(
'
foo:a
'
),
URI
.
parse
(
'
foo:b
'
));
edit
.
replace
(
URI
.
parse
(
'
foo:a
'
),
new
types
.
Range
(
2
,
1
,
2
,
1
),
'
bar
'
);
edit
.
replace
(
URI
.
parse
(
'
foo:b
'
),
new
types
.
Range
(
3
,
1
,
3
,
1
),
'
bazz
'
);
const
all
=
edit
.
allEntries
();
assert
.
equal
(
all
.
length
,
3
);
function
isFileChange
(
thing
:
[
URI
,
types
.
TextEdit
[]]
|
[
URI
,
URI
]):
thing
is
[
URI
,
URI
]
{
const
[
f
,
s
]
=
thing
;
return
URI
.
isUri
(
f
)
&&
URI
.
isUri
(
s
);
}
function
isTextChange
(
thing
:
[
URI
,
types
.
TextEdit
[]]
|
[
URI
,
URI
]):
thing
is
[
URI
,
types
.
TextEdit
[]]
{
const
[
f
,
s
]
=
thing
;
return
URI
.
isUri
(
f
)
&&
Array
.
isArray
(
s
);
}
const
[
first
,
second
,
third
]
=
all
;
assert
.
equal
(
first
[
0
].
toString
(),
'
foo:a
'
);
assert
.
ok
(
!
isFileChange
(
first
));
assert
.
ok
(
isTextChange
(
first
)
&&
first
[
1
].
length
===
2
);
assert
.
equal
(
second
[
0
].
toString
(),
'
foo:a
'
);
assert
.
ok
(
isFileChange
(
second
));
assert
.
equal
(
third
[
0
].
toString
(),
'
foo:b
'
);
assert
.
ok
(
!
isFileChange
(
third
));
assert
.
ok
(
isTextChange
(
third
)
&&
third
[
1
].
length
===
1
);
});
test
(
'
DocumentLink
'
,
function
()
{
...
...
src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts
浏览文件 @
dc31fa21
...
...
@@ -13,7 +13,7 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import
{
TestCodeEditorService
}
from
'
vs/editor/test/browser/testCodeEditorService
'
;
import
{
ITextFileService
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
IWorkbenchEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
ExtHostDocumentsAndEditorsShape
,
IWorkspaceResourceEdit
,
ExtHostContext
,
ExtHostDocumentsShape
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
ExtHostDocumentsAndEditorsShape
,
ExtHostContext
,
ExtHostDocumentsShape
}
from
'
vs/workbench/api/node/extHost.protocol
'
;
import
{
mock
}
from
'
vs/workbench/test/electron-browser/api/mock
'
;
import
{
IEditorGroupService
}
from
'
vs/workbench/services/group/common/groupService
'
;
import
Event
from
'
vs/base/common/event
'
;
...
...
@@ -26,6 +26,7 @@ import { EditOperation } from 'vs/editor/common/core/editOperation';
import
{
TestFileService
}
from
'
vs/workbench/test/workbenchTestServices
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IFileStat
}
from
'
vs/platform/files/common/files
'
;
import
{
ResourceTextEdit
}
from
'
vs/editor/common/modes
'
;
suite
(
'
MainThreadEditors
'
,
()
=>
{
...
...
@@ -35,7 +36,7 @@ suite('MainThreadEditors', () => {
let
editors
:
MainThreadEditors
;
const
movedResources
=
new
Map
<
URI
,
URI
>
();
const
createdResources
=
new
Map
<
URI
,
string
>
();
const
createdResources
=
new
Set
<
URI
>
();
const
deletedResources
=
new
Set
<
URI
>
();
setup
(()
=>
{
...
...
@@ -46,23 +47,22 @@ suite('MainThreadEditors', () => {
movedResources
.
clear
();
createdResources
.
clear
();
deletedResources
.
clear
();
const
fileService
=
new
TestFileService
();
fileService
.
moveFile
=
async
(
from
,
target
):
TPromise
<
IFileStat
>
=>
{
as
sert
(
!
movedResources
.
has
(
from
));
const
fileService
=
new
class
extends
TestFileService
{
as
ync
moveFile
(
from
,
target
):
TPromise
<
IFileStat
>
{
movedResources
.
set
(
from
,
target
);
return
createMockFileStat
(
target
);
};
fileService
.
createFile
=
async
(
uri
,
contents
):
TPromise
<
IFileStat
>
=>
{
assert
(
!
createdResources
.
has
(
uri
));
createdResources
.
set
(
uri
,
contents
);
}
async
createFile
(
uri
):
TPromise
<
IFileStat
>
{
createdResources
.
add
(
uri
);
return
createMockFileStat
(
uri
);
};
fileService
.
del
=
async
(
uri
):
TPromise
<
void
>
=>
{
assert
(
!
deletedResources
.
has
(
uri
));
}
async
del
(
uri
):
TPromise
<
any
>
{
deletedResources
.
add
(
uri
);
}
};
const
textFileService
=
new
class
extends
mock
<
ITextFileService
>
()
{
isDirty
()
{
return
false
;
}
models
=
<
any
>
{
...
...
@@ -119,11 +119,11 @@ suite('MainThreadEditors', () => {
let
model
=
modelService
.
createModel
(
'
something
'
,
null
,
resource
);
let
workspaceResourceEdit
:
IWorkspaceResource
Edit
=
{
let
workspaceResourceEdit
:
ResourceText
Edit
=
{
resource
:
resource
,
modelVersionId
:
model
.
getVersionId
(),
edits
:
[{
newT
ext
:
'
asdfg
'
,
t
ext
:
'
asdfg
'
,
range
:
new
Range
(
1
,
1
,
1
,
1
)
}]
};
...
...
@@ -131,28 +131,22 @@ suite('MainThreadEditors', () => {
// Act as if the user edited the model
model
.
applyEdits
([
EditOperation
.
insert
(
new
Position
(
0
,
0
),
'
something
'
)]);
return
editors
.
$tryApplyWorkspaceEdit
(
[
workspaceResourceEdit
]
).
then
((
result
)
=>
{
return
editors
.
$tryApplyWorkspaceEdit
(
{
edits
:
[
workspaceResourceEdit
]
}
).
then
((
result
)
=>
{
assert
.
equal
(
result
,
false
);
});
});
test
(
`applyWorkspaceEdit with only resource edit`
,
()
=>
{
let
model
=
modelService
.
createModel
(
'
something
'
,
null
,
resource
);
let
workspaceResourceEdit
:
IWorkspaceResourceEdit
=
{
resource
:
resource
,
modelVersionId
:
model
.
getVersionId
(),
edits
:
[]
};
return
editors
.
$tryApplyWorkspaceEdit
([
workspaceResourceEdit
],
{
renamedResources
:
[{
from
:
resource
,
to
:
resource
}],
createdResources
:
[{
uri
:
resource
,
contents
:
'
foo
'
}],
deletedResources
:
[
resource
]
return
editors
.
$tryApplyWorkspaceEdit
({
edits
:
[
{
oldUri
:
resource
,
newUri
:
resource
},
{
oldUri
:
undefined
,
newUri
:
resource
},
{
oldUri
:
resource
,
newUri
:
undefined
}
]
}).
then
((
result
)
=>
{
assert
.
equal
(
result
,
true
);
assert
.
equal
(
movedResources
.
get
(
resource
),
resource
);
assert
.
equal
(
createdResources
.
get
(
resource
),
'
foo
'
);
assert
.
equal
(
createdResources
.
has
(
resource
),
true
);
assert
.
equal
(
deletedResources
.
has
(
resource
),
true
);
});
});
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录