Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
0ff871ce
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
0ff871ce
编写于
12月 02, 2016
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Hot Exit: properly deal with backups to files that got deleted (fixes #14054)
上级
2e77e6c9
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
149 addition
and
114 deletion
+149
-114
src/vs/platform/files/common/files.ts
src/vs/platform/files/common/files.ts
+5
-0
src/vs/workbench/parts/backup/common/backupRestorer.ts
src/vs/workbench/parts/backup/common/backupRestorer.ts
+21
-21
src/vs/workbench/services/files/electron-browser/fileService.ts
.../workbench/services/files/electron-browser/fileService.ts
+4
-0
src/vs/workbench/services/files/node/fileService.ts
src/vs/workbench/services/files/node/fileService.ts
+1
-1
src/vs/workbench/services/textfile/common/textFileEditorModel.ts
...workbench/services/textfile/common/textFileEditorModel.ts
+118
-92
未找到文件。
src/vs/platform/files/common/files.ts
浏览文件 @
0ff871ce
...
...
@@ -126,6 +126,11 @@ export interface IFileService {
*/
updateOptions
(
options
:
any
):
void
;
/**
* Returns the preferred encoding to use for a given resource.
*/
getEncoding
(
resource
:
URI
):
string
;
/**
* Frees up any resources occupied by this service.
*/
...
...
src/vs/workbench/parts/backup/common/backupRestorer.ts
浏览文件 @
0ff871ce
...
...
@@ -59,6 +59,27 @@ export class BackupRestorer implements IWorkbenchContribution {
});
}
private
doResolveOpenedBackups
(
backups
:
URI
[]):
TPromise
<
URI
[]
>
{
const
stacks
=
this
.
groupService
.
getStacksModel
();
const
restorePromises
:
TPromise
<
any
>
[]
=
[];
const
unresolved
:
URI
[]
=
[];
backups
.
forEach
(
backup
=>
{
if
(
stacks
.
isOpen
(
backup
))
{
if
(
backup
.
scheme
===
'
file
'
)
{
restorePromises
.
push
(
this
.
textModelResolverService
.
createModelReference
(
backup
).
then
(
null
,
()
=>
unresolved
.
push
(
backup
)));
}
else
if
(
backup
.
scheme
===
'
untitled
'
)
{
restorePromises
.
push
(
this
.
untitledEditorService
.
get
(
backup
).
resolve
().
then
(
null
,
()
=>
unresolved
.
push
(
backup
)));
}
}
else
{
unresolved
.
push
(
backup
);
}
});
return
TPromise
.
join
(
restorePromises
).
then
(()
=>
unresolved
,
()
=>
unresolved
);
}
private
doOpenEditors
(
inputs
:
URI
[]):
TPromise
<
void
>
{
const
stacks
=
this
.
groupService
.
getStacksModel
();
const
hasOpenedEditors
=
stacks
.
groups
.
length
>
0
;
...
...
@@ -83,27 +104,6 @@ export class BackupRestorer implements IWorkbenchContribution {
return
this
.
editorService
.
createInput
({
resource
});
}
private
doResolveOpenedBackups
(
backups
:
URI
[]):
TPromise
<
URI
[]
>
{
const
stacks
=
this
.
groupService
.
getStacksModel
();
const
restorePromises
:
TPromise
<
any
>
[]
=
[];
const
unresolved
:
URI
[]
=
[];
backups
.
forEach
(
backup
=>
{
if
(
stacks
.
isOpen
(
backup
))
{
if
(
backup
.
scheme
===
'
file
'
)
{
restorePromises
.
push
(
this
.
textModelResolverService
.
createModelReference
(
backup
).
then
(
null
,
()
=>
unresolved
.
push
(
backup
)));
}
else
if
(
backup
.
scheme
===
'
untitled
'
)
{
restorePromises
.
push
(
this
.
untitledEditorService
.
get
(
backup
).
resolve
().
then
(
null
,
()
=>
unresolved
.
push
(
backup
)));
}
}
else
{
unresolved
.
push
(
backup
);
}
});
return
TPromise
.
join
(
restorePromises
).
then
(()
=>
unresolved
,
()
=>
unresolved
);
}
public
getId
():
string
{
return
'
vs.backup.backupRestorer
'
;
}
...
...
src/vs/workbench/services/files/electron-browser/fileService.ts
浏览文件 @
0ff871ce
...
...
@@ -289,6 +289,10 @@ export class FileService implements IFileService {
this
.
raw
.
unwatchFileChanges
(
arg1
);
}
public
getEncoding
(
resource
:
uri
):
string
{
return
this
.
raw
.
getEncoding
(
resource
);
}
public
dispose
():
void
{
this
.
toUnbind
=
dispose
(
this
.
toUnbind
);
...
...
src/vs/workbench/services/files/node/fileService.ts
浏览文件 @
0ff871ce
...
...
@@ -518,7 +518,7 @@ export class FileService implements IFileService {
});
}
p
rivate
getEncoding
(
resource
:
uri
,
preferredEncoding
?:
string
):
string
{
p
ublic
getEncoding
(
resource
:
uri
,
preferredEncoding
?:
string
):
string
{
let
fileEncoding
:
string
;
const
override
=
this
.
getEncodingOverride
(
resource
);
...
...
src/vs/workbench/services/textfile/common/textFileEditorModel.ts
浏览文件 @
0ff871ce
...
...
@@ -19,11 +19,11 @@ import types = require('vs/base/common/types');
import
{
IModelContentChangedEvent
,
IRawText
}
from
'
vs/editor/common/editorCommon
'
;
import
{
IMode
}
from
'
vs/editor/common/modes
'
;
import
{
ILifecycleService
}
from
'
vs/platform/lifecycle/common/lifecycle
'
;
import
{
ITextFileService
,
IAutoSaveConfiguration
,
ModelState
,
ITextFileEditorModel
,
IModelSaveOptions
,
ISaveErrorHandler
,
ISaveParticipant
,
StateChange
,
SaveReason
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
ITextFileService
,
IAutoSaveConfiguration
,
ModelState
,
ITextFileEditorModel
,
IModelSaveOptions
,
ISaveErrorHandler
,
ISaveParticipant
,
StateChange
,
SaveReason
,
IRawTextContent
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
EncodingMode
,
EditorModel
}
from
'
vs/workbench/common/editor
'
;
import
{
BaseTextEditorModel
}
from
'
vs/workbench/common/editor/textEditorModel
'
;
import
{
IBackupFileService
,
BACKUP_FILE_RESOLVE_OPTIONS
}
from
'
vs/workbench/services/backup/common/backup
'
;
import
{
IFileService
,
IFileStat
,
IFileOperationResult
,
FileOperationResult
}
from
'
vs/platform/files/common/files
'
;
import
{
IFileService
,
IFileStat
,
IFileOperationResult
,
FileOperationResult
,
IContent
}
from
'
vs/platform/files/common/files
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IMessageService
,
Severity
}
from
'
vs/platform/message/common/message
'
;
import
{
IModeService
}
from
'
vs/editor/common/services/modeService
'
;
...
...
@@ -196,7 +196,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
// Emit file change event
this
.
_onDidStateChange
.
fire
(
StateChange
.
REVERTED
);
},
(
error
)
=>
{
},
error
=>
{
// FileNotFound means the file got deleted meanwhile, so emit revert event because thats ok
if
((
<
IFileOperationResult
>
error
).
fileOperationResult
===
FileOperationResult
.
FILE_NOT_FOUND
)
{
...
...
@@ -233,109 +233,135 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
}
// Resolve Content
return
this
.
textFileService
.
resolveTextContent
(
this
.
resource
,
{
acceptTextOnly
:
true
,
etag
:
etag
,
encoding
:
this
.
preferredEncoding
}).
then
((
content
)
=>
{
diag
(
'
load() - resolved content
'
,
this
.
resource
,
new
Date
());
// Telemetry
this
.
telemetryService
.
publicLog
(
'
fileGet
'
,
{
mimeType
:
guessMimeTypes
(
this
.
resource
.
fsPath
).
join
(
'
,
'
),
ext
:
paths
.
extname
(
this
.
resource
.
fsPath
),
path
:
anonymize
(
this
.
resource
.
fsPath
)
});
// Update our resolved disk stat model
const
resolvedStat
:
IFileStat
=
{
resource
:
this
.
resource
,
name
:
content
.
name
,
mtime
:
content
.
mtime
,
etag
:
content
.
etag
,
isDirectory
:
false
,
hasChildren
:
false
,
children
:
void
0
,
};
this
.
updateVersionOnDiskStat
(
resolvedStat
);
return
this
.
textFileService
.
resolveTextContent
(
this
.
resource
,
{
acceptTextOnly
:
true
,
etag
:
etag
,
encoding
:
this
.
preferredEncoding
}).
then
(
content
=>
this
.
loadWithContent
(
content
),
error
=>
{
const
result
=
(
<
IFileOperationResult
>
error
).
fileOperationResult
;
//
Keep the original encoding to not loose it when saving
const
oldEncoding
=
this
.
contentEncoding
;
this
.
contentEncoding
=
content
.
encoding
;
//
NotModified status is expected and can be handled gracefully
if
(
result
===
FileOperationResult
.
FILE_NOT_MODIFIED_SINCE
)
{
this
.
setDirty
(
false
);
// Ensure we are not tracking a stale state
// Handle events if encoding changed
if
(
this
.
preferredEncoding
)
{
this
.
updatePreferredEncoding
(
this
.
contentEncoding
);
// make sure to reflect the real encoding of the file (never out of sync)
}
else
if
(
oldEncoding
!==
this
.
contentEncoding
)
{
this
.
_onDidStateChange
.
fire
(
StateChange
.
ENCODING
);
return
TPromise
.
as
<
EditorModel
>
(
this
);
}
// Update Existing Model
if
(
this
.
textEditorModel
)
{
diag
(
'
load() - updated text editor model
'
,
this
.
resource
,
new
Date
());
// FileNotFound needs to be handled if we have a backup
if
(
result
===
FileOperationResult
.
FILE_NOT_FOUND
)
{
if
(
!
this
.
textEditorModel
&&
!
this
.
createTextEditorModelPromise
)
{
return
this
.
backupFileService
.
loadBackupResource
(
this
.
resource
).
then
(
backup
=>
{
if
(
!!
backup
)
{
const
content
:
IContent
=
{
resource
:
this
.
resource
,
name
:
paths
.
basename
(
this
.
resource
.
fsPath
),
mtime
:
Date
.
now
(),
etag
:
void
0
,
value
:
''
,
/* will be filled later from backup */
encoding
:
this
.
fileService
.
getEncoding
(
this
.
resource
)
};
return
this
.
loadWithContent
(
content
);
}
// Otherwise bubble up the error
return
TPromise
.
wrapError
(
error
);
},
ignoreError
=>
TPromise
.
wrapError
(
error
));
}
}
this
.
setDirty
(
false
);
// Ensure we are not tracking a stale state
// Otherwise bubble up the error
return
TPromise
.
wrapError
(
error
);
});
}
this
.
blockModelContentChange
=
true
;
try
{
this
.
updateTextEditorModel
(
content
.
value
);
}
finally
{
this
.
blockModelContentChange
=
false
;
}
private
loadWithContent
(
content
:
IRawTextContent
|
IContent
):
TPromise
<
EditorModel
>
{
diag
(
'
load() - resolved content
'
,
this
.
resource
,
new
Date
());
return
TPromise
.
as
<
EditorModel
>
(
this
);
}
// Telemetry
this
.
telemetryService
.
publicLog
(
'
fileGet
'
,
{
mimeType
:
guessMimeTypes
(
this
.
resource
.
fsPath
).
join
(
'
,
'
),
ext
:
paths
.
extname
(
this
.
resource
.
fsPath
),
path
:
anonymize
(
this
.
resource
.
fsPath
)
});
// Join an existing request to create the editor model to avoid race conditions
else
if
(
this
.
createTextEditorModelPromise
)
{
diag
(
'
load() - join existing text editor model promise
'
,
this
.
resource
,
new
Date
());
// Update our resolved disk stat model
const
resolvedStat
:
IFileStat
=
{
resource
:
this
.
resource
,
name
:
content
.
name
,
mtime
:
content
.
mtime
,
etag
:
content
.
etag
,
isDirectory
:
false
,
hasChildren
:
false
,
children
:
void
0
,
};
this
.
updateVersionOnDiskStat
(
resolvedStat
);
return
this
.
createTextEditorModelPromise
;
}
// Keep the original encoding to not loose it when saving
const
oldEncoding
=
this
.
contentEncoding
;
this
.
contentEncoding
=
content
.
encoding
;
// Create New Model
else
{
diag
(
'
load() - created text editor model
'
,
this
.
resource
,
new
Date
());
return
this
.
backupFileService
.
loadBackupResource
(
this
.
resource
).
then
(
backupResource
=>
{
let
resolveBackupPromise
:
TPromise
<
string
|
IRawText
>
;
// Try get restore content, if there is an issue fallback silently to the original file's content
if
(
backupResource
)
{
resolveBackupPromise
=
this
.
textFileService
.
resolveTextContent
(
backupResource
,
BACKUP_FILE_RESOLVE_OPTIONS
).
then
(
backup
=>
{
return
this
.
backupFileService
.
parseBackupContent
(
backup
);
},
error
=>
content
.
value
);
}
else
{
resolveBackupPromise
=
TPromise
.
as
(
content
.
value
);
}
this
.
createTextEditorModelPromise
=
resolveBackupPromise
.
then
(
fileContent
=>
{
return
this
.
createTextEditorModel
(
fileContent
,
content
.
resource
).
then
(()
=>
{
this
.
createTextEditorModelPromise
=
null
;
if
(
backupResource
)
{
this
.
makeDirty
();
}
else
{
this
.
setDirty
(
false
);
// Ensure we are not tracking a stale state
}
this
.
toDispose
.
push
(
this
.
textEditorModel
.
onDidChangeRawContent
((
e
:
IModelContentChangedEvent
)
=>
this
.
onModelContentChanged
(
e
)));
return
this
;
},
(
error
)
=>
{
this
.
createTextEditorModelPromise
=
null
;
return
TPromise
.
wrapError
(
error
);
});
});
// Handle events if encoding changed
if
(
this
.
preferredEncoding
)
{
this
.
updatePreferredEncoding
(
this
.
contentEncoding
);
// make sure to reflect the real encoding of the file (never out of sync)
}
else
if
(
oldEncoding
!==
this
.
contentEncoding
)
{
this
.
_onDidStateChange
.
fire
(
StateChange
.
ENCODING
);
}
return
this
.
createTextEditorModelPromise
;
});
}
},
(
error
)
=>
{
// Update Existing Model
if
(
this
.
textEditorModel
)
{
diag
(
'
load() - updated text editor model
'
,
this
.
resource
,
new
Date
());
// NotModified status code is expected and can be handled gracefully
if
((
<
IFileOperationResult
>
error
).
fileOperationResult
===
FileOperationResult
.
FILE_NOT_MODIFIED_SINCE
)
{
this
.
setDirty
(
false
);
// Ensure we are not tracking a stale state
this
.
setDirty
(
false
);
// Ensure we are not tracking a stale state
return
TPromise
.
as
<
EditorModel
>
(
this
);
this
.
blockModelContentChange
=
true
;
try
{
this
.
updateTextEditorModel
(
content
.
value
);
}
finally
{
this
.
blockModelContentChange
=
false
;
}
// Otherwise bubble up the error
return
TPromise
.
wrapError
(
error
);
});
return
TPromise
.
as
<
EditorModel
>
(
this
);
}
// Join an existing request to create the editor model to avoid race conditions
else
if
(
this
.
createTextEditorModelPromise
)
{
diag
(
'
load() - join existing text editor model promise
'
,
this
.
resource
,
new
Date
());
return
this
.
createTextEditorModelPromise
;
}
// Create New Model
else
{
diag
(
'
load() - created text editor model
'
,
this
.
resource
,
new
Date
());
return
this
.
backupFileService
.
loadBackupResource
(
this
.
resource
).
then
(
backupResource
=>
{
let
resolveBackupPromise
:
TPromise
<
string
|
IRawText
>
;
// Try get restore content, if there is an issue fallback silently to the original file's content
if
(
backupResource
)
{
resolveBackupPromise
=
this
.
textFileService
.
resolveTextContent
(
backupResource
,
BACKUP_FILE_RESOLVE_OPTIONS
).
then
(
backup
=>
{
return
this
.
backupFileService
.
parseBackupContent
(
backup
);
},
error
=>
content
.
value
);
}
else
{
resolveBackupPromise
=
TPromise
.
as
(
content
.
value
);
}
this
.
createTextEditorModelPromise
=
resolveBackupPromise
.
then
(
fileContent
=>
{
return
this
.
createTextEditorModel
(
fileContent
,
content
.
resource
).
then
(()
=>
{
this
.
createTextEditorModelPromise
=
null
;
if
(
backupResource
)
{
this
.
makeDirty
();
}
else
{
this
.
setDirty
(
false
);
// Ensure we are not tracking a stale state
}
this
.
toDispose
.
push
(
this
.
textEditorModel
.
onDidChangeRawContent
((
e
:
IModelContentChangedEvent
)
=>
this
.
onModelContentChanged
(
e
)));
return
this
;
},
error
=>
{
this
.
createTextEditorModelPromise
=
null
;
return
TPromise
.
wrapError
(
error
);
});
});
return
this
.
createTextEditorModelPromise
;
});
}
}
protected
getOrCreateMode
(
modeService
:
IModeService
,
preferredModeIds
:
string
,
firstLineText
?:
string
):
TPromise
<
IMode
>
{
...
...
@@ -561,7 +587,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
// Emit File Saved Event
this
.
_onDidStateChange
.
fire
(
StateChange
.
SAVED
);
},
(
error
)
=>
{
},
error
=>
{
diag
(
`doSave(
${
versionId
}
) - exit - resulted in a save error:
${
error
.
toString
()}
`
,
this
.
resource
,
new
Date
());
// Remove from pending saves
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录