Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
cdc24699
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,发现更多精彩内容 >>
提交
cdc24699
编写于
1月 17, 2020
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
untitled - rewrite creation logic
上级
97005d89
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
109 addition
and
67 deletion
+109
-67
extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts
...vscode-api-tests/src/singlefolder-tests/workspace.test.ts
+2
-2
src/vs/workbench/api/browser/mainThreadDocuments.ts
src/vs/workbench/api/browser/mainThreadDocuments.ts
+4
-5
src/vs/workbench/browser/parts/editor/editorDropTarget.ts
src/vs/workbench/browser/parts/editor/editorDropTarget.ts
+1
-1
src/vs/workbench/contrib/backup/test/electron-browser/backupRestorer.test.ts
...ntrib/backup/test/electron-browser/backupRestorer.test.ts
+2
-2
src/vs/workbench/services/editor/browser/editorService.ts
src/vs/workbench/services/editor/browser/editorService.ts
+2
-1
src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts
...ices/textmodelResolver/common/textModelResolverService.ts
+1
-1
src/vs/workbench/services/untitled/common/untitledTextEditorService.ts
...nch/services/untitled/common/untitledTextEditorService.ts
+91
-49
src/vs/workbench/test/common/editor/untitledTextEditor.test.ts
...s/workbench/test/common/editor/untitledTextEditor.test.ts
+6
-6
未找到文件。
extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts
浏览文件 @
cdc24699
...
...
@@ -75,8 +75,8 @@ suite('workspace-namespace', () => {
});
});
test
(
'
openTextDocument, untitled is dirty
'
,
function
()
{
return
vscode
.
workspace
.
openTextDocument
(
vscode
.
Uri
.
parse
(
'
untitled:
'
+
join
(
vscode
.
workspace
.
workspaceFolders
!
[
0
].
uri
.
toString
()
||
''
,
'
./newfile.txt
'
)
)).
then
(
doc
=>
{
test
(
'
openTextDocument, untitled is dirty
'
,
async
function
()
{
return
vscode
.
workspace
.
openTextDocument
(
vscode
.
workspace
.
workspaceFolders
!
[
0
].
uri
.
with
({
scheme
:
'
untitled
'
,
path
:
posix
.
join
(
vscode
.
workspace
.
workspaceFolders
!
[
0
].
uri
.
path
,
'
newfile.txt
'
)
}
)).
then
(
doc
=>
{
assert
.
equal
(
doc
.
uri
.
scheme
,
'
untitled
'
);
assert
.
ok
(
doc
.
isDirty
);
});
...
...
src/vs/workbench/api/browser/mainThreadDocuments.ts
浏览文件 @
cdc24699
...
...
@@ -211,16 +211,15 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
// don't create a new file ontop of an existing file
return
Promise
.
reject
(
new
Error
(
'
file already exists
'
));
},
err
=>
{
return
this
.
_doCreateUntitled
(
uri
).
then
(
resource
=>
!!
resource
);
return
this
.
_doCreateUntitled
(
Boolean
(
uri
.
path
)
?
uri
:
undefined
).
then
(
resource
=>
!!
resource
);
});
}
private
_doCreateUntitled
(
r
esource
?:
URI
,
mode
?:
string
,
initialValue
?:
string
):
Promise
<
URI
>
{
private
_doCreateUntitled
(
associatedR
esource
?:
URI
,
mode
?:
string
,
initialValue
?:
string
):
Promise
<
URI
>
{
return
this
.
_textFileService
.
untitled
.
resolve
({
r
esource
,
associatedR
esource
,
mode
,
initialValue
,
useResourcePath
:
Boolean
(
resource
&&
resource
.
path
)
initialValue
}).
then
(
model
=>
{
const
resource
=
model
.
resource
;
...
...
src/vs/workbench/browser/parts/editor/editorDropTarget.ts
浏览文件 @
cdc24699
...
...
@@ -309,7 +309,7 @@ class DropOverlay extends Themable {
// Open as untitled file with the provided contents
const
contents
=
VSBuffer
.
wrap
(
new
Uint8Array
(
event
.
target
.
result
)).
toString
();
const
untitledEditor
=
this
.
textFileService
.
untitled
.
create
({
r
esource
:
proposedFilePath
,
initialValue
:
contents
});
const
untitledEditor
=
this
.
textFileService
.
untitled
.
create
({
associatedR
esource
:
proposedFilePath
,
initialValue
:
contents
});
if
(
!
targetGroup
)
{
targetGroup
=
ensureTargetGroup
();
...
...
src/vs/workbench/contrib/backup/test/electron-browser/backupRestorer.test.ts
浏览文件 @
cdc24699
...
...
@@ -127,12 +127,12 @@ suite('BackupRestorer', () => {
for
(
const
editor
of
editorService
.
editors
)
{
const
resource
=
editor
.
getResource
();
if
(
isEqual
(
resource
,
untitledFile1
))
{
const
model
=
await
accessor
.
textFileService
.
untitled
.
resolve
({
resource
});
const
model
=
await
accessor
.
textFileService
.
untitled
.
resolve
({
untitledResource
:
resource
});
assert
.
equal
(
model
.
textEditorModel
.
getValue
(),
'
untitled-1
'
);
model
.
dispose
();
counter
++
;
}
else
if
(
isEqual
(
resource
,
untitledFile2
))
{
const
model
=
await
accessor
.
textFileService
.
untitled
.
resolve
({
resource
});
const
model
=
await
accessor
.
textFileService
.
untitled
.
resolve
({
untitledResource
:
resource
});
assert
.
equal
(
model
.
textEditorModel
.
getValue
(),
'
untitled-2
'
);
model
.
dispose
();
counter
++
;
...
...
src/vs/workbench/services/editor/browser/editorService.ts
浏览文件 @
cdc24699
...
...
@@ -611,7 +611,8 @@ export class EditorService extends Disposable implements EditorServiceImpl {
const
untitledInput
=
input
as
IUntitledTextResourceInput
;
if
(
untitledInput
.
forceUntitled
||
!
untitledInput
.
resource
||
(
untitledInput
.
resource
&&
untitledInput
.
resource
.
scheme
===
Schemas
.
untitled
))
{
return
this
.
untitledTextEditorService
.
create
({
resource
:
untitledInput
.
resource
,
untitledResource
:
untitledInput
.
resource
?.
scheme
===
Schemas
.
untitled
?
untitledInput
.
resource
:
undefined
,
associatedResource
:
untitledInput
.
resource
?.
scheme
!==
Schemas
.
untitled
?
untitledInput
.
resource
:
undefined
,
mode
:
untitledInput
.
mode
,
initialValue
:
untitledInput
.
contents
,
encoding
:
untitledInput
.
encoding
...
...
src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts
浏览文件 @
cdc24699
...
...
@@ -141,7 +141,7 @@ export class TextModelResolverService implements ITextModelService {
// Untitled Schema: go through cached input
if
(
resource
.
scheme
===
network
.
Schemas
.
untitled
)
{
const
model
=
await
this
.
untitledTextEditorService
.
resolve
({
resource
});
const
model
=
await
this
.
untitledTextEditorService
.
resolve
({
untitledResource
:
resource
});
return
new
ImmortalReference
(
model
);
}
...
...
src/vs/workbench/services/untitled/common/untitledTextEditorService.ts
浏览文件 @
cdc24699
...
...
@@ -6,7 +6,7 @@
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
createDecorator
,
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
UntitledTextEditorInput
}
from
'
vs/workbench/common/editor/untitledTextEditorInput
'
;
import
{
IFilesConfiguration
,
IFileService
}
from
'
vs/platform/files/common/files
'
;
import
{
IFilesConfiguration
}
from
'
vs/platform/files/common/files
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
ResourceMap
}
from
'
vs/base/common/map
'
;
...
...
@@ -14,16 +14,40 @@ import { Schemas } from 'vs/base/common/network';
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
import
{
UntitledTextEditorModel
,
IUntitledTextEditorModel
}
from
'
vs/workbench/common/editor/untitledTextEditorModel
'
;
import
type
{
IResolvedTextEditorModel
}
from
'
vs/editor/common/services/resolverService
'
;
import
{
IResolvedTextEditorModel
}
from
'
vs/editor/common/services/resolverService
'
;
export
const
IUntitledTextEditorService
=
createDecorator
<
IUntitledTextEditorService
>
(
'
untitledTextEditorService
'
);
export
interface
IUntitledTextEditorOptions
{
resource
?:
URI
;
mode
?:
string
;
/**
* An optional resource to identify the untitled resource to create or return
* if already existing.
*/
untitledResource
?:
URI
;
/**
* An optional resource to associate with the untitled file. When saving
* the untitled file, the associated resource will be used and the user
* is not being asked to provide a file path.
*/
associatedResource
?:
URI
;
/**
* Initial value of the untitled file. An untitled file with initial
* value is dirty right from the beginning.
*/
initialValue
?:
string
;
/**
* Preferred language mode to use when saving the untitled file.
*/
mode
?:
string
;
/**
* Preferred encoding to use when saving the untitled file.
*/
encoding
?:
string
;
useResourcePath
?:
boolean
;
}
export
interface
IUntitledTextEditorModelManager
{
...
...
@@ -54,13 +78,16 @@ export interface IUntitledTextEditorModelManager {
get
(
resource
:
URI
):
UntitledTextEditorInput
|
undefined
;
/**
* Creates a new untitled input with the provided options.
* Creates a new untitled input with the provided options. If the `untitledResource`
* property is provided and the untitled input exists, it will return that existing
* instance instead of creating a new one.
*/
create
(
options
?:
IUntitledTextEditorOptions
):
UntitledTextEditorInput
;
/**
* Resolves an untitled editor model from the provided options. This can either
* return a new or existing model based on the options provided.
* Resolves an untitled editor model from the provided options. If the `untitledResource`
* property is provided and the untitled input exists, it will return that existing
* instance instead of creating a new one.
*/
resolve
(
options
?:
IUntitledTextEditorOptions
):
Promise
<
IUntitledTextEditorModel
&
IResolvedTextEditorModel
>
;
...
...
@@ -93,8 +120,7 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
constructor
(
@
IInstantiationService
private
readonly
instantiationService
:
IInstantiationService
,
@
IConfigurationService
private
readonly
configurationService
:
IConfigurationService
,
@
IFileService
private
readonly
fileService
:
IFileService
@
IConfigurationService
private
readonly
configurationService
:
IConfigurationService
)
{
super
();
}
...
...
@@ -107,40 +133,61 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
return
this
.
mapResourceToInput
.
get
(
resource
);
}
resolve
(
options
?:
IUntitledTextEditorOptions
):
Promise
<
UntitledTextEditorModel
&
IResolvedTextEditorModel
>
{
return
this
.
doCreateOrGet
(
options
).
resolve
();
}
create
(
options
?:
IUntitledTextEditorOptions
):
UntitledTextEditorInput
{
return
this
.
doCreateOrGet
(
options
?.
resource
,
options
?.
mode
,
options
?.
initialValue
,
options
?.
encoding
,
options
?.
useResourcePath
);
return
this
.
doCreateOrGet
(
options
);
}
private
doCreateOrGet
(
resource
?:
URI
,
mode
?:
string
,
initialValue
?:
string
,
encoding
?:
string
,
hasAssociatedFilePath
:
boolean
=
false
):
UntitledTextEditorInput
{
if
(
resource
)
{
private
doCreateOrGet
(
options
:
IUntitledTextEditorOptions
=
Object
.
create
(
null
)
):
UntitledTextEditorInput
{
const
massagedOptions
=
this
.
massageOptions
(
options
);
// Massage resource if it comes with known file based resource
if
(
this
.
fileService
.
canHandleResource
(
resource
))
{
hasAssociatedFilePath
=
true
;
resource
=
resource
.
with
({
scheme
:
Schemas
.
untitled
});
// ensure we have the right scheme
}
// Return existing instance if asked for it
if
(
massagedOptions
.
untitledResource
&&
this
.
mapResourceToInput
.
has
(
massagedOptions
.
untitledResource
))
{
return
this
.
mapResourceToInput
.
get
(
massagedOptions
.
untitledResource
)
!
;
}
// Create new instance otherwise
return
this
.
doCreate
(
massagedOptions
);
}
if
(
hasAssociatedFilePath
)
{
this
.
mapResourceToAssociatedFilePath
.
set
(
resource
,
true
);
// remember for future lookups
private
massageOptions
(
options
:
IUntitledTextEditorOptions
):
IUntitledTextEditorOptions
{
const
massagedOptions
:
IUntitledTextEditorOptions
=
Object
.
create
(
null
);
// Figure out associated and untitled resource
if
(
options
.
associatedResource
)
{
massagedOptions
.
untitledResource
=
options
.
associatedResource
.
with
({
scheme
:
Schemas
.
untitled
});
massagedOptions
.
associatedResource
=
options
.
associatedResource
;
}
else
{
if
(
options
.
untitledResource
?.
scheme
===
Schemas
.
untitled
)
{
massagedOptions
.
untitledResource
=
options
.
untitledResource
;
}
}
// Return existing instance if asked for it
if
(
resource
&&
this
.
mapResourceToInput
.
has
(
resource
))
{
return
this
.
mapResourceToInput
.
get
(
resource
)
!
;
// Language mode
if
(
options
.
mode
)
{
massagedOptions
.
mode
=
options
.
mode
;
}
else
if
(
!
massagedOptions
.
associatedResource
)
{
const
configuration
=
this
.
configurationService
.
getValue
<
IFilesConfiguration
>
();
if
(
configuration
.
files
?.
defaultLanguage
)
{
massagedOptions
.
mode
=
configuration
.
files
.
defaultLanguage
;
}
}
// Create new otherwise
return
this
.
doCreate
(
resource
,
hasAssociatedFilePath
,
mode
,
initialValue
,
encoding
);
// Take over encoding and initial value
massagedOptions
.
encoding
=
options
.
encoding
;
massagedOptions
.
initialValue
=
options
.
initialValue
;
return
massagedOptions
;
}
private
doCreate
(
resource
?:
URI
,
hasAssociatedFilePath
?:
boolean
,
mode
?:
string
,
initialValue
?:
string
,
encoding
?:
string
):
UntitledTextEditorInput
{
let
untitledResource
:
URI
;
if
(
resource
)
{
untitledResource
=
resource
;
}
else
{
private
doCreate
(
options
:
IUntitledTextEditorOptions
):
UntitledTextEditorInput
{
// Create new taking a resource URI that is not already taken
// Create a new untitled resource if none is provided
let
untitledResource
=
options
.
untitledResource
;
if
(
!
untitledResource
)
{
let
counter
=
this
.
mapResourceToInput
.
size
+
1
;
do
{
untitledResource
=
URI
.
from
({
scheme
:
Schemas
.
untitled
,
path
:
`Untitled-
${
counter
}
`
});
...
...
@@ -148,25 +195,21 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
}
while
(
this
.
mapResourceToInput
.
has
(
untitledResource
));
}
// Look up default language from settings if any
if
(
!
mode
&&
!
hasAssociatedFilePath
)
{
const
configuration
=
this
.
configurationService
.
getValue
<
IFilesConfiguration
>
();
if
(
configuration
.
files
?.
defaultLanguage
)
{
mode
=
configuration
.
files
.
defaultLanguage
;
}
}
const
input
=
this
.
instantiationService
.
createInstance
(
UntitledTextEditorInput
,
untitledResource
,
!!
hasAssociatedFilePath
,
mode
,
initialValue
,
encoding
);
// Create new input with provided options
const
input
=
this
.
instantiationService
.
createInstance
(
UntitledTextEditorInput
,
untitledResource
,
!!
options
.
associatedResource
,
options
.
mode
,
options
.
initialValue
,
options
.
encoding
);
const
dirtyListener
=
input
.
onDidChangeDirty
(()
=>
this
.
_onDidChangeDirty
.
fire
(
untitledResource
));
const
encodingListener
=
input
.
onDidModelChangeEncoding
(()
=>
this
.
_onDidChangeEncoding
.
fire
(
untitledResource
));
const
disposeListener
=
input
.
onDispose
(()
=>
this
.
_onDidDisposeModel
.
fire
(
untitledResource
));
const
dirtyListener
=
input
.
onDidChangeDirty
(()
=>
this
.
_onDidChangeDirty
.
fire
(
input
.
getResource
()
));
const
encodingListener
=
input
.
onDidModelChangeEncoding
(()
=>
this
.
_onDidChangeEncoding
.
fire
(
input
.
getResource
()
));
const
disposeListener
=
input
.
onDispose
(()
=>
this
.
_onDidDisposeModel
.
fire
(
input
.
getResource
()
));
// Remove from cache on dispose
const
onceDispose
=
Event
.
once
(
input
.
onDispose
);
onceDispose
(()
=>
{
Event
.
once
(
input
.
onDispose
)(()
=>
{
// Registry
this
.
mapResourceToInput
.
delete
(
input
.
getResource
());
this
.
mapResourceToAssociatedFilePath
.
delete
(
input
.
getResource
());
// Listeners
dirtyListener
.
dispose
();
encodingListener
.
dispose
();
disposeListener
.
dispose
();
...
...
@@ -174,14 +217,13 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
// Add to cache
this
.
mapResourceToInput
.
set
(
untitledResource
,
input
);
if
(
options
.
associatedResource
)
{
this
.
mapResourceToAssociatedFilePath
.
set
(
untitledResource
,
true
);
}
return
input
;
}
resolve
(
options
?:
IUntitledTextEditorOptions
):
Promise
<
UntitledTextEditorModel
&
IResolvedTextEditorModel
>
{
return
this
.
doCreateOrGet
(
options
?.
resource
,
options
?.
mode
,
options
?.
initialValue
,
options
?.
encoding
,
options
?.
useResourcePath
).
resolve
();
}
hasAssociatedFilePath
(
resource
:
URI
):
boolean
{
return
this
.
mapResourceToAssociatedFilePath
.
has
(
resource
);
}
...
...
src/vs/workbench/test/common/editor/untitledTextEditor.test.ts
浏览文件 @
cdc24699
...
...
@@ -46,7 +46,7 @@ suite('Workbench untitled text editors', () => {
const
workingCopyService
=
accessor
.
workingCopyService
;
const
input1
=
service
.
create
();
assert
.
equal
(
input1
,
service
.
create
({
r
esource
:
input1
.
getResource
()
}));
assert
.
equal
(
input1
,
service
.
create
({
untitledR
esource
:
input1
.
getResource
()
}));
assert
.
equal
(
service
.
get
(
input1
.
getResource
()),
input1
);
assert
.
ok
(
service
.
exists
(
input1
.
getResource
()));
...
...
@@ -66,7 +66,7 @@ suite('Workbench untitled text editors', () => {
// dirty
const
model
=
await
input2
.
resolve
();
assert
.
equal
(
await
service
.
resolve
({
r
esource
:
input2
.
getResource
()
}),
model
);
assert
.
equal
(
await
service
.
resolve
({
untitledR
esource
:
input2
.
getResource
()
}),
model
);
assert
.
ok
(
!
input2
.
isDirty
());
...
...
@@ -109,7 +109,7 @@ suite('Workbench untitled text editors', () => {
test
(
'
Untitled with associated resource is dirty
'
,
()
=>
{
const
service
=
accessor
.
untitledTextEditorService
;
const
file
=
URI
.
file
(
join
(
'
C:
\\
'
,
'
/foo/file.txt
'
));
const
untitled
=
service
.
create
({
r
esource
:
file
});
const
untitled
=
service
.
create
({
associatedR
esource
:
file
});
assert
.
ok
(
service
.
hasAssociatedFilePath
(
untitled
.
getResource
()));
assert
.
equal
(
untitled
.
isDirty
(),
true
);
...
...
@@ -150,12 +150,12 @@ suite('Workbench untitled text editors', () => {
const
input
=
service
.
create
();
const
model3
=
await
service
.
create
({
r
esource
:
input
.
getResource
()
}).
resolve
();
const
model3
=
await
service
.
create
({
untitledR
esource
:
input
.
getResource
()
}).
resolve
();
assert
.
equal
(
model3
.
resource
.
toString
(),
input
.
getResource
().
toString
());
const
file
=
URI
.
file
(
join
(
'
C:
\\
'
,
'
/foo/file44.txt
'
));
const
model4
=
await
service
.
create
({
r
esource
:
file
}).
resolve
();
const
model4
=
await
service
.
create
({
associatedR
esource
:
file
}).
resolve
();
assert
.
ok
(
service
.
hasAssociatedFilePath
(
model4
.
resource
));
assert
.
ok
(
model4
.
isDirty
());
...
...
@@ -177,7 +177,7 @@ suite('Workbench untitled text editors', () => {
test
(
'
Untitled with associated path remains dirty when content gets empty
'
,
async
()
=>
{
const
service
=
accessor
.
untitledTextEditorService
;
const
file
=
URI
.
file
(
join
(
'
C:
\\
'
,
'
/foo/file.txt
'
));
const
input
=
service
.
create
({
r
esource
:
file
});
const
input
=
service
.
create
({
associatedR
esource
:
file
});
// dirty
const
model
=
await
input
.
resolve
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录