Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
1eac96d1
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,发现更多精彩内容 >>
提交
1eac96d1
编写于
6月 09, 2020
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
history - use editor input factory to support to reopen any editor that can be serialised
上级
516bb5fd
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
139 addition
and
88 deletion
+139
-88
src/vs/base/common/arrays.ts
src/vs/base/common/arrays.ts
+15
-6
src/vs/base/test/common/arrays.test.ts
src/vs/base/test/common/arrays.test.ts
+9
-0
src/vs/workbench/browser/parts/editor/editor.contribution.ts
src/vs/workbench/browser/parts/editor/editor.contribution.ts
+3
-3
src/vs/workbench/common/editor.ts
src/vs/workbench/common/editor.ts
+1
-1
src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts
...contrib/searchEditor/browser/searchEditor.contribution.ts
+3
-1
src/vs/workbench/services/history/browser/history.ts
src/vs/workbench/services/history/browser/history.ts
+108
-77
未找到文件。
src/vs/base/common/arrays.ts
浏览文件 @
1eac96d1
...
...
@@ -489,12 +489,21 @@ export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string,
export
function
insert
<
T
>
(
array
:
T
[],
element
:
T
):
()
=>
void
{
array
.
push
(
element
);
return
()
=>
{
const
index
=
array
.
indexOf
(
element
);
if
(
index
>
-
1
)
{
array
.
splice
(
index
,
1
);
}
};
return
()
=>
remove
(
array
,
element
);
}
/**
* Removes an element from an array if it can be found.
*/
export
function
remove
<
T
>
(
array
:
T
[],
element
:
T
):
T
|
undefined
{
const
index
=
array
.
indexOf
(
element
);
if
(
index
>
-
1
)
{
array
.
splice
(
index
,
1
);
return
element
;
}
return
undefined
;
}
/**
...
...
src/vs/base/test/common/arrays.test.ts
浏览文件 @
1eac96d1
...
...
@@ -342,5 +342,14 @@ suite('Arrays', () => {
arrays
.
coalesceInPlace
(
sparse
);
assert
.
equal
(
sparse
.
length
,
5
);
});
test
(
'
insert, remove
'
,
function
()
{
const
array
:
string
[]
=
[];
const
remove
=
arrays
.
insert
(
array
,
'
foo
'
);
assert
.
equal
(
array
[
0
],
'
foo
'
);
remove
();
assert
.
equal
(
array
.
length
,
0
);
});
});
src/vs/workbench/browser/parts/editor/editor.contribution.ts
浏览文件 @
1eac96d1
...
...
@@ -118,12 +118,12 @@ class UntitledTextEditorInputFactory implements IEditorInputFactory {
)
{
}
canSerialize
(
editorInput
:
EditorInput
):
boolean
{
return
this
.
filesConfigurationService
.
isHotExitEnabled
;
return
this
.
filesConfigurationService
.
isHotExitEnabled
&&
!
editorInput
.
isDisposed
()
;
}
serialize
(
editorInput
:
EditorInput
):
string
|
undefined
{
if
(
!
this
.
filesConfigurationService
.
isHotExitEnabled
)
{
return
undefined
;
// never restore untitled unless hot exit is enabled
if
(
!
this
.
filesConfigurationService
.
isHotExitEnabled
||
editorInput
.
isDisposed
()
)
{
return
undefined
;
}
const
untitledTextEditorInput
=
<
UntitledTextEditorInput
>
editorInput
;
...
...
src/vs/workbench/common/editor.ts
浏览文件 @
1eac96d1
...
...
@@ -235,7 +235,7 @@ export interface IEditorInputFactory {
* Returns a string representation of the provided editor input that contains enough information
* to deserialize back to the original editor input from the deserialize() method.
*/
serialize
(
editorInput
:
EditorInput
):
string
|
undefined
;
serialize
(
editorInput
:
I
EditorInput
):
string
|
undefined
;
/**
* Returns an editor input from the provided serialized form of the editor input. This form matches
...
...
src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts
浏览文件 @
1eac96d1
...
...
@@ -109,7 +109,9 @@ workbenchContributionsRegistry.registerWorkbenchContribution(SearchEditorContrib
type
SerializedSearchEditor
=
{
modelUri
:
string
,
dirty
:
boolean
,
config
:
SearchConfiguration
,
name
:
string
,
matchRanges
:
Range
[],
backingUri
:
string
};
class
SearchEditorInputFactory
implements
IEditorInputFactory
{
canSerialize
()
{
return
true
;
}
canSerialize
(
input
:
SearchEditorInput
)
{
return
!
input
.
isDisposed
();
}
serialize
(
input
:
SearchEditorInput
)
{
let
modelUri
=
undefined
;
...
...
src/vs/workbench/services/history/browser/history.ts
浏览文件 @
1eac96d1
...
...
@@ -6,7 +6,7 @@
import
{
URI
,
UriComponents
}
from
'
vs/base/common/uri
'
;
import
{
IEditor
}
from
'
vs/editor/common/editorCommon
'
;
import
{
ITextEditorOptions
,
IResourceEditorInput
,
TextEditorSelectionRevealType
,
IEditorOptions
}
from
'
vs/platform/editor/common/editor
'
;
import
{
IEditorInput
,
IEditorPane
,
Extensions
as
EditorExtensions
,
EditorInput
,
IEditorCloseEvent
,
IEditorInputFactoryRegistry
,
toResource
,
IEditorIdentifier
,
GroupIdentifier
,
EditorsOrder
}
from
'
vs/workbench/common/editor
'
;
import
{
IEditorInput
,
IEditorPane
,
Extensions
as
EditorExtensions
,
EditorInput
,
IEditorCloseEvent
,
IEditorInputFactoryRegistry
,
toResource
,
IEditorIdentifier
,
GroupIdentifier
,
EditorsOrder
,
SideBySideEditor
}
from
'
vs/workbench/common/editor
'
;
import
{
IEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
IHistoryService
}
from
'
vs/workbench/services/history/common/history
'
;
import
{
FileChangesEvent
,
IFileService
,
FileChangeType
}
from
'
vs/platform/files/common/files
'
;
...
...
@@ -17,7 +17,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import
{
Registry
}
from
'
vs/platform/registry/common/platform
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
IEditorGroupsService
,
IEditorGroup
}
from
'
vs/workbench/services/editor/common/editorGroupsService
'
;
import
{
IEditorGroupsService
}
from
'
vs/workbench/services/editor/common/editorGroupsService
'
;
import
{
getCodeEditor
,
ICodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
createResourceExcludeMatcher
}
from
'
vs/workbench/services/search/common/search
'
;
import
{
ICursorPositionChangedEvent
}
from
'
vs/editor/common/controller/cursorEvents
'
;
...
...
@@ -25,13 +25,12 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import
{
EditorServiceImpl
}
from
'
vs/workbench/browser/parts/editor/editor
'
;
import
{
IWorkbenchLayoutService
}
from
'
vs/workbench/services/layout/browser/layoutService
'
;
import
{
IContextKeyService
,
RawContextKey
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
coalesce
}
from
'
vs/base/common/arrays
'
;
import
{
coalesce
,
remove
}
from
'
vs/base/common/arrays
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
import
{
withNullAsUndefined
}
from
'
vs/base/common/types
'
;
import
{
addDisposableListener
,
EventType
,
EventHelper
}
from
'
vs/base/browser/dom
'
;
import
{
IWorkspacesService
}
from
'
vs/platform/workspaces/common/workspaces
'
;
import
{
Schemas
}
from
'
vs/base/common/network
'
;
import
{
isEqual
}
from
'
vs/base/common/resources
'
;
import
{
onUnexpectedError
}
from
'
vs/base/common/errors
'
;
/**
...
...
@@ -85,8 +84,10 @@ interface IStackEntry {
selection
?:
Selection
;
}
interface
IRecentlyClosedFile
{
resource
:
URI
;
interface
IRecentlyClosedEditor
{
resource
:
URI
|
undefined
;
associatedResources
:
URI
[];
serialized
:
{
typeId
:
string
,
value
:
string
};
index
:
number
;
sticky
:
boolean
;
}
...
...
@@ -101,6 +102,8 @@ export class HistoryService extends Disposable implements IHistoryService {
private
readonly
editorHistoryListeners
=
new
Map
();
private
readonly
editorStackListeners
=
new
Map
();
private
readonly
editorInputFactory
=
Registry
.
as
<
IEditorInputFactoryRegistry
>
(
EditorExtensions
.
EditorInputFactories
);
constructor
(
@
IEditorService
private
readonly
editorService
:
EditorServiceImpl
,
@
IEditorGroupsService
private
readonly
editorGroupService
:
IEditorGroupsService
,
...
...
@@ -260,7 +263,7 @@ export class HistoryService extends Disposable implements IHistoryService {
remove
(
arg1
:
IEditorInput
|
IResourceEditorInput
|
FileChangesEvent
):
void
{
this
.
removeFromHistory
(
arg1
);
this
.
removeFromNavigationStack
(
arg1
);
this
.
removeFromRecentlyClosed
File
s
(
arg1
);
this
.
removeFromRecentlyClosed
Editor
s
(
arg1
);
this
.
removeFromRecentlyOpened
(
arg1
);
}
...
...
@@ -286,8 +289,8 @@ export class HistoryService extends Disposable implements IHistoryService {
this
.
editorStackListeners
.
forEach
(
listeners
=>
dispose
(
listeners
));
this
.
editorStackListeners
.
clear
();
//
Closed file
s
this
.
recentlyClosed
File
s
=
[];
//
Recently closed editor
s
this
.
recentlyClosed
Editor
s
=
[];
// Context Keys
this
.
updateContextKeys
();
...
...
@@ -602,88 +605,120 @@ export class HistoryService extends Disposable implements IHistoryService {
//#endregion
//#region Recently Closed
File
s
//#region Recently Closed
Editor
s
private
static
readonly
MAX_RECENTLY_CLOSED_EDITORS
=
20
;
private
recentlyClosed
Files
:
IRecentlyClosedFile
[]
=
[];
private
recentlyClosed
Editors
:
IRecentlyClosedEditor
[]
=
[];
private
onEditorClosed
(
event
:
IEditorCloseEvent
):
void
{
const
{
editor
,
replaced
}
=
event
;
if
(
replaced
)
{
return
;
// ignore if editor was replaced
}
const
factory
=
this
.
editorInputFactory
.
getEditorInputFactory
(
editor
.
getTypeId
());
if
(
!
factory
||
!
factory
.
canSerialize
(
editor
))
{
return
;
// we need a factory from this point that can serialize this editor
}
// Track closing of editor to support to reopen closed editors (unless editor was replaced)
if
(
!
event
.
replaced
)
{
const
resource
=
event
.
editor
?
event
.
editor
.
resource
:
undefined
;
const
supportsReopen
=
resource
&&
this
.
fileService
.
canHandleResource
(
resource
);
// we only support file'ish things to reopen
if
(
resource
&&
supportsReopen
)
{
const
serialized
=
factory
.
serialize
(
editor
);
if
(
typeof
serialized
!==
'
string
'
)
{
return
;
// we need something to deserialize from
}
// Remove all inputs matching and add as last recently closed
this
.
removeFromRecentlyClosedFiles
(
event
.
editor
);
this
.
recentlyClosedFiles
.
push
({
resource
,
index
:
event
.
index
,
sticky
:
event
.
sticky
});
const
associatedResources
:
URI
[]
=
[];
const
editorResource
=
toResource
(
editor
,
{
supportSideBySide
:
SideBySideEditor
.
BOTH
});
if
(
URI
.
isUri
(
editorResource
))
{
associatedResources
.
push
(
editorResource
);
}
else
if
(
editorResource
)
{
associatedResources
.
push
(...
coalesce
([
editorResource
.
master
,
editorResource
.
detail
]));
}
// Bounding
if
(
this
.
recentlyClosedFiles
.
length
>
HistoryService
.
MAX_RECENTLY_CLOSED_EDITORS
)
{
this
.
recentlyClosedFiles
.
shift
();
}
// Remove from list of recently closed before...
this
.
removeFromRecentlyClosedEditors
(
editor
);
// Context
this
.
canReopenClosedEditorContextKey
.
set
(
true
);
}
// ...adding it as last recently closed
this
.
recentlyClosedEditors
.
push
({
resource
:
editor
.
resource
,
associatedResources
,
serialized
:
{
typeId
:
editor
.
getTypeId
(),
value
:
serialized
},
index
:
event
.
index
,
sticky
:
event
.
sticky
});
// Bounding
if
(
this
.
recentlyClosedEditors
.
length
>
HistoryService
.
MAX_RECENTLY_CLOSED_EDITORS
)
{
this
.
recentlyClosedEditors
.
shift
();
}
// Context
this
.
canReopenClosedEditorContextKey
.
set
(
true
);
}
reopenLastClosedEditor
():
void
{
let
lastClosedFile
=
this
.
recentlyClosedFiles
.
pop
();
while
(
lastClosedFile
&&
this
.
containsRecentlyClosedFile
(
this
.
editorGroupService
.
activeGroup
,
lastClosedFile
))
{
lastClosedFile
=
this
.
recentlyClosedFiles
.
pop
();
// pop until we find a file that is not opened
}
if
(
lastClosedFile
)
{
(
async
()
=>
{
let
options
:
IEditorOptions
;
if
(
lastClosedFile
.
sticky
)
{
// Sticky: in case the target index is outside of the range of
// sticky editors, we make sure to not provide the index as
// option. Otherwise the index will cause the sticky flag to
// be ignored.
if
(
!
this
.
editorGroupService
.
activeGroup
.
isSticky
(
lastClosedFile
.
index
))
{
options
=
{
pinned
:
true
,
sticky
:
true
};
}
else
{
options
=
{
pinned
:
true
,
sticky
:
true
,
index
:
lastClosedFile
.
index
};
}
}
else
{
options
=
{
pinned
:
true
,
index
:
lastClosedFile
.
index
};
}
const
editor
=
await
this
.
editorService
.
openEditor
({
resource
:
lastClosedFile
.
resource
,
options
});
// Fix for https://github.com/Microsoft/vscode/issues/67882
// If opening of the editor fails, make sure to try the next one
// but make sure to remove this one from the list to prevent
// endless loops.
if
(
!
editor
)
{
this
.
recentlyClosedFiles
.
pop
();
this
.
reopenLastClosedEditor
();
}
})();
// Open editor if we have one
const
lastClosedEditor
=
this
.
recentlyClosedEditors
.
pop
();
if
(
lastClosedEditor
)
{
this
.
doReopenLastClosedEditor
(
lastClosedEditor
);
}
//
C
ontext
this
.
canReopenClosedEditorContextKey
.
set
(
this
.
recentlyClosed
File
s
.
length
>
0
);
//
Update c
ontext
this
.
canReopenClosedEditorContextKey
.
set
(
this
.
recentlyClosed
Editor
s
.
length
>
0
);
}
private
containsRecentlyClosedFile
(
group
:
IEditorGroup
,
recentlyClosedEditor
:
IRecentlyClosedFile
):
boolean
{
for
(
const
editor
of
group
.
editors
)
{
if
(
isEqual
(
editor
.
resource
,
recentlyClosedEditor
.
resource
))
{
return
true
;
private
async
doReopenLastClosedEditor
(
lastClosedEditor
:
IRecentlyClosedEditor
):
Promise
<
void
>
{
// Determine editor options
let
options
:
IEditorOptions
;
if
(
lastClosedEditor
.
sticky
)
{
// Sticky: in case the target index is outside of the range of
// sticky editors, we make sure to not provide the index as
// option. Otherwise the index will cause the sticky flag to
// be ignored.
if
(
!
this
.
editorGroupService
.
activeGroup
.
isSticky
(
lastClosedEditor
.
index
))
{
options
=
{
pinned
:
true
,
sticky
:
true
,
ignoreError
:
true
};
}
else
{
options
=
{
pinned
:
true
,
sticky
:
true
,
index
:
lastClosedEditor
.
index
,
ignoreError
:
true
};
}
}
else
{
options
=
{
pinned
:
true
,
index
:
lastClosedEditor
.
index
,
ignoreError
:
true
};
}
return
false
;
// Deserialize and open editor unless already opened
const
restoredEditor
=
this
.
editorInputFactory
.
getEditorInputFactory
(
lastClosedEditor
.
serialized
.
typeId
)?.
deserialize
(
this
.
instantiationService
,
lastClosedEditor
.
serialized
.
value
);
let
editorPane
:
IEditorPane
|
undefined
=
undefined
;
if
(
restoredEditor
&&
!
this
.
editorGroupService
.
activeGroup
.
isOpened
(
restoredEditor
))
{
editorPane
=
await
this
.
editorService
.
openEditor
(
restoredEditor
,
options
);
}
// If no editor was opened, try with the next one
if
(
!
editorPane
)
{
// Fix for https://github.com/Microsoft/vscode/issues/67882
// If opening of the editor fails, make sure to try the next one
// but make sure to remove this one from the list to prevent
// endless loops.
remove
(
this
.
recentlyClosedEditors
,
lastClosedEditor
);
this
.
reopenLastClosedEditor
();
}
}
private
removeFromRecentlyClosedFiles
(
arg1
:
IEditorInput
|
IResourceEditorInput
|
FileChangesEvent
):
void
{
this
.
recentlyClosedFiles
=
this
.
recentlyClosedFiles
.
filter
(
e
=>
!
this
.
matchesFile
(
e
.
resource
,
arg1
));
this
.
canReopenClosedEditorContextKey
.
set
(
this
.
recentlyClosedFiles
.
length
>
0
);
private
removeFromRecentlyClosedEditors
(
arg1
:
IEditorInput
|
IResourceEditorInput
|
FileChangesEvent
):
void
{
this
.
recentlyClosedEditors
=
this
.
recentlyClosedEditors
.
filter
(
recentlyClosedEditor
=>
{
if
(
recentlyClosedEditor
.
resource
&&
this
.
matchesFile
(
recentlyClosedEditor
.
resource
,
arg1
))
{
return
false
;
// editor matches directly
}
if
(
recentlyClosedEditor
.
associatedResources
.
some
(
associatedResource
=>
this
.
matchesFile
(
associatedResource
,
arg1
)))
{
return
false
;
// an associated resource matches
}
return
true
;
});
// Update context
this
.
canReopenClosedEditorContextKey
.
set
(
this
.
recentlyClosedEditors
.
length
>
0
);
}
//#endregion
...
...
@@ -721,7 +756,7 @@ export class HistoryService extends Disposable implements IHistoryService {
this
.
canNavigateBackContextKey
.
set
(
this
.
navigationStack
.
length
>
0
&&
this
.
navigationStackIndex
>
0
);
this
.
canNavigateForwardContextKey
.
set
(
this
.
navigationStack
.
length
>
0
&&
this
.
navigationStackIndex
<
this
.
navigationStack
.
length
-
1
);
this
.
canNavigateToLastEditLocationContextKey
.
set
(
!!
this
.
lastEditLocation
);
this
.
canReopenClosedEditorContextKey
.
set
(
this
.
recentlyClosed
File
s
.
length
>
0
);
this
.
canReopenClosedEditorContextKey
.
set
(
this
.
recentlyClosed
Editor
s
.
length
>
0
);
}
//#endregion
...
...
@@ -833,18 +868,16 @@ export class HistoryService extends Disposable implements IHistoryService {
}
}
const
registry
=
Registry
.
as
<
IEditorInputFactoryRegistry
>
(
EditorExtensions
.
EditorInputFactories
);
return
coalesce
(
entries
.
map
(
entry
=>
{
try
{
return
this
.
safeLoadHistoryEntry
(
registry
,
entry
);
return
this
.
safeLoadHistoryEntry
(
entry
);
}
catch
(
error
)
{
return
undefined
;
// https://github.com/Microsoft/vscode/issues/60960
}
}));
}
private
safeLoadHistoryEntry
(
registry
:
IEditorInputFactoryRegistry
,
entry
:
ISerializedEditorHistoryEntry
):
IEditorInput
|
IResourceEditorInput
|
undefined
{
private
safeLoadHistoryEntry
(
entry
:
ISerializedEditorHistoryEntry
):
IEditorInput
|
IResourceEditorInput
|
undefined
{
const
serializedEditorHistoryEntry
=
entry
;
// File resource: via URI.revive()
...
...
@@ -855,7 +888,7 @@ export class HistoryService extends Disposable implements IHistoryService {
// Editor input: via factory
const
{
editorInputJSON
}
=
serializedEditorHistoryEntry
;
if
(
editorInputJSON
?.
deserialized
)
{
const
factory
=
regist
ry
.
getEditorInputFactory
(
editorInputJSON
.
typeId
);
const
factory
=
this
.
editorInputFacto
ry
.
getEditorInputFactory
(
editorInputJSON
.
typeId
);
if
(
factory
)
{
const
input
=
factory
.
deserialize
(
this
.
instantiationService
,
editorInputJSON
.
deserialized
);
if
(
input
)
{
...
...
@@ -874,13 +907,11 @@ export class HistoryService extends Disposable implements IHistoryService {
return
;
// nothing to save because history was not used
}
const
registry
=
Registry
.
as
<
IEditorInputFactoryRegistry
>
(
EditorExtensions
.
EditorInputFactories
);
const
entries
:
ISerializedEditorHistoryEntry
[]
=
coalesce
(
this
.
history
.
map
((
input
):
ISerializedEditorHistoryEntry
|
undefined
=>
{
// Editor input: try via factory
if
(
input
instanceof
EditorInput
)
{
const
factory
=
regist
ry
.
getEditorInputFactory
(
input
.
getTypeId
());
const
factory
=
this
.
editorInputFacto
ry
.
getEditorInputFactory
(
input
.
getTypeId
());
if
(
factory
)
{
const
deserialized
=
factory
.
serialize
(
input
);
if
(
deserialized
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录