Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
ceabb063
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,发现更多精彩内容 >>
提交
ceabb063
编写于
1月 18, 2020
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Unsaved tab labels should preview text instead of "Untitled-#" (fixes #37414)
上级
c09fa216
变更
10
显示空白变更内容
内联
并排
Showing
10 changed file
with
206 addition
and
66 deletion
+206
-66
src/vs/workbench/browser/parts/editor/editorActions.ts
src/vs/workbench/browser/parts/editor/editorActions.ts
+10
-9
src/vs/workbench/browser/parts/editor/editorGroupView.ts
src/vs/workbench/browser/parts/editor/editorGroupView.ts
+9
-3
src/vs/workbench/common/editor.ts
src/vs/workbench/common/editor.ts
+18
-13
src/vs/workbench/common/editor/diffEditorInput.ts
src/vs/workbench/common/editor/diffEditorInput.ts
+18
-17
src/vs/workbench/common/editor/untitledTextEditorInput.ts
src/vs/workbench/common/editor/untitledTextEditorInput.ts
+33
-1
src/vs/workbench/common/editor/untitledTextEditorModel.ts
src/vs/workbench/common/editor/untitledTextEditorModel.ts
+19
-3
src/vs/workbench/contrib/backup/electron-browser/backupOnShutdown.ts
...bench/contrib/backup/electron-browser/backupOnShutdown.ts
+1
-1
src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts
...ontrib/backup/test/electron-browser/backupTracker.test.ts
+19
-5
src/vs/workbench/services/editor/browser/editorService.ts
src/vs/workbench/services/editor/browser/editorService.ts
+21
-14
src/vs/workbench/test/common/editor/untitledTextEditor.test.ts
...s/workbench/test/common/editor/untitledTextEditor.test.ts
+58
-0
未找到文件。
src/vs/workbench/browser/parts/editor/editorActions.ts
浏览文件 @
ceabb063
...
...
@@ -6,7 +6,7 @@
import
*
as
nls
from
'
vs/nls
'
;
import
{
Action
}
from
'
vs/base/common/actions
'
;
import
{
mixin
}
from
'
vs/base/common/objects
'
;
import
{
IEditorInput
,
EditorInput
,
IEditorIdentifier
,
IEditorCommandsContext
,
CloseDirection
,
SaveReason
,
EditorsOrder
}
from
'
vs/workbench/common/editor
'
;
import
{
IEditorInput
,
EditorInput
,
IEditorIdentifier
,
IEditorCommandsContext
,
CloseDirection
,
SaveReason
,
EditorsOrder
,
SideBySideEditorInput
}
from
'
vs/workbench/common/editor
'
;
import
{
QuickOpenEntryGroup
}
from
'
vs/base/parts/quickopen/browser/quickOpenModel
'
;
import
{
EditorQuickOpenEntry
,
EditorQuickOpenEntryGroup
,
IEditorQuickOpenEntry
,
QuickOpenAction
}
from
'
vs/workbench/browser/quickopen
'
;
import
{
IQuickOpenService
}
from
'
vs/platform/quickOpen/common/quickOpen
'
;
...
...
@@ -23,7 +23,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
import
{
IWorkspacesService
}
from
'
vs/platform/workspaces/common/workspaces
'
;
import
{
IFileDialogService
,
ConfirmResult
}
from
'
vs/platform/dialogs/common/dialogs
'
;
import
{
IWorkingCopyService
}
from
'
vs/workbench/services/workingCopy/common/workingCopyService
'
;
import
{
ResourceMap
,
values
}
from
'
vs/base/common/map
'
;
import
{
values
}
from
'
vs/base/common/map
'
;
export
class
ExecuteCommandAction
extends
Action
{
...
...
@@ -640,23 +640,24 @@ export abstract class BaseCloseAllAction extends Action {
return
undefined
;
}));
const
dirtyEditorsToConfirmByName
=
new
Set
<
string
>
();
const
dirtyEditorsToConfirmByResource
=
new
ResourceMap
();
const
dirtyEditorsToConfirm
=
new
Set
<
string
>
();
for
(
const
editor
of
this
.
editorService
.
editors
)
{
if
(
!
editor
.
isDirty
()
||
editor
.
isSaving
())
{
continue
;
// only interested in dirty editors (unless in the process of saving)
}
const
resource
=
editor
.
getResource
()
;
if
(
resource
)
{
dirtyEditorsToConfirmByResource
.
set
(
resource
,
true
);
let
name
:
string
;
if
(
editor
instanceof
SideBySideEditorInput
)
{
name
=
editor
.
master
.
getName
();
// prefer shorter names by using master's name in this case
}
else
{
dirtyEditorsToConfirmByName
.
add
(
editor
.
getName
()
);
name
=
editor
.
getName
(
);
}
dirtyEditorsToConfirm
.
add
(
name
);
}
const
confirm
=
await
this
.
fileDialogService
.
showSaveConfirm
(
[...
dirtyEditorsToConfirmByResource
.
keys
(),
...
values
(
dirtyEditorsToConfirmByName
)]
);
const
confirm
=
await
this
.
fileDialogService
.
showSaveConfirm
(
values
(
dirtyEditorsToConfirm
)
);
if
(
confirm
===
ConfirmResult
.
CANCEL
)
{
return
;
}
...
...
src/vs/workbench/browser/parts/editor/editorGroupView.ts
浏览文件 @
ceabb063
...
...
@@ -6,7 +6,7 @@
import
'
vs/css!./media/editorgroupview
'
;
import
{
EditorGroup
,
IEditorOpenOptions
,
EditorCloseEvent
,
ISerializedEditorGroup
,
isSerializedEditorGroup
}
from
'
vs/workbench/common/editor/editorGroup
'
;
import
{
EditorInput
,
EditorOptions
,
GroupIdentifier
,
SideBySideEditorInput
,
CloseDirection
,
IEditorCloseEvent
,
EditorGroupActiveEditorDirtyContext
,
IEditor
,
EditorGroupEditorsCountContext
,
toResource
,
SideBySideEditor
,
SaveReason
,
SaveContext
,
IEditorPartOptionsChangeEvent
,
EditorsOrder
}
from
'
vs/workbench/common/editor
'
;
import
{
EditorInput
,
EditorOptions
,
GroupIdentifier
,
SideBySideEditorInput
,
CloseDirection
,
IEditorCloseEvent
,
EditorGroupActiveEditorDirtyContext
,
IEditor
,
EditorGroupEditorsCountContext
,
SaveReason
,
SaveContext
,
IEditorPartOptionsChangeEvent
,
EditorsOrder
}
from
'
vs/workbench/common/editor
'
;
import
{
Event
,
Emitter
,
Relay
}
from
'
vs/base/common/event
'
;
import
{
IInstantiationService
,
ServicesAccessor
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
addClass
,
addClasses
,
Dimension
,
trackFocus
,
toggleClass
,
removeClass
,
addDisposableListener
,
EventType
,
EventHelper
,
findParentWithClass
,
clearNode
,
isAncestor
}
from
'
vs/base/browser/dom
'
;
...
...
@@ -1306,8 +1306,14 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Switch to editor that we want to handle and confirm to save/revert
await
this
.
openEditor
(
editor
);
const
editorResource
=
toResource
(
editor
,
{
supportSideBySide
:
SideBySideEditor
.
MASTER
});
const
res
=
await
this
.
fileDialogService
.
showSaveConfirm
(
editorResource
?
[
editorResource
]
:
[
editor
.
getName
()]);
let
name
:
string
;
if
(
editor
instanceof
SideBySideEditorInput
)
{
name
=
editor
.
master
.
getName
();
// prefer shorter names by using master's name in this case
}
else
{
name
=
editor
.
getName
();
}
const
res
=
await
this
.
fileDialogService
.
showSaveConfirm
([
name
]);
// It could be that the editor saved meanwhile or is saving, so we check
// again to see if anything needs to happen before closing for good.
...
...
src/vs/workbench/common/editor.ts
浏览文件 @
ceabb063
...
...
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
localize
}
from
'
vs/nls
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
assign
}
from
'
vs/base/common/objects
'
;
import
{
withNullAsUndefined
,
assertIsDefined
}
from
'
vs/base/common/types
'
;
...
...
@@ -682,7 +683,7 @@ export class SideBySideEditorInput extends EditorInput {
static
readonly
ID
:
string
=
'
workbench.editorinputs.sidebysideEditorInput
'
;
constructor
(
pr
ivate
readonly
name
:
string
,
pr
otected
readonly
name
:
string
|
undefined
,
private
readonly
description
:
string
|
undefined
,
private
readonly
_details
:
EditorInput
,
private
readonly
_master
:
EditorInput
...
...
@@ -700,6 +701,22 @@ export class SideBySideEditorInput extends EditorInput {
return
this
.
_details
;
}
getTypeId
():
string
{
return
SideBySideEditorInput
.
ID
;
}
getName
():
string
{
if
(
!
this
.
name
)
{
return
localize
(
'
sideBySideLabels
'
,
"
{0} - {1}
"
,
this
.
_details
.
getName
(),
this
.
_master
.
getName
());
}
return
this
.
name
;
}
getDescription
():
string
|
undefined
{
return
this
.
description
;
}
isReadonly
():
boolean
{
return
this
.
master
.
isReadonly
();
}
...
...
@@ -760,18 +777,6 @@ export class SideBySideEditorInput extends EditorInput {
return
null
;
}
getTypeId
():
string
{
return
SideBySideEditorInput
.
ID
;
}
getName
():
string
{
return
this
.
name
;
}
getDescription
():
string
|
undefined
{
return
this
.
description
;
}
matches
(
otherInput
:
unknown
):
boolean
{
if
(
super
.
matches
(
otherInput
)
===
true
)
{
return
true
;
...
...
src/vs/workbench/common/editor/diffEditorInput.ts
浏览文件 @
ceabb063
...
...
@@ -7,6 +7,7 @@ import { EditorModel, EditorInput, SideBySideEditorInput, TEXT_DIFF_EDITOR_ID, B
import
{
BaseTextEditorModel
}
from
'
vs/workbench/common/editor/textEditorModel
'
;
import
{
DiffEditorModel
}
from
'
vs/workbench/common/editor/diffEditorModel
'
;
import
{
TextDiffEditorModel
}
from
'
vs/workbench/common/editor/textDiffEditorModel
'
;
import
{
localize
}
from
'
vs/nls
'
;
/**
* The base editor input for the diff editor. It is made up of two editor inputs, the original version
...
...
@@ -19,33 +20,25 @@ export class DiffEditorInput extends SideBySideEditorInput {
private
cachedModel
:
DiffEditorModel
|
null
=
null
;
constructor
(
name
:
string
,
protected
name
:
string
|
undefined
,
description
:
string
|
undefined
,
original
:
EditorInput
,
modified
:
EditorInput
,
public
readonly
originalInput
:
EditorInput
,
public
readonly
modifiedInput
:
EditorInput
,
private
readonly
forceOpenAsBinary
?:
boolean
)
{
super
(
name
,
description
,
original
,
modified
);
}
matches
(
otherInput
:
unknown
):
boolean
{
if
(
!
super
.
matches
(
otherInput
))
{
return
false
;
}
return
otherInput
instanceof
DiffEditorInput
&&
otherInput
.
forceOpenAsBinary
===
this
.
forceOpenAsBinary
;
super
(
name
,
description
,
originalInput
,
modifiedInput
);
}
getTypeId
():
string
{
return
DiffEditorInput
.
ID
;
}
get
originalInput
():
EditorInput
{
return
this
.
details
;
getName
():
string
{
if
(
!
this
.
name
)
{
return
localize
(
'
sideBySideLabels
'
,
"
{0} ↔ {1}
"
,
this
.
originalInput
.
getName
(),
this
.
modifiedInput
.
getName
());
}
get
modifiedInput
():
EditorInput
{
return
this
.
master
;
return
this
.
name
;
}
async
resolve
():
Promise
<
EditorModel
>
{
...
...
@@ -88,6 +81,14 @@ export class DiffEditorInput extends SideBySideEditorInput {
return
new
DiffEditorModel
(
originalEditorModel
,
modifiedEditorModel
);
}
matches
(
otherInput
:
unknown
):
boolean
{
if
(
!
super
.
matches
(
otherInput
))
{
return
false
;
}
return
otherInput
instanceof
DiffEditorInput
&&
otherInput
.
forceOpenAsBinary
===
this
.
forceOpenAsBinary
;
}
dispose
():
void
{
// Free the diff editor model but do not propagate the dispose() call to the two inputs
...
...
src/vs/workbench/common/editor/untitledTextEditorInput.ts
浏览文件 @
ceabb063
...
...
@@ -28,10 +28,14 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
private
static
readonly
MEMOIZER
=
createMemoizer
();
private
static
readonly
FIRST_LINE_MAX_TITLE_LENGTH
=
50
;
private
readonly
_onDidModelChangeEncoding
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onDidModelChangeEncoding
=
this
.
_onDidModelChangeEncoding
.
event
;
private
cachedModel
:
UntitledTextEditorModel
|
null
=
null
;
private
cachedModelFirstLine
:
string
|
undefined
=
undefined
;
private
modelResolve
:
Promise
<
UntitledTextEditorModel
&
IResolvedTextEditorModel
>
|
null
=
null
;
private
preferredMode
:
string
|
undefined
;
...
...
@@ -71,6 +75,15 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
}
getName
():
string
{
// Take name from first line if present and only if
// we have no associated file path. In that case we
// prefer the file name as title.
if
(
!
this
.
_hasAssociatedFilePath
&&
this
.
cachedModelFirstLine
)
{
return
this
.
cachedModelFirstLine
;
}
// Otherwise fallback to resource
return
this
.
hasAssociatedFilePath
?
basenameOrAuthority
(
this
.
resource
)
:
this
.
resource
.
path
;
}
...
...
@@ -278,11 +291,30 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
private
createModel
():
UntitledTextEditorModel
{
const
model
=
this
.
_register
(
this
.
instantiationService
.
createInstance
(
UntitledTextEditorModel
,
this
.
preferredMode
,
this
.
resource
,
this
.
hasAssociatedFilePath
,
this
.
initialValue
,
this
.
preferredEncoding
));
this
.
registerModelListeners
(
model
);
return
model
;
}
private
registerModelListeners
(
model
:
UntitledTextEditorModel
):
void
{
// re-emit some events from the model
this
.
_register
(
model
.
onDidChangeDirty
(()
=>
this
.
_onDidChangeDirty
.
fire
()));
this
.
_register
(
model
.
onDidChangeEncoding
(()
=>
this
.
_onDidModelChangeEncoding
.
fire
()));
return
model
;
// listen for first line change events if we use it for the label
// by checking the contents of the first line has changed
if
(
!
this
.
_hasAssociatedFilePath
)
{
this
.
_register
(
model
.
onDidChangeFirstLine
(()
=>
this
.
onDidChangeFirstLine
(
model
)));
}
}
private
onDidChangeFirstLine
(
model
:
UntitledTextEditorModel
):
void
{
const
firstLineText
=
model
.
textEditorModel
?.
getValueInRange
({
startLineNumber
:
1
,
endLineNumber
:
1
,
startColumn
:
1
,
endColumn
:
UntitledTextEditorInput
.
FIRST_LINE_MAX_TITLE_LENGTH
}).
trim
();
if
(
firstLineText
!==
this
.
cachedModelFirstLine
)
{
this
.
cachedModelFirstLine
=
firstLineText
;
this
.
_onDidChangeLabel
.
fire
();
}
}
matches
(
otherInput
:
unknown
):
boolean
{
...
...
src/vs/workbench/common/editor/untitledTextEditorModel.ts
浏览文件 @
ceabb063
...
...
@@ -16,6 +16,7 @@ import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
import
{
IResolvedTextEditorModel
,
ITextEditorModel
}
from
'
vs/editor/common/services/resolverService
'
;
import
{
IWorkingCopyService
,
IWorkingCopy
,
WorkingCopyCapabilities
}
from
'
vs/workbench/services/workingCopy/common/workingCopyService
'
;
import
{
ITextFileService
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
IModelContentChangedEvent
}
from
'
vs/editor/common/model/textModelEvents
'
;
export
interface
IUntitledTextEditorModel
extends
ITextEditorModel
,
IModeSupport
,
IEncodingSupport
,
IWorkingCopy
{
}
...
...
@@ -24,6 +25,9 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
private
readonly
_onDidChangeContent
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onDidChangeContent
=
this
.
_onDidChangeContent
.
event
;
private
readonly
_onDidChangeFirstLine
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onDidChangeFirstLine
=
this
.
_onDidChangeFirstLine
.
event
;
private
readonly
_onDidChangeDirty
=
this
.
_register
(
new
Emitter
<
void
>
());
readonly
onDidChangeDirty
=
this
.
_onDidChangeDirty
.
event
;
...
...
@@ -170,15 +174,22 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
const
textEditorModel
=
this
.
textEditorModel
!
;
// Listen to content changes
this
.
_register
(
textEditorModel
.
onDidChangeContent
(
()
=>
this
.
onModelContentChanged
(
)));
this
.
_register
(
textEditorModel
.
onDidChangeContent
(
e
=>
this
.
onModelContentChanged
(
e
)));
// Listen to mode changes
this
.
_register
(
textEditorModel
.
onDidChangeLanguage
(()
=>
this
.
onConfigurationChange
()));
// mode change can have impact on config
// If we have initial contents, make sure to emit this
// as the appropiate events to the outside.
if
(
backup
||
this
.
initialValue
)
{
this
.
_onDidChangeContent
.
fire
();
this
.
_onDidChangeFirstLine
.
fire
();
}
return
this
as
UntitledTextEditorModel
&
IResolvedTextEditorModel
;
}
private
onModelContentChanged
():
void
{
private
onModelContentChanged
(
e
:
IModelContentChangedEvent
):
void
{
if
(
!
this
.
isResolved
())
{
return
;
}
...
...
@@ -196,8 +207,13 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
this
.
setDirty
(
true
);
}
// Emit as event
// Emit as
general content change
event
this
.
_onDidChangeContent
.
fire
();
// Emit as first line change event depending on actual change
if
(
e
.
changes
.
some
(
change
=>
change
.
range
.
startLineNumber
===
1
||
change
.
range
.
endLineNumber
===
1
))
{
this
.
_onDidChangeFirstLine
.
fire
();
}
}
isReadonly
():
boolean
{
...
...
src/vs/workbench/contrib/backup/electron-browser/backupOnShutdown.ts
浏览文件 @
ceabb063
...
...
@@ -17,7 +17,7 @@ import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/
import
{
isMacintosh
}
from
'
vs/base/common/platform
'
;
import
{
HotExitConfiguration
}
from
'
vs/platform/files/common/files
'
;
import
{
IElectronService
}
from
'
vs/platform/electron/node/electron
'
;
import
type
{
ISaveOptions
,
IRevertOptions
}
from
'
vs/workbench/common/editor
'
;
import
{
ISaveOptions
,
IRevertOptions
}
from
'
vs/workbench/common/editor
'
;
export
class
BackupOnShutdown
extends
Disposable
implements
IWorkbenchContribution
{
...
...
src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts
浏览文件 @
ceabb063
...
...
@@ -32,6 +32,7 @@ import { toResource } from 'vs/base/test/common/utils';
import
{
IFilesConfigurationService
}
from
'
vs/workbench/services/filesConfiguration/common/filesConfigurationService
'
;
import
{
IWorkingCopyService
}
from
'
vs/workbench/services/workingCopy/common/workingCopyService
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
INewUntitledTextEditorOptions
}
from
'
vs/workbench/services/untitled/common/untitledTextEditorService
'
;
const
userdataDir
=
getRandomTestPath
(
os
.
tmpdir
(),
'
vsctests
'
,
'
backuprestorer
'
);
const
backupHome
=
path
.
join
(
userdataDir
,
'
Backups
'
);
...
...
@@ -118,16 +119,17 @@ suite('BackupTracker', () => {
return
[
accessor
,
part
,
tracker
];
}
test
(
'
Track backups (untitled)
'
,
async
function
()
{
this
.
timeout
(
20000
);
async
function
untitledBackupTest
(
options
?:
INewUntitledTextEditorOptions
):
Promise
<
void
>
{
const
[
accessor
,
part
,
tracker
]
=
await
createTracker
();
const
untitledEditor
=
accessor
.
textFileService
.
untitled
.
create
();
const
untitledEditor
=
accessor
.
textFileService
.
untitled
.
create
(
options
);
await
accessor
.
editorService
.
openEditor
(
untitledEditor
,
{
pinned
:
true
});
const
untitledModel
=
await
untitledEditor
.
resolve
();
if
(
!
options
?.
initialValue
)
{
untitledModel
.
textEditorModel
.
setValue
(
'
Super Good
'
);
}
await
accessor
.
backupFileService
.
joinBackupResource
();
...
...
@@ -141,6 +143,18 @@ suite('BackupTracker', () => {
part
.
dispose
();
tracker
.
dispose
();
}
test
(
'
Track backups (untitled)
'
,
function
()
{
this
.
timeout
(
20000
);
return
untitledBackupTest
();
});
test
(
'
Track backups (untitled with initial contents)
'
,
function
()
{
this
.
timeout
(
20000
);
return
untitledBackupTest
({
initialValue
:
'
Foo Bar
'
});
});
test
(
'
Track backups (file)
'
,
async
function
()
{
...
...
src/vs/workbench/services/editor/browser/editorService.ts
浏览文件 @
ceabb063
...
...
@@ -16,7 +16,6 @@ import { Event, Emitter } from 'vs/base/common/event';
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
basename
,
isEqual
}
from
'
vs/base/common/resources
'
;
import
{
DiffEditorInput
}
from
'
vs/workbench/common/editor/diffEditorInput
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
IEditorGroupsService
,
IEditorGroup
,
GroupsOrder
,
IEditorReplacement
,
GroupChangeKind
,
preferredSideBySideGroupDirection
}
from
'
vs/workbench/services/editor/common/editorGroupsService
'
;
import
{
IResourceEditor
,
SIDE_GROUP
,
IResourceEditorReplacement
,
IOpenEditorOverrideHandler
,
IVisibleEditor
,
IEditorService
,
SIDE_GROUP_TYPE
,
ACTIVE_GROUP_TYPE
,
ISaveEditorsOptions
,
ISaveAllEditorsOptions
,
IRevertAllEditorsOptions
,
IBaseSaveRevertAllEditorOptions
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
...
...
@@ -587,11 +586,10 @@ export class EditorService extends Disposable implements EditorServiceImpl {
if
(
resourceSideBySideInput
.
masterResource
&&
resourceSideBySideInput
.
detailResource
)
{
const
masterInput
=
this
.
createInput
({
resource
:
resourceSideBySideInput
.
masterResource
,
forceFile
:
resourceSideBySideInput
.
forceFile
});
const
detailInput
=
this
.
createInput
({
resource
:
resourceSideBySideInput
.
detailResource
,
forceFile
:
resourceSideBySideInput
.
forceFile
});
const
label
=
resourceSideBySideInput
.
label
||
masterInput
.
getName
()
||
localize
(
'
sideBySideLabels
'
,
"
{0} - {1}
"
,
this
.
toDiffLabel
(
masterInput
),
this
.
toDiffLabel
(
detailInput
));
return
new
SideBySideEditorInput
(
label
,
typeof
resourceSideBySideInput
.
description
===
'
string
'
?
resourceSideBySideInput
.
description
:
masterInput
.
getDescription
()
,
resourceSideBySideInput
.
label
||
this
.
toSideBySideLabel
(
detailInput
,
masterInput
,
'
-
'
)
,
resourceSideBySideInput
.
description
,
detailInput
,
masterInput
);
...
...
@@ -602,9 +600,13 @@ export class EditorService extends Disposable implements EditorServiceImpl {
if
(
resourceDiffInput
.
leftResource
&&
resourceDiffInput
.
rightResource
)
{
const
leftInput
=
this
.
createInput
({
resource
:
resourceDiffInput
.
leftResource
,
forceFile
:
resourceDiffInput
.
forceFile
});
const
rightInput
=
this
.
createInput
({
resource
:
resourceDiffInput
.
rightResource
,
forceFile
:
resourceDiffInput
.
forceFile
});
const
label
=
resourceDiffInput
.
label
||
localize
(
'
compareLabels
'
,
"
{0} ↔ {1}
"
,
this
.
toDiffLabel
(
leftInput
),
this
.
toDiffLabel
(
rightInput
));
return
new
DiffEditorInput
(
label
,
resourceDiffInput
.
description
,
leftInput
,
rightInput
);
return
new
DiffEditorInput
(
resourceDiffInput
.
label
||
this
.
toSideBySideLabel
(
leftInput
,
rightInput
,
'
↔
'
),
resourceDiffInput
.
description
,
leftInput
,
rightInput
);
}
// Untitled file support
...
...
@@ -687,19 +689,24 @@ export class EditorService extends Disposable implements EditorServiceImpl {
return
input
;
}
private
toDiffLabel
(
input
:
EditorInput
):
string
|
undefined
{
const
res
=
input
.
getResource
();
if
(
!
res
)
{
private
toSideBySideLabel
(
leftInput
:
EditorInput
,
rightInput
:
EditorInput
,
divider
:
string
):
string
|
undefined
{
const
leftResource
=
leftInput
.
getResource
();
const
rightResource
=
rightInput
.
getResource
();
// Without any resource, do not try to compute a label
if
(
!
leftResource
||
!
rightResource
)
{
return
undefined
;
}
// Do not try to extract any paths from simple untitled text editors
if
(
res
.
scheme
===
Schemas
.
untitled
&&
!
this
.
untitledTextEditorService
.
hasAssociatedFilePath
(
res
))
{
return
input
.
getName
();
// If both editors are file inputs, we produce an optimized label
// by adding the relative path of both inputs to the label. This
// makes it easier to understand a file-based comparison.
if
(
this
.
fileInputFactory
.
isFileInput
(
leftInput
)
&&
this
.
fileInputFactory
.
isFileInput
(
rightInput
))
{
return
`
${
this
.
labelService
.
getUriLabel
(
leftResource
,
{
relative
:
true
})}
${
divider
}
${
this
.
labelService
.
getUriLabel
(
rightResource
,
{
relative
:
true
})}
`
;
}
//
Otherwise: for diff labels prefer to see the path as part of the label
return
this
.
labelService
.
getUriLabel
(
res
,
{
relative
:
true
})
;
//
Signal back that the label should be computed from within the editor
return
undefined
;
}
//#endregion
...
...
src/vs/workbench/test/common/editor/untitledTextEditor.test.ts
浏览文件 @
ceabb063
...
...
@@ -16,6 +16,8 @@ import { snapshotToString } from 'vs/workbench/services/textfile/common/textfile
import
{
ModesRegistry
,
PLAINTEXT_MODE_ID
}
from
'
vs/editor/common/modes/modesRegistry
'
;
import
{
IWorkingCopyService
,
IWorkingCopy
}
from
'
vs/workbench/services/workingCopy/common/workingCopyService
'
;
import
{
IEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
IIdentifiedSingleEditOperation
}
from
'
vs/editor/common/model
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
class
ServiceAccessor
{
constructor
(
...
...
@@ -328,6 +330,62 @@ suite('Workbench untitled text editors', () => {
model
.
dispose
();
});
test
(
'
onDidChangeFirstLine event and input name
'
,
async
function
()
{
const
service
=
accessor
.
untitledTextEditorService
;
const
input
=
service
.
create
();
let
counter
=
0
;
let
model
=
await
input
.
resolve
();
model
.
onDidChangeFirstLine
(()
=>
counter
++
);
model
.
textEditorModel
.
setValue
(
'
foo
'
);
assert
.
equal
(
input
.
getName
(),
'
foo
'
);
assert
.
equal
(
counter
,
1
);
model
.
textEditorModel
.
setValue
(
'
bar
'
);
assert
.
equal
(
input
.
getName
(),
'
bar
'
);
assert
.
equal
(
counter
,
2
);
model
.
textEditorModel
.
setValue
(
''
);
assert
.
equal
(
input
.
getName
(),
'
Untitled-1
'
);
assert
.
equal
(
counter
,
3
);
model
.
textEditorModel
.
setValue
(
'
Hello
\n
World
'
);
assert
.
equal
(
counter
,
4
);
function
createSingleEditOp
(
text
:
string
,
positionLineNumber
:
number
,
positionColumn
:
number
,
selectionLineNumber
:
number
=
positionLineNumber
,
selectionColumn
:
number
=
positionColumn
):
IIdentifiedSingleEditOperation
{
let
range
=
new
Range
(
selectionLineNumber
,
selectionColumn
,
positionLineNumber
,
positionColumn
);
return
{
identifier
:
null
,
range
,
text
,
forceMoveMarkers
:
false
};
}
model
.
textEditorModel
.
applyEdits
([
createSingleEditOp
(
'
hello
'
,
2
,
2
)]);
assert
.
equal
(
counter
,
4
);
// change was not on first line
input
.
dispose
();
model
.
dispose
();
const
inputWithContents
=
service
.
create
({
initialValue
:
'
Foo
'
});
model
=
await
inputWithContents
.
resolve
();
assert
.
equal
(
inputWithContents
.
getName
(),
'
Foo
'
);
inputWithContents
.
dispose
();
model
.
dispose
();
});
test
(
'
onDidChangeDirty event
'
,
async
function
()
{
const
service
=
accessor
.
untitledTextEditorService
;
const
input
=
service
.
create
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录