mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
history - allow to rename entries
This commit is contained in:
@@ -21,6 +21,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ResourceContextKey } from 'vs/workbench/common/contextkeys';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
export const LOCAL_HISTORY_MENU_CONTEXT_VALUE = 'localHistory:item';
|
||||
export const LOCAL_HISTORY_MENU_CONTEXT_KEY = ContextKeyExpr.equals('timelineItem', LOCAL_HISTORY_MENU_CONTEXT_VALUE);
|
||||
@@ -230,6 +231,45 @@ async function restore(accessor: ServicesAccessor, item: ITimelineCommandArgumen
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Rename
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.action.localHistory.rename',
|
||||
title: { value: localize('localHistory.rename', "Rename"), original: 'Rename' },
|
||||
menu: {
|
||||
id: MenuId.TimelineItemContext,
|
||||
group: '3_edit',
|
||||
order: 1,
|
||||
when: LOCAL_HISTORY_MENU_CONTEXT_KEY
|
||||
}
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor, item: ITimelineCommandArgument): Promise<void> {
|
||||
const workingCopyHistoryService = accessor.get(IWorkingCopyHistoryService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
|
||||
const { entry } = await findLocalHistoryEntry(workingCopyHistoryService, item);
|
||||
if (entry) {
|
||||
const inputBox = quickInputService.createInputBox();
|
||||
inputBox.title = localize('renameLocalHistoryEntryTitle', "Rename Local History Entry");
|
||||
inputBox.ignoreFocusOut = true;
|
||||
inputBox.placeholder = localize('renameLocalHistoryPlaceholder', "Enter the new name of the local history entry");
|
||||
inputBox.value = SaveSourceRegistry.getSourceLabel(entry.source) ?? entry.source;
|
||||
inputBox.show();
|
||||
inputBox.onDidAccept(() => {
|
||||
if (inputBox.value) {
|
||||
workingCopyHistoryService.updateEntry(entry, { source: inputBox.value }, CancellationToken.None);
|
||||
}
|
||||
inputBox.dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Delete
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
@@ -240,7 +280,7 @@ registerAction2(class extends Action2 {
|
||||
menu: {
|
||||
id: MenuId.TimelineItemContext,
|
||||
group: '3_edit',
|
||||
order: 1,
|
||||
order: 2,
|
||||
when: LOCAL_HISTORY_MENU_CONTEXT_KEY
|
||||
}
|
||||
});
|
||||
|
||||
@@ -78,6 +78,7 @@ export class LocalHistoryTimeline extends Disposable implements IWorkbenchContri
|
||||
|
||||
// History changes
|
||||
this._register(this.workingCopyHistoryService.onDidAddEntry(e => this.onDidChangeWorkingCopyHistoryEntry(e.entry, false /* entry added */)));
|
||||
this._register(this.workingCopyHistoryService.onDidChangeEntry(e => this.onDidChangeWorkingCopyHistoryEntry(e.entry, false /* entry changed */)));
|
||||
this._register(this.workingCopyHistoryService.onDidRemoveEntry(e => this.onDidChangeWorkingCopyHistoryEntry(e.entry, true /* entry removed */)));
|
||||
this._register(this.workingCopyHistoryService.onDidRemoveAllEntries(() => this.onDidChangeWorkingCopyHistoryEntry(undefined /* all history */, true /* entry removed */)));
|
||||
|
||||
|
||||
@@ -28,6 +28,13 @@ class BrowserWorkingCopyHistoryModel extends WorkingCopyHistoryModel {
|
||||
return entry;
|
||||
}
|
||||
|
||||
override async updateEntry(entry: IWorkingCopyHistoryEntry, properties: { source: SaveSource }, token: CancellationToken): Promise<void> {
|
||||
await super.updateEntry(entry, properties, token);
|
||||
if (!token.isCancellationRequested) {
|
||||
await this.store(); // need to store on each remove because we do not have long running shutdown support in web
|
||||
}
|
||||
}
|
||||
|
||||
override async removeEntry(entry: IWorkingCopyHistoryEntry, token: CancellationToken): Promise<boolean> {
|
||||
const removed = await super.removeEntry(entry, token);
|
||||
if (removed && !token.isCancellationRequested) {
|
||||
@@ -53,7 +60,7 @@ export class BrowserWorkingCopyHistoryService extends WorkingCopyHistoryService
|
||||
}
|
||||
|
||||
protected override createModel(resource: URI, historyHome: URI): WorkingCopyHistoryModel {
|
||||
return new BrowserWorkingCopyHistoryModel(resource, historyHome, this._onDidAddEntry, this._onDidRemoveEntry, this.fileService, this.labelService, this.logService, this.configurationService);
|
||||
return new BrowserWorkingCopyHistoryModel(resource, historyHome, this._onDidAddEntry, this._onDidChangeEntry, this._onDidRemoveEntry, this.fileService, this.labelService, this.logService, this.configurationService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export interface IWorkingCopyHistoryEntry {
|
||||
/**
|
||||
* Associated source with the history entry.
|
||||
*/
|
||||
readonly source: SaveSource;
|
||||
source: SaveSource;
|
||||
}
|
||||
|
||||
export interface IWorkingCopyHistoryEntryDescriptor {
|
||||
@@ -90,6 +90,11 @@ export interface IWorkingCopyHistoryService {
|
||||
*/
|
||||
onDidAddEntry: Event<IWorkingCopyHistoryEvent>;
|
||||
|
||||
/**
|
||||
* An event when entries are changed in the history.
|
||||
*/
|
||||
onDidChangeEntry: Event<IWorkingCopyHistoryEvent>;
|
||||
|
||||
/**
|
||||
* An event when entries are removed from the history.
|
||||
*/
|
||||
@@ -106,6 +111,11 @@ export interface IWorkingCopyHistoryService {
|
||||
*/
|
||||
addEntry(descriptor: IWorkingCopyHistoryEntryDescriptor, token: CancellationToken): Promise<IWorkingCopyHistoryEntry | undefined>;
|
||||
|
||||
/**
|
||||
* Updates an entry in the local history if found.
|
||||
*/
|
||||
updateEntry(entry: IWorkingCopyHistoryEntry, properties: { source: SaveSource }, token: CancellationToken): Promise<void>;
|
||||
|
||||
/**
|
||||
* Removes an entry from the local history if found.
|
||||
*/
|
||||
|
||||
@@ -64,6 +64,7 @@ export class WorkingCopyHistoryModel {
|
||||
private readonly workingCopyResource: URI,
|
||||
private readonly historyHome: URI,
|
||||
private readonly entryAddedEmitter: Emitter<IWorkingCopyHistoryEvent>,
|
||||
private readonly entryChangedEmitter: Emitter<IWorkingCopyHistoryEvent>,
|
||||
private readonly entryRemovedEmitter: Emitter<IWorkingCopyHistoryEvent>,
|
||||
private readonly fileService: IFileService,
|
||||
private readonly labelService: ILabelService,
|
||||
@@ -125,6 +126,19 @@ export class WorkingCopyHistoryModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
async updateEntry(entry: IWorkingCopyHistoryEntry, properties: { source: SaveSource }, token: CancellationToken): Promise<void> {
|
||||
const index = this.entries.indexOf(entry);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update entry
|
||||
entry.source = properties.source;
|
||||
|
||||
// Events
|
||||
this.entryChangedEmitter.fire({ entry });
|
||||
}
|
||||
|
||||
async getEntries(): Promise<readonly IWorkingCopyHistoryEntry[]> {
|
||||
|
||||
// Make sure to await resolving when all entries are asked for
|
||||
@@ -322,6 +336,9 @@ export abstract class WorkingCopyHistoryService extends Disposable implements IW
|
||||
protected readonly _onDidAddEntry = this._register(new Emitter<IWorkingCopyHistoryEvent>());
|
||||
readonly onDidAddEntry = this._onDidAddEntry.event;
|
||||
|
||||
protected readonly _onDidChangeEntry = this._register(new Emitter<IWorkingCopyHistoryEvent>());
|
||||
readonly onDidChangeEntry = this._onDidChangeEntry.event;
|
||||
|
||||
protected readonly _onDidRemoveEntry = this._register(new Emitter<IWorkingCopyHistoryEvent>());
|
||||
readonly onDidRemoveEntry = this._onDidRemoveEntry.event;
|
||||
|
||||
@@ -382,6 +399,18 @@ export abstract class WorkingCopyHistoryService extends Disposable implements IW
|
||||
return model.addEntry(source, timestamp, token);
|
||||
}
|
||||
|
||||
async updateEntry(entry: IWorkingCopyHistoryEntry, properties: { source: SaveSource }, token: CancellationToken): Promise<void> {
|
||||
|
||||
// Resolve history model for working copy
|
||||
const model = await this.getModel(entry.workingCopy.resource);
|
||||
if (token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Rename in model
|
||||
return model.updateEntry(entry, properties, token);
|
||||
}
|
||||
|
||||
async removeEntry(entry: IWorkingCopyHistoryEntry, token: CancellationToken): Promise<boolean> {
|
||||
|
||||
// Resolve history model for working copy
|
||||
@@ -433,7 +462,7 @@ export abstract class WorkingCopyHistoryService extends Disposable implements IW
|
||||
}
|
||||
|
||||
protected createModel(resource: URI, historyHome: URI): WorkingCopyHistoryModel {
|
||||
return new WorkingCopyHistoryModel(resource, historyHome, this._onDidAddEntry, this._onDidRemoveEntry, this.fileService, this.labelService, this.logService, this.configurationService);
|
||||
return new WorkingCopyHistoryModel(resource, historyHome, this._onDidAddEntry, this._onDidChangeEntry, this._onDidRemoveEntry, this.fileService, this.labelService, this.logService, this.configurationService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+51
@@ -173,6 +173,42 @@ flakySuite('WorkingCopyHistoryService', () => {
|
||||
assert.strictEqual(addEvents.length, 4);
|
||||
});
|
||||
|
||||
test('renameEntry', async () => {
|
||||
let changeEvents: IWorkingCopyHistoryEvent[] = [];
|
||||
service.onDidChangeEntry(e => changeEvents.push(e));
|
||||
|
||||
const workingCopy1 = new TestWorkingCopy(URI.file(testFile1Path));
|
||||
|
||||
const entry = await addEntry({ resource: workingCopy1.resource }, CancellationToken.None);
|
||||
await addEntry({ resource: workingCopy1.resource }, CancellationToken.None);
|
||||
await addEntry({ resource: workingCopy1.resource, source: 'My Source' }, CancellationToken.None);
|
||||
|
||||
let entries = await service.getEntries(workingCopy1.resource, CancellationToken.None);
|
||||
assert.strictEqual(entries.length, 3);
|
||||
|
||||
await service.updateEntry(entry, { source: 'Hello Rename' }, CancellationToken.None);
|
||||
|
||||
assert.strictEqual(changeEvents.length, 1);
|
||||
assert.strictEqual(changeEvents[0].entry, entry);
|
||||
|
||||
entries = await service.getEntries(workingCopy1.resource, CancellationToken.None);
|
||||
assert.strictEqual(entries[0].source, 'Hello Rename');
|
||||
|
||||
// Simulate shutdown
|
||||
const event = new TestWillShutdownEvent();
|
||||
service._lifecycleService.fireWillShutdown(event);
|
||||
await Promise.allSettled(event.value);
|
||||
|
||||
// Resolve from disk fresh and verify again
|
||||
|
||||
service.dispose();
|
||||
service = new TestWorkingCopyHistoryService(testDir);
|
||||
|
||||
entries = await service.getEntries(workingCopy1.resource, CancellationToken.None);
|
||||
assert.strictEqual(entries.length, 3);
|
||||
assert.strictEqual(entries[0].source, 'Hello Rename');
|
||||
});
|
||||
|
||||
test('removeEntry', async () => {
|
||||
let removeEvents: IWorkingCopyHistoryEvent[] = [];
|
||||
service.onDidRemoveEntry(e => removeEvents.push(e));
|
||||
@@ -199,6 +235,19 @@ flakySuite('WorkingCopyHistoryService', () => {
|
||||
|
||||
entries = await service.getEntries(workingCopy1.resource, CancellationToken.None);
|
||||
assert.strictEqual(entries.length, 3);
|
||||
|
||||
// Simulate shutdown
|
||||
const event = new TestWillShutdownEvent();
|
||||
service._lifecycleService.fireWillShutdown(event);
|
||||
await Promise.allSettled(event.value);
|
||||
|
||||
// Resolve from disk fresh and verify again
|
||||
|
||||
service.dispose();
|
||||
service = new TestWorkingCopyHistoryService(testDir);
|
||||
|
||||
entries = await service.getEntries(workingCopy1.resource, CancellationToken.None);
|
||||
assert.strictEqual(entries.length, 3);
|
||||
});
|
||||
|
||||
test('removeAll', async () => {
|
||||
@@ -220,6 +269,8 @@ flakySuite('WorkingCopyHistoryService', () => {
|
||||
|
||||
await service.removeAll(CancellationToken.None);
|
||||
|
||||
assert.strictEqual(removed, true);
|
||||
|
||||
entries = await service.getEntries(workingCopy1.resource, CancellationToken.None);
|
||||
assert.strictEqual(entries.length, 0);
|
||||
entries = await service.getEntries(workingCopy2.resource, CancellationToken.None);
|
||||
|
||||
Reference in New Issue
Block a user