Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
1fd95d53
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,发现更多精彩内容 >>
未验证
提交
1fd95d53
编写于
11月 04, 2019
作者:
J
Johannes Rieken
提交者:
GitHub
11月 04, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #83822 from microsoft/joh/willRename
Propose API for [onWill|onDid][Create|Delete|Rename]
上级
ec7e8633
073735c5
变更
11
显示空白变更内容
内联
并排
Showing
11 changed file
with
278 addition
and
100 deletion
+278
-100
extensions/typescript-language-features/src/features/updatePathsOnRename.ts
...ipt-language-features/src/features/updatePathsOnRename.ts
+2
-1
src/vs/base/common/event.ts
src/vs/base/common/event.ts
+1
-1
src/vs/base/test/common/event.test.ts
src/vs/base/test/common/event.test.ts
+36
-0
src/vs/platform/files/test/node/diskFileService.test.ts
src/vs/platform/files/test/node/diskFileService.test.ts
+1
-0
src/vs/vscode.proposed.d.ts
src/vs/vscode.proposed.d.ts
+31
-6
src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts
...workbench/api/browser/mainThreadFileSystemEventService.ts
+32
-16
src/vs/workbench/api/common/extHost.api.impl.ts
src/vs/workbench/api/common/extHost.api.impl.ts
+18
-2
src/vs/workbench/api/common/extHost.protocol.ts
src/vs/workbench/api/common/extHost.protocol.ts
+3
-2
src/vs/workbench/api/common/extHostFileSystemEventService.ts
src/vs/workbench/api/common/extHostFileSystemEventService.ts
+86
-33
src/vs/workbench/services/textfile/browser/textFileService.ts
...vs/workbench/services/textfile/browser/textFileService.ts
+27
-28
src/vs/workbench/services/textfile/common/textfiles.ts
src/vs/workbench/services/textfile/common/textfiles.ts
+41
-11
未找到文件。
extensions/typescript-language-features/src/features/updatePathsOnRename.ts
浏览文件 @
1fd95d53
...
...
@@ -57,7 +57,8 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
)
{
super
();
this
.
_register
(
vscode
.
workspace
.
onDidRenameFile
(
async
({
newUri
,
oldUri
})
=>
{
this
.
_register
(
vscode
.
workspace
.
onDidRenameFiles
(
async
(
e
)
=>
{
const
[{
newUri
,
oldUri
}]
=
e
.
renamed
;
const
newFilePath
=
this
.
client
.
toPath
(
newUri
);
if
(
!
newFilePath
)
{
return
;
...
...
src/vs/base/common/event.ts
浏览文件 @
1fd95d53
...
...
@@ -688,7 +688,7 @@ export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
// freeze thenables-collection to enforce sync-calls to
// wait until and then wait for all thenables to resolve
Object
.
freeze
(
thenables
);
await
Promise
.
all
(
thenables
);
await
Promise
.
all
(
thenables
)
.
catch
(
e
=>
onUnexpectedError
(
e
))
;
}
}
}
...
...
src/vs/base/test/common/event.test.ts
浏览文件 @
1fd95d53
...
...
@@ -350,6 +350,42 @@ suite('AsyncEmitter', function () {
}));
assert
.
ok
(
done
);
});
test
(
'
catch errors
'
,
async
function
()
{
const
origErrorHandler
=
Errors
.
errorHandler
.
getUnexpectedErrorHandler
();
Errors
.
setUnexpectedErrorHandler
(()
=>
null
);
interface
E
extends
IWaitUntil
{
foo
:
boolean
;
}
let
globalState
=
0
;
let
emitter
=
new
AsyncEmitter
<
E
>
();
emitter
.
event
(
e
=>
{
globalState
+=
1
;
e
.
waitUntil
(
new
Promise
((
_r
,
reject
)
=>
reject
(
new
Error
())));
});
emitter
.
event
(
e
=>
{
globalState
+=
1
;
e
.
waitUntil
(
timeout
(
10
));
});
await
emitter
.
fireAsync
(
thenables
=>
({
foo
:
true
,
waitUntil
(
t
)
{
thenables
.
push
(
t
);
}
})).
then
(()
=>
{
assert
.
equal
(
globalState
,
2
);
}).
catch
(
e
=>
{
console
.
log
(
e
);
assert
.
ok
(
false
);
});
Errors
.
setUnexpectedErrorHandler
(
origErrorHandler
);
});
});
suite
(
'
PausableEmitter
'
,
function
()
{
...
...
src/vs/platform/files/test/node/diskFileService.test.ts
浏览文件 @
1fd95d53
...
...
@@ -428,6 +428,7 @@ suite('Disk File Service', function () {
await
service
.
del
(
source
.
resource
);
assert
.
equal
(
existsSync
(
source
.
resource
.
fsPath
),
false
);
assert
.
ok
(
event
!
);
assert
.
equal
(
event
!
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
!
.
operation
,
FileOperation
.
DELETE
);
...
...
src/vs/vscode.proposed.d.ts
浏览文件 @
1fd95d53
...
...
@@ -708,20 +708,45 @@ declare module 'vscode' {
//#endregion
//#region mjbvz,joh: https://github.com/Microsoft/vscode/issues/43768
export
interface
FileCreateEvent
{
readonly
created
:
ReadonlyArray
<
Uri
>
;
}
export
interface
FileWillCreateEvent
{
readonly
creating
:
ReadonlyArray
<
Uri
>
;
waitUntil
(
thenable
:
Thenable
<
any
>
):
void
;
}
export
interface
FileDeleteEvent
{
readonly
deleted
:
ReadonlyArray
<
Uri
>
;
}
export
interface
FileWillDeleteEvent
{
readonly
deleting
:
ReadonlyArray
<
Uri
>
;
waitUntil
(
thenable
:
Thenable
<
any
>
):
void
;
}
export
interface
FileRenameEvent
{
readonly
oldUri
:
Uri
;
readonly
newUri
:
Uri
;
readonly
renamed
:
ReadonlyArray
<
{
oldUri
:
Uri
,
newUri
:
Uri
}
>
;
}
export
interface
FileWillRenameEvent
{
readonly
oldUri
:
Uri
;
readonly
newUri
:
Uri
;
readonly
renaming
:
ReadonlyArray
<
{
oldUri
:
Uri
,
newUri
:
Uri
}
>
;
waitUntil
(
thenable
:
Thenable
<
WorkspaceEdit
>
):
void
;
}
export
namespace
workspace
{
export
const
onWillRenameFile
:
Event
<
FileWillRenameEvent
>
;
export
const
onDidRenameFile
:
Event
<
FileRenameEvent
>
;
export
const
onWillCreateFiles
:
Event
<
FileWillCreateEvent
>
;
export
const
onDidCreateFiles
:
Event
<
FileCreateEvent
>
;
export
const
onWillDeleteFiles
:
Event
<
FileWillDeleteEvent
>
;
export
const
onDidDeleteFiles
:
Event
<
FileDeleteEvent
>
;
export
const
onWillRenameFiles
:
Event
<
FileWillRenameEvent
>
;
export
const
onDidRenameFiles
:
Event
<
FileRenameEvent
>
;
}
//#endregion
...
...
src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts
浏览文件 @
1fd95d53
...
...
@@ -3,21 +3,24 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
IDisposable
,
dispos
e
}
from
'
vs/base/common/lifecycle
'
;
import
{
DisposableStor
e
}
from
'
vs/base/common/lifecycle
'
;
import
{
FileChangeType
,
IFileService
,
FileOperation
}
from
'
vs/platform/files/common/files
'
;
import
{
extHostCustomer
}
from
'
vs/workbench/api/common/extHostCustomers
'
;
import
{
ExtHostContext
,
FileSystemEvents
,
IExtHostContext
}
from
'
../common/extHost.protocol
'
;
import
{
ITextFileService
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
IProgressService
,
ProgressLocation
}
from
'
vs/platform/progress/common/progress
'
;
import
{
localize
}
from
'
vs/nls
'
;
@
extHostCustomer
export
class
MainThreadFileSystemEventService
{
private
readonly
_listener
=
new
Array
<
IDisposable
>
();
private
readonly
_listener
=
new
DisposableStore
();
constructor
(
extHostContext
:
IExtHostContext
,
@
IFileService
fileService
:
IFileService
,
@
ITextFileService
textfileService
:
ITextFileService
,
@
ITextFileService
textFileService
:
ITextFileService
,
@
IProgressService
progressService
:
IProgressService
)
{
const
proxy
=
extHostContext
.
getProxy
(
ExtHostContext
.
ExtHostFileSystemEventService
);
...
...
@@ -28,7 +31,7 @@ export class MainThreadFileSystemEventService {
changed
:
[],
deleted
:
[]
};
fileService
.
onFileChanges
(
event
=>
{
this
.
_listener
.
add
(
fileService
.
onFileChanges
(
event
=>
{
for
(
let
change
of
event
.
changes
)
{
switch
(
change
.
type
)
{
case
FileChangeType
.
ADDED
:
...
...
@@ -47,22 +50,35 @@ export class MainThreadFileSystemEventService {
events
.
created
.
length
=
0
;
events
.
changed
.
length
=
0
;
events
.
deleted
.
length
=
0
;
}
,
undefined
,
this
.
_listener
);
}
)
);
// file operation events - (changes the editor makes)
fileService
.
onAfterOperation
(
e
=>
{
if
(
e
.
isOperation
(
FileOperation
.
MOVE
))
{
proxy
.
$onFileRename
(
e
.
resource
,
e
.
target
.
resource
);
}
},
undefined
,
this
.
_listener
);
textfileService
.
onWillMove
(
e
=>
{
const
promise
=
proxy
.
$onWillRename
(
e
.
oldResource
,
e
.
newResource
);
e
.
waitUntil
(
promise
);
},
undefined
,
this
.
_listener
);
// BEFORE file operation
const
messages
=
new
Map
<
FileOperation
,
string
>
();
messages
.
set
(
FileOperation
.
CREATE
,
localize
(
'
msg-create
'
,
"
Running 'File Create' participants...
"
));
messages
.
set
(
FileOperation
.
DELETE
,
localize
(
'
msg-delete
'
,
"
Running 'File Delete' participants...
"
));
messages
.
set
(
FileOperation
.
MOVE
,
localize
(
'
msg-rename
'
,
"
Running 'File Rename' participants...
"
));
this
.
_listener
.
add
(
textFileService
.
onWillRunOperation
(
e
=>
{
const
p
=
progressService
.
withProgress
({
location
:
ProgressLocation
.
Window
},
progress
=>
{
progress
.
report
({
message
:
messages
.
get
(
e
.
operation
)
});
const
p1
=
proxy
.
$onWillRunFileOperation
(
e
.
operation
,
e
.
target
,
e
.
source
);
const
p2
=
new
Promise
((
_resolve
,
reject
)
=>
{
setTimeout
(()
=>
reject
(
new
Error
(
'
timeout
'
)),
5000
);
});
return
Promise
.
race
([
p1
,
p2
]);
});
e
.
waitUntil
(
p
);
}));
// AFTER file operation
this
.
_listener
.
add
(
textFileService
.
onDidRunOperation
(
e
=>
proxy
.
$onDidRunFileOperation
(
e
.
operation
,
e
.
target
,
e
.
source
)));
}
dispose
():
void
{
dispose
(
this
.
_listener
);
this
.
_listener
.
dispose
(
);
}
}
src/vs/workbench/api/common/extHost.api.impl.ts
浏览文件 @
1fd95d53
...
...
@@ -695,11 +695,27 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled
(
extension
);
return
extHostLabelService
.
$registerResourceLabelFormatter
(
formatter
);
},
onDidRenameFile
:
(
listener
:
(
e
:
vscode
.
FileRenameEvent
)
=>
any
,
thisArg
?:
any
,
disposables
?:
vscode
.
Disposable
[])
=>
{
onDidCreateFiles
:
(
listener
,
thisArg
,
disposables
)
=>
{
checkProposedApiEnabled
(
extension
);
return
extHostFileSystemEvent
.
onDidCreateFile
(
listener
,
thisArg
,
disposables
);
},
onDidDeleteFiles
:
(
listener
,
thisArg
,
disposables
)
=>
{
checkProposedApiEnabled
(
extension
);
return
extHostFileSystemEvent
.
onDidDeleteFile
(
listener
,
thisArg
,
disposables
);
},
onDidRenameFiles
:
(
listener
,
thisArg
,
disposables
)
=>
{
checkProposedApiEnabled
(
extension
);
return
extHostFileSystemEvent
.
onDidRenameFile
(
listener
,
thisArg
,
disposables
);
},
onWillRenameFile
:
(
listener
:
(
e
:
vscode
.
FileWillRenameEvent
)
=>
any
,
thisArg
?:
any
,
disposables
?:
vscode
.
Disposable
[])
=>
{
onWillCreateFiles
:
(
listener
:
(
e
:
vscode
.
FileWillCreateEvent
)
=>
any
,
thisArg
?:
any
,
disposables
?:
vscode
.
Disposable
[])
=>
{
checkProposedApiEnabled
(
extension
);
return
extHostFileSystemEvent
.
getOnWillCreateFileEvent
(
extension
)(
listener
,
thisArg
,
disposables
);
},
onWillDeleteFiles
:
(
listener
:
(
e
:
vscode
.
FileWillDeleteEvent
)
=>
any
,
thisArg
?:
any
,
disposables
?:
vscode
.
Disposable
[])
=>
{
checkProposedApiEnabled
(
extension
);
return
extHostFileSystemEvent
.
getOnWillDeleteFileEvent
(
extension
)(
listener
,
thisArg
,
disposables
);
},
onWillRenameFiles
:
(
listener
:
(
e
:
vscode
.
FileWillRenameEvent
)
=>
any
,
thisArg
?:
any
,
disposables
?:
vscode
.
Disposable
[])
=>
{
checkProposedApiEnabled
(
extension
);
return
extHostFileSystemEvent
.
getOnWillRenameFileEvent
(
extension
)(
listener
,
thisArg
,
disposables
);
}
...
...
src/vs/workbench/api/common/extHost.protocol.ts
浏览文件 @
1fd95d53
...
...
@@ -914,10 +914,11 @@ export interface FileSystemEvents {
changed
:
UriComponents
[];
deleted
:
UriComponents
[];
}
export
interface
ExtHostFileSystemEventServiceShape
{
$onFileEvent
(
events
:
FileSystemEvents
):
void
;
$on
FileRename
(
oldUri
:
UriComponents
,
newUri
:
UriComponents
):
void
;
$on
WillRename
(
oldUri
:
UriComponents
,
newUri
:
UriComponents
):
Promise
<
any
>
;
$on
WillRunFileOperation
(
operation
:
files
.
FileOperation
,
target
:
UriComponents
,
source
:
UriComponents
|
undefined
):
Promise
<
any
>
;
$on
DidRunFileOperation
(
operation
:
files
.
FileOperation
,
target
:
UriComponents
,
source
:
UriComponents
|
undefined
):
void
;
}
export
interface
ObjectIdentifier
{
...
...
src/vs/workbench/api/common/extHostFileSystemEventService.ts
浏览文件 @
1fd95d53
...
...
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import
{
flatten
}
from
'
vs/base/common/arrays
'
;
import
{
AsyncEmitter
,
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
AsyncEmitter
,
Emitter
,
Event
,
IWaitUntil
}
from
'
vs/base/common/event
'
;
import
{
IRelativePattern
,
parse
}
from
'
vs/base/common/glob
'
;
import
{
URI
,
UriComponents
}
from
'
vs/base/common/uri
'
;
import
{
ExtHostDocumentsAndEditors
}
from
'
vs/workbench/api/common/extHostDocumentsAndEditors
'
;
...
...
@@ -13,6 +13,7 @@ import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, Mai
import
*
as
typeConverter
from
'
./extHostTypeConverters
'
;
import
{
Disposable
,
WorkspaceEdit
}
from
'
./extHostTypes
'
;
import
{
IExtensionDescription
}
from
'
vs/platform/extensions/common/extensions
'
;
import
{
FileOperation
}
from
'
vs/platform/files/common/files
'
;
class
FileSystemWatcher
implements
vscode
.
FileSystemWatcher
{
...
...
@@ -96,18 +97,26 @@ class FileSystemWatcher implements vscode.FileSystemWatcher {
}
}
interface
WillRenameListener
{
interface
IExtensionListener
<
E
>
{
extension
:
IExtensionDescription
;
(
e
:
vscode
.
FileWillRenameEvent
):
any
;
(
e
:
E
):
any
;
}
export
class
ExtHostFileSystemEventService
implements
ExtHostFileSystemEventServiceShape
{
private
readonly
_onFileEvent
=
new
Emitter
<
FileSystemEvents
>
();
private
readonly
_onFileSystemEvent
=
new
Emitter
<
FileSystemEvents
>
();
private
readonly
_onDidRenameFile
=
new
Emitter
<
vscode
.
FileRenameEvent
>
();
private
readonly
_onDidCreateFile
=
new
Emitter
<
vscode
.
FileCreateEvent
>
();
private
readonly
_onDidDeleteFile
=
new
Emitter
<
vscode
.
FileDeleteEvent
>
();
private
readonly
_onWillRenameFile
=
new
AsyncEmitter
<
vscode
.
FileWillRenameEvent
>
();
private
readonly
_onWillCreateFile
=
new
AsyncEmitter
<
vscode
.
FileWillCreateEvent
>
();
private
readonly
_onWillDeleteFile
=
new
AsyncEmitter
<
vscode
.
FileWillDeleteEvent
>
();
readonly
onDidRenameFile
:
Event
<
vscode
.
FileRenameEvent
>
=
this
.
_onDidRenameFile
.
event
;
readonly
onDidCreateFile
:
Event
<
vscode
.
FileCreateEvent
>
=
this
.
_onDidCreateFile
.
event
;
readonly
onDidDeleteFile
:
Event
<
vscode
.
FileDeleteEvent
>
=
this
.
_onDidDeleteFile
.
event
;
constructor
(
mainContext
:
IMainContext
,
...
...
@@ -117,37 +126,78 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
//
}
public
createFileSystemWatcher
(
globPattern
:
string
|
IRelativePattern
,
ignoreCreateEvents
?:
boolean
,
ignoreChangeEvents
?:
boolean
,
ignoreDeleteEvents
?:
boolean
):
vscode
.
FileSystemWatcher
{
return
new
FileSystemWatcher
(
this
.
_onFileEvent
.
event
,
globPattern
,
ignoreCreateEvents
,
ignoreChangeEvents
,
ignoreDeleteEvents
);
//--- file events
createFileSystemWatcher
(
globPattern
:
string
|
IRelativePattern
,
ignoreCreateEvents
?:
boolean
,
ignoreChangeEvents
?:
boolean
,
ignoreDeleteEvents
?:
boolean
):
vscode
.
FileSystemWatcher
{
return
new
FileSystemWatcher
(
this
.
_onFileSystemEvent
.
event
,
globPattern
,
ignoreCreateEvents
,
ignoreChangeEvents
,
ignoreDeleteEvents
);
}
$onFileEvent
(
events
:
FileSystemEvents
)
{
this
.
_onFileEvent
.
fire
(
events
);
this
.
_onFile
System
Event
.
fire
(
events
);
}
$onFileRename
(
oldUri
:
UriComponents
,
newUri
:
UriComponents
)
{
this
.
_onDidRenameFile
.
fire
(
Object
.
freeze
({
oldUri
:
URI
.
revive
(
oldUri
),
newUri
:
URI
.
revive
(
newUri
)
}));
//--- file operations
$onDidRunFileOperation
(
operation
:
FileOperation
,
target
:
UriComponents
,
source
:
UriComponents
|
undefined
):
void
{
switch
(
operation
)
{
case
FileOperation
.
MOVE
:
this
.
_onDidRenameFile
.
fire
(
Object
.
freeze
({
renamed
:
[{
oldUri
:
URI
.
revive
(
target
),
newUri
:
URI
.
revive
(
source
!
)
}]
}));
break
;
case
FileOperation
.
DELETE
:
this
.
_onDidDeleteFile
.
fire
(
Object
.
freeze
({
deleted
:
[
URI
.
revive
(
target
)]
}));
break
;
case
FileOperation
.
CREATE
:
this
.
_onDidCreateFile
.
fire
(
Object
.
freeze
({
created
:
[
URI
.
revive
(
target
)]
}));
break
;
default
:
//ignore, dont send
}
}
getOnWillRenameFileEvent
(
extension
:
IExtensionDescription
):
Event
<
vscode
.
FileWillRenameEvent
>
{
return
this
.
_createWillExecuteEvent
(
extension
,
this
.
_onWillRenameFile
);
}
getOnWillCreateFileEvent
(
extension
:
IExtensionDescription
):
Event
<
vscode
.
FileWillCreateEvent
>
{
return
this
.
_createWillExecuteEvent
(
extension
,
this
.
_onWillCreateFile
);
}
getOnWillDeleteFileEvent
(
extension
:
IExtensionDescription
):
Event
<
vscode
.
FileWillDeleteEvent
>
{
return
this
.
_createWillExecuteEvent
(
extension
,
this
.
_onWillDeleteFile
);
}
private
_createWillExecuteEvent
<
E
extends
IWaitUntil
>
(
extension
:
IExtensionDescription
,
emitter
:
AsyncEmitter
<
E
>
):
Event
<
E
>
{
return
(
listener
,
thisArg
,
disposables
)
=>
{
const
wrappedListener
:
WillRenameListener
=
<
any
>
((
e
:
vscode
.
FileWillRenameEvent
)
=>
{
listener
.
call
(
thisArg
,
e
);
});
const
wrappedListener
:
IExtensionListener
<
E
>
=
function
wrapped
(
e
:
E
)
{
listener
.
call
(
thisArg
,
e
);
};
wrappedListener
.
extension
=
extension
;
return
this
.
_onWillRenameFile
.
event
(
wrappedListener
,
undefined
,
disposables
);
return
emitter
.
event
(
wrappedListener
,
undefined
,
disposables
);
};
}
$onWillRename
(
oldUriDto
:
UriComponents
,
newUriDto
:
UriComponents
):
Promise
<
any
>
{
const
oldUri
=
URI
.
revive
(
oldUriDto
);
const
newUri
=
URI
.
revive
(
newUriDto
);
async
$onWillRunFileOperation
(
operation
:
FileOperation
,
target
:
UriComponents
,
source
:
UriComponents
|
undefined
):
Promise
<
any
>
{
switch
(
operation
)
{
case
FileOperation
.
MOVE
:
await
this
.
_fireWillRename
(
URI
.
revive
(
target
),
URI
.
revive
(
source
!
));
break
;
case
FileOperation
.
DELETE
:
this
.
_onWillDeleteFile
.
fireAsync
(
thenables
=>
(
<
vscode
.
FileWillDeleteEvent
>
{
deleting
:
[
URI
.
revive
(
target
)],
waitUntil
:
p
=>
thenables
.
push
(
Promise
.
resolve
(
p
))
}));
break
;
case
FileOperation
.
CREATE
:
this
.
_onWillCreateFile
.
fireAsync
(
thenables
=>
(
<
vscode
.
FileWillCreateEvent
>
{
creating
:
[
URI
.
revive
(
target
)],
waitUntil
:
p
=>
thenables
.
push
(
Promise
.
resolve
(
p
))
}));
break
;
default
:
//ignore, dont send
}
}
private
async
_fireWillRename
(
oldUri
:
URI
,
newUri
:
URI
):
Promise
<
any
>
{
const
edits
:
WorkspaceEdit
[]
=
[];
return
Promise
.
resolve
(
this
.
_onWillRenameFile
.
fireAsync
((
bucket
,
_listener
)
=>
{
await
Promise
.
resolve
(
this
.
_onWillRenameFile
.
fireAsync
(
bucket
=>
{
return
{
oldUri
,
newUri
,
renaming
:
[{
oldUri
,
newUri
}],
waitUntil
:
(
thenable
:
Promise
<
vscode
.
WorkspaceEdit
>
):
void
=>
{
if
(
Object
.
isFrozen
(
bucket
))
{
throw
new
TypeError
(
'
waitUntil cannot be called async
'
);
...
...
@@ -163,10 +213,12 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
bucket
.
push
(
wrappedThenable
);
}
};
}).
then
(():
any
=>
{
}));
if
(
edits
.
length
===
0
)
{
return
undefined
;
}
// flatten all WorkspaceEdits collected via waitUntil-call
// and apply them in one go.
const
allEdits
=
new
Array
<
Array
<
IResourceFileEditDto
|
IResourceTextEditDto
>>
();
...
...
@@ -177,6 +229,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
}
}
return
this
.
_mainThreadTextEditors
.
$tryApplyWorkspaceEdit
({
edits
:
flatten
(
allEdits
)
});
}));
}
}
src/vs/workbench/services/textfile/browser/textFileService.ts
浏览文件 @
1fd95d53
...
...
@@ -5,16 +5,15 @@
import
*
as
nls
from
'
vs/nls
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
*
as
errors
from
'
vs/base/common/errors
'
;
import
*
as
objects
from
'
vs/base/common/objects
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Event
,
Emitter
,
AsyncEmitter
}
from
'
vs/base/common/event
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
{
IBackupFileService
}
from
'
vs/workbench/services/backup/common/backup
'
;
import
{
IResult
,
ITextFileOperationResult
,
ITextFileService
,
ITextFileStreamContent
,
IAutoSaveConfiguration
,
AutoSaveMode
,
SaveReason
,
ITextFileEditorModelManager
,
ITextFileEditorModel
,
ModelState
,
ISaveOptions
,
AutoSaveContext
,
I
WillMoveEvent
,
ITextFileContent
,
IResourceEncodings
,
IReadTextFileOptions
,
IWriteTextFileOptions
,
toBufferOrReadable
,
TextFileOperationError
,
TextFileOperationResul
t
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
IResult
,
ITextFileOperationResult
,
ITextFileService
,
ITextFileStreamContent
,
IAutoSaveConfiguration
,
AutoSaveMode
,
SaveReason
,
ITextFileEditorModelManager
,
ITextFileEditorModel
,
ModelState
,
ISaveOptions
,
AutoSaveContext
,
I
TextFileContent
,
IResourceEncodings
,
IReadTextFileOptions
,
IWriteTextFileOptions
,
toBufferOrReadable
,
TextFileOperationError
,
TextFileOperationResult
,
FileOperationWillRunEvent
,
FileOperationDidRunEven
t
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
ConfirmResult
,
IRevertOptions
}
from
'
vs/workbench/common/editor
'
;
import
{
ILifecycleService
,
ShutdownReason
,
LifecyclePhase
}
from
'
vs/platform/lifecycle/common/lifecycle
'
;
import
{
IWorkspaceContextService
,
WorkbenchState
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
IFileService
,
IFilesConfiguration
,
FileOperationError
,
FileOperationResult
,
AutoSaveConfiguration
,
HotExitConfiguration
,
IFileStatWithMetadata
,
ICreateFileOptions
}
from
'
vs/platform/files/common/files
'
;
import
{
IFileService
,
IFilesConfiguration
,
FileOperationError
,
FileOperationResult
,
AutoSaveConfiguration
,
HotExitConfiguration
,
IFileStatWithMetadata
,
ICreateFileOptions
,
FileOperation
}
from
'
vs/platform/files/common/files
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IWorkbenchEnvironmentService
}
from
'
vs/workbench/services/environment/common/environmentService
'
;
...
...
@@ -53,8 +52,13 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
private
readonly
_onFilesAssociationChange
:
Emitter
<
void
>
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onFilesAssociationChange
:
Event
<
void
>
=
this
.
_onFilesAssociationChange
.
event
;
private
readonly
_onWillMove
=
this
.
_register
(
new
Emitter
<
IWillMoveEvent
>
());
readonly
onWillMove
:
Event
<
IWillMoveEvent
>
=
this
.
_onWillMove
.
event
;
private
_onWillRunOperation
=
this
.
_register
(
new
AsyncEmitter
<
FileOperationWillRunEvent
>
());
readonly
onWillRunOperation
=
this
.
_onWillRunOperation
.
event
;
private
_onDidRunOperation
=
this
.
_register
(
new
Emitter
<
FileOperationDidRunEvent
>
());
readonly
onDidRunOperation
=
this
.
_onDidRunOperation
.
event
;
private
_models
:
TextFileEditorModelManager
;
get
models
():
ITextFileEditorModelManager
{
return
this
.
_models
;
}
...
...
@@ -409,6 +413,10 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
}
async
create
(
resource
:
URI
,
value
?:
string
|
ITextSnapshot
,
options
?:
ICreateFileOptions
):
Promise
<
IFileStatWithMetadata
>
{
// before event
await
this
.
_onWillRunOperation
.
fireAsync
(
promises
=>
new
FileOperationWillRunEvent
(
promises
,
FileOperation
.
CREATE
,
resource
));
const
stat
=
await
this
.
doCreate
(
resource
,
value
,
options
);
// If we had an existing model for the given resource, load
...
...
@@ -420,6 +428,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
await
existingModel
.
revert
();
}
// after event
this
.
_onDidRunOperation
.
fire
(
new
FileOperationDidRunEvent
(
FileOperation
.
CREATE
,
resource
));
return
stat
;
}
...
...
@@ -432,17 +443,20 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
}
async
delete
(
resource
:
URI
,
options
?:
{
useTrash
?:
boolean
,
recursive
?:
boolean
}):
Promise
<
void
>
{
const
dirtyFiles
=
this
.
getDirty
().
filter
(
dirty
=>
isEqualOrParent
(
dirty
,
resource
));
await
this
.
_onWillRunOperation
.
fireAsync
(
promises
=>
new
FileOperationWillRunEvent
(
promises
,
FileOperation
.
DELETE
,
resource
));
const
dirtyFiles
=
this
.
getDirty
().
filter
(
dirty
=>
isEqualOrParent
(
dirty
,
resource
));
await
this
.
revertAll
(
dirtyFiles
,
{
soft
:
true
});
return
this
.
fileService
.
del
(
resource
,
options
);
await
this
.
fileService
.
del
(
resource
,
options
);
this
.
_onDidRunOperation
.
fire
(
new
FileOperationDidRunEvent
(
FileOperation
.
DELETE
,
resource
));
}
async
move
(
source
:
URI
,
target
:
URI
,
overwrite
?:
boolean
):
Promise
<
IFileStatWithMetadata
>
{
//
await onWillMove event joiner
s
await
this
.
notifyOnWillMove
(
source
,
target
);
//
before event
s
await
this
.
_onWillRunOperation
.
fireAsync
(
promises
=>
new
FileOperationWillRunEvent
(
promises
,
FileOperation
.
MOVE
,
target
,
source
)
);
// find all models that related to either source or target (can be many if resource is a folder)
const
sourceModels
:
ITextFileEditorModel
[]
=
[];
...
...
@@ -521,25 +535,10 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
}
}));
return
stat
;
}
private
async
notifyOnWillMove
(
source
:
URI
,
target
:
URI
):
Promise
<
void
>
{
const
waitForPromises
:
Promise
<
unknown
>
[]
=
[];
// fire event
this
.
_onWillMove
.
fire
({
oldResource
:
source
,
newResource
:
target
,
waitUntil
(
promise
:
Promise
<
unknown
>
)
{
waitForPromises
.
push
(
promise
.
then
(
undefined
,
errors
.
onUnexpectedError
));
}
});
// after event
this
.
_onDidRunOperation
.
fire
(
new
FileOperationDidRunEvent
(
FileOperation
.
MOVE
,
target
,
source
));
// prevent async waitUntil-calls
Object
.
freeze
(
waitForPromises
);
await
Promise
.
all
(
waitForPromises
);
return
stat
;
}
//#endregion
...
...
src/vs/workbench/services/textfile/common/textfiles.ts
浏览文件 @
1fd95d53
...
...
@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
Event
,
IWaitUntil
}
from
'
vs/base/common/event
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IEncodingSupport
,
ConfirmResult
,
IRevertOptions
,
IModeSupport
}
from
'
vs/workbench/common/editor
'
;
import
{
IBaseStatWithMetadata
,
IFileStatWithMetadata
,
IReadFileOptions
,
IWriteFileOptions
,
FileOperationError
,
FileOperationResult
}
from
'
vs/platform/files/common/files
'
;
import
{
IBaseStatWithMetadata
,
IFileStatWithMetadata
,
IReadFileOptions
,
IWriteFileOptions
,
FileOperationError
,
FileOperationResult
,
FileOperation
}
from
'
vs/platform/files/common/files
'
;
import
{
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
ITextEditorModel
}
from
'
vs/editor/common/services/resolverService
'
;
import
{
ITextBufferFactory
,
ITextModel
,
ITextSnapshot
}
from
'
vs/editor/common/model
'
;
...
...
@@ -22,14 +22,22 @@ export interface ITextFileService extends IDisposable {
_serviceBrand
:
undefined
;
readonly
onWillMove
:
Event
<
IWillMoveEvent
>
;
readonly
onAutoSaveConfigurationChange
:
Event
<
IAutoSaveConfiguration
>
;
readonly
onFilesAssociationChange
:
Event
<
void
>
;
readonly
isHotExitEnabled
:
boolean
;
/**
* An event that is fired before attempting a certain file operation.
*/
readonly
onWillRunOperation
:
Event
<
FileOperationWillRunEvent
>
;
/**
* An event that is fired after a file operation has been performed.
*/
readonly
onDidRunOperation
:
Event
<
FileOperationDidRunEvent
>
;
/**
* Access to the manager of text file editor models providing further methods to work with them.
*/
...
...
@@ -147,6 +155,35 @@ export interface ITextFileService extends IDisposable {
getAutoSaveConfiguration
():
IAutoSaveConfiguration
;
}
export
class
FileOperationWillRunEvent
implements
IWaitUntil
{
constructor
(
private
_thenables
:
Promise
<
any
>
[],
readonly
operation
:
FileOperation
,
readonly
target
:
URI
,
readonly
source
?:
URI
|
undefined
)
{
}
waitUntil
(
thenable
:
Promise
<
any
>
):
void
{
if
(
Object
.
isFrozen
(
this
.
_thenables
))
{
throw
new
Error
(
'
waitUntil cannot be used aync
'
);
}
this
.
_thenables
.
push
(
thenable
);
}
}
export
class
FileOperationDidRunEvent
{
constructor
(
readonly
operation
:
FileOperation
,
readonly
target
:
URI
,
readonly
source
?:
URI
|
undefined
)
{
}
}
export
interface
IReadTextFileOptions
extends
IReadFileOptions
{
/**
...
...
@@ -492,13 +529,6 @@ export interface IResolvedTextFileEditorModel extends ITextFileEditorModel {
createSnapshot
():
ITextSnapshot
;
}
export
interface
IWillMoveEvent
{
oldResource
:
URI
;
newResource
:
URI
;
waitUntil
(
p
:
Promise
<
unknown
>
):
void
;
}
/**
* Helper method to convert a snapshot into its full string form.
*/
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录