提交 40fdd128 编写于 作者: B Benjamin Pasero

history: avoid typed input for editor history (for #13283)

上级 ee9bb45d
......@@ -190,9 +190,13 @@ export class FocusFirstGroupAction extends Action {
const history = this.historyService.getHistory();
for (let input of history) {
// For now only support to open resources from history to the side
if (!!getUntitledOrFileResource(input)) {
return this.editorService.openEditor(input, null, Position.LEFT);
// For now only support to open files from history to the side
if (input instanceof EditorInput) {
if (!!getUntitledOrFileResource(input)) {
return this.editorService.openEditor(input, null, Position.LEFT);
}
} else {
return this.editorService.openEditor(input as IResourceInput, Position.LEFT);
}
}
......@@ -259,8 +263,12 @@ export abstract class BaseFocusSideGroupAction extends Action {
for (let input of history) {
// For now only support to open files from history to the side
if (!!getUntitledOrFileResource(input)) {
return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide());
if (input instanceof EditorInput) {
if (!!getUntitledOrFileResource(input)) {
return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide());
}
} else {
return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: true } }, this.getTargetEditorSide());
}
}
}
......
......@@ -24,7 +24,9 @@ import {QuickOpenWidget, HideReason} from 'vs/base/parts/quickopen/browser/quick
import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry';
import labels = require('vs/base/common/labels');
import paths = require('vs/base/common/paths');
import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles';
import {Registry} from 'vs/platform/platform';
import {IResourceInput, IEditorInput} from 'vs/platform/editor/common/editor';
import {IModeService} from 'vs/editor/common/services/modeService';
import {getIconClasses} from 'vs/workbench/browser/labels';
import {IModelService} from 'vs/editor/common/services/modelService';
......@@ -744,14 +746,28 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe
const results: QuickOpenEntry[] = [];
history.forEach(input => {
const resource = getUntitledOrFileResource(input);
let resource: URI;
if (input instanceof EditorInput) {
resource = getUntitledOrFileResource(input);
} else {
resource = (input as IResourceInput).resource;
}
if (!resource) {
return; //For now, only support to match on inputs that provide resource information
}
let searchTargetToMatch: string;
if (searchInPath) {
searchTargetToMatch = labels.getPathLabel(resource, this.contextService);
} else if (input instanceof EditorInput) {
searchTargetToMatch = input.getName();
} else {
searchTargetToMatch = paths.basename((input as IResourceInput).resource.fsPath);
}
// Check if this entry is a match for the search value
const targetToMatch = searchInPath ? labels.getPathLabel(resource, this.contextService) : input.getName();
if (!filters.matchesFuzzy(searchValue, targetToMatch)) {
if (!filters.matchesFuzzy(searchValue, searchTargetToMatch)) {
return;
}
......@@ -1018,28 +1034,42 @@ export class EditorHistoryEntryGroup extends QuickOpenEntryGroup {
}
export class EditorHistoryEntry extends EditorQuickOpenEntry {
private input: EditorInput;
private input: IEditorInput | IResourceInput;
private resource: URI;
private label: string;
private description: string;
constructor(
input: EditorInput,
input: IEditorInput | IResourceInput,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IModeService private modeService: IModeService,
@IModelService private modelService: IModelService,
@ITextFileService private textFileService: ITextFileService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IConfigurationService private configurationService: IConfigurationService
) {
super(editorService);
this.input = input;
this.resource = getUntitledOrFileResource(input);
if (input instanceof EditorInput) {
this.resource = getUntitledOrFileResource(input);
this.label = input.getName();
this.description = input.getDescription();
} else {
const resourceInput = input as IResourceInput;
this.resource = resourceInput.resource;
this.label = paths.basename(resourceInput.resource.fsPath);
this.description = labels.getPathLabel(paths.dirname(this.resource.fsPath), contextService);
}
}
public getIcon(): string {
return this.input.isDirty() ? 'dirty' : '';
return this.resource && this.textFileService.isDirty(this.resource) ? 'dirty' : '';
}
public getLabel(): string {
return this.input.getName();
return this.label;
}
public getLabelOptions(): IIconLabelOptions {
......@@ -1053,27 +1083,27 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry {
}
public getDescription(): string {
return this.input.getDescription();
return this.description;
}
public getResource(): URI {
return this.resource;
}
public getInput(): EditorInput {
public getInput(): IEditorInput | IResourceInput {
return this.input;
}
public matches(input: EditorInput): boolean {
return this.input.matches(input);
}
public run(mode: Mode, context: IEntryRunContext): boolean {
if (mode === Mode.OPEN) {
const sideBySide = !context.quickNavigateConfiguration && context.keymods.indexOf(KeyMod.CtrlCmd) >= 0;
const pinned = !this.configurationService.getConfiguration<IWorkbenchEditorConfiguration>().workbench.editor.enablePreviewFromQuickOpen;
this.editorService.openEditor(this.input, { pinned }, sideBySide).done(null, errors.onUnexpectedError);
if (this.input instanceof EditorInput) {
this.editorService.openEditor(this.input, { pinned }, sideBySide).done(null, errors.onUnexpectedError);
} else {
this.editorService.openEditor({ resource: (this.input as IResourceInput).resource, options: { pinned: true } }, sideBySide);
}
return true;
}
......
......@@ -70,11 +70,15 @@ export class EditorState {
}
}
interface ISerializedEditorInput {
interface ILegacySerializedEditorInput {
id: string;
value: string;
}
interface ISerializedFileEditorInput {
resource: string;
}
export abstract class BaseHistoryService {
protected toUnbind: IDisposable[];
......@@ -246,7 +250,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
private blockStackChanges: boolean;
private currentFileEditorState: EditorState;
private history: IEditorInput[];
private history: (IEditorInput|IResourceInput)[];
private recentlyClosedFiles: IRecentlyClosedFile[];
private loaded: boolean;
private registry: IEditorRegistry;
......@@ -351,8 +355,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
if (entry.input instanceof EditorInput) {
openEditorPromise = this.editorService.openEditor(entry.input, options);
} else {
const resourceInput = entry.input as IResourceInput;
openEditorPromise = this.editorService.openEditor({ resource: resourceInput.resource, options });
openEditorPromise = this.editorService.openEditor({ resource: (entry.input as IResourceInput).resource, options });
}
openEditorPromise.done(() => {
......@@ -382,37 +385,24 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
this.ensureLoaded();
const historyInput = this.preferResourceInput(input);
// Remove any existing entry and add to the beginning
this.removeFromHistory(input);
this.history.unshift(input);
this.history.unshift(historyInput);
// Respect max entries setting
if (this.history.length > HistoryService.MAX_HISTORY_ITEMS) {
this.history.pop();
}
// Restore on dispose
const onceDispose = once(input.onDispose);
onceDispose(() => {
this.restoreInHistory(input);
});
}
private restoreInHistory(input: IEditorInput): void {
const index = this.indexOf(input);
if (index < 0) {
return;
}
// Using the factory we try to recreate the input
const restoredInput = this.restoreInput(input);
if (restoredInput) {
this.history[index] = restoredInput;
}
// Factory failed, just remove entry then
else {
this.removeFromHistory(input, index);
// Remove this from the history unless the history input is a resource
// that can easily be restored even when the input gets disposed
if (historyInput instanceof EditorInput) {
const onceDispose = once(historyInput.onDispose);
onceDispose(() => {
this.removeFromHistory(input);
});
}
}
......@@ -437,7 +427,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
private indexOf(input: IEditorInput): number {
for (let i = 0; i < this.history.length; i++) {
const entry = this.history[i];
if (entry.matches(input)) {
if (this.matches(input, entry)) {
return i;
}
}
......@@ -577,20 +567,6 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
return s1.startLineNumber === s2.startLineNumber; // we consider the history entry same if we are on the same line
}
private restoreInput(input: IEditorInput): EditorInput {
if (input instanceof EditorInput) {
const factory = this.registry.getEditorInputFactory(input.getTypeId());
if (factory) {
const inputRaw = factory.serialize(input);
if (inputRaw) {
return factory.deserialize(this.instantiationService, inputRaw);
}
}
}
return null;
}
private removeFromStack(input: IEditorInput): void {
this.stack.forEach((e, i) => {
if (this.matches(input, e.input)) {
......@@ -627,9 +603,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
return input.matches(typedInput);
}
const resourceInput = input as IResourceInput;
return this.matchesFile(resourceInput.resource, typedInput);
return this.matchesFile((input as IResourceInput).resource, typedInput);
}
private matchesFile(resource: URI, input: IEditorInput): boolean {
......@@ -638,7 +612,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
return fileInput && fileInput.getResource().toString() === resource.toString();
}
public getHistory(): IEditorInput[] {
public getHistory(): (IEditorInput|IResourceInput)[] {
this.ensureLoaded();
return this.history.slice(0);
......@@ -657,35 +631,45 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
return; // nothing to save because history was not used
}
const entries: ISerializedEditorInput[] = this.history.map((input: EditorInput) => {
const factory = this.registry.getEditorInputFactory(input.getTypeId());
if (factory) {
const value = factory.serialize(input);
if (typeof value === 'string') {
return {
id: input.getTypeId(),
value: value
};
}
const entries: ISerializedFileEditorInput[] = this.history.map(input => {
if (input instanceof EditorInput) {
return void 0; // only file resource inputs are serializable currently
}
return void 0;
return { resource: (input as IResourceInput).resource.toString() };
}).filter(serialized => !!serialized);
this.storageService.store(HistoryService.STORAGE_KEY, JSON.stringify(entries), StorageScope.WORKSPACE);
}
private load(): void {
let entries: ISerializedEditorInput[] = [];
let entries: (ILegacySerializedEditorInput|ISerializedFileEditorInput)[] = [];
const entriesRaw = this.storageService.get(HistoryService.STORAGE_KEY, StorageScope.WORKSPACE);
if (entriesRaw) {
entries = JSON.parse(entriesRaw);
}
this.history = entries.map(entry => {
const factory = this.registry.getEditorInputFactory(entry.id);
if (factory && typeof entry.value === 'string') {
return factory.deserialize(this.instantiationService, entry.value);
const serializedLegacyInput = entry as ILegacySerializedEditorInput;
const serializedFileInput = entry as ISerializedFileEditorInput;
// Legacy support (TODO@Ben remove me - migration)
if (serializedLegacyInput.id) {
const factory = this.registry.getEditorInputFactory(serializedLegacyInput.id);
if (factory && typeof serializedLegacyInput.value === 'string') {
const fileInput = asFileEditorInput(factory.deserialize(this.instantiationService, serializedLegacyInput.value));
if (fileInput) {
return { resource: fileInput.getResource() } as IResourceInput;
}
return void 0;
}
}
// New resource input support
else if (serializedFileInput.resource) {
return { resource: URI.parse(serializedFileInput.resource) } as IResourceInput;
}
return void 0;
......
......@@ -5,7 +5,7 @@
'use strict';
import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
import {IEditorInput, ITextEditorOptions} from 'vs/platform/editor/common/editor';
import {IEditorInput, ITextEditorOptions, IResourceInput} from 'vs/platform/editor/common/editor';
export const IHistoryService = createDecorator<IHistoryService>('historyService');
......@@ -46,5 +46,5 @@ export interface IHistoryService {
/**
* Get the entire history of opened editors.
*/
getHistory(): IEditorInput[];
getHistory(): (IEditorInput|IResourceInput)[];
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册