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

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

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