Skip to content

Commit ce6519e

Browse files
author
Benjamin Pasero
committed
backup - drop internal backup service for dirty editor dnd and use content directly
1 parent 4dcfc6c commit ce6519e

3 files changed

Lines changed: 36 additions & 53 deletions

File tree

src/vs/workbench/browser/dnd.ts

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@ import { basename } from 'vs/base/common/resources';
99
import { IFileService } from 'vs/platform/files/common/files';
1010
import { IWindowOpenable } from 'vs/platform/windows/common/windows';
1111
import { URI } from 'vs/base/common/uri';
12-
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
13-
import { IBackupFileService, IInternalBackupFilesService } from 'vs/workbench/services/backup/common/backup';
12+
import { ITextFileService, stringToSnapshot } from 'vs/workbench/services/textfile/common/textfiles';
1413
import { Schemas } from 'vs/base/common/network';
15-
import { DefaultEndOfLine } from 'vs/editor/common/model';
16-
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1714
import { IEditorViewState } from 'vs/editor/common/editorCommon';
1815
import { DataTransfers } from 'vs/base/browser/dnd';
1916
import { DragMouseEvent } from 'vs/base/browser/mouseEvent';
@@ -31,6 +28,8 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/commo
3128
import { withNullAsUndefined } from 'vs/base/common/types';
3229
import { IHostService } from 'vs/workbench/services/host/browser/host';
3330
import { isStandalone } from 'vs/base/browser/browser';
31+
import { IModelService } from 'vs/editor/common/services/modelService';
32+
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
3433

3534
export interface IDraggedResource {
3635
resource: URI;
@@ -56,15 +55,15 @@ export class DraggedEditorGroupIdentifier {
5655
}
5756

5857
export interface IDraggedEditor extends IDraggedResource {
59-
backupResource?: URI;
58+
content?: string;
6059
encoding?: string;
6160
mode?: string;
6261
viewState?: IEditorViewState;
6362
}
6463

6564
export interface ISerializedDraggedEditor {
6665
resource: string;
67-
backupResource?: string;
66+
content?: string;
6867
encoding?: string;
6968
mode?: string;
7069
viewState?: IEditorViewState;
@@ -90,7 +89,7 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array<ID
9089
draggedEditors.forEach(draggedEditor => {
9190
resources.push({
9291
resource: URI.parse(draggedEditor.resource),
93-
backupResource: draggedEditor.backupResource ? URI.parse(draggedEditor.backupResource) : undefined,
92+
content: draggedEditor.content,
9493
viewState: draggedEditor.viewState,
9594
encoding: draggedEditor.encoding,
9695
mode: draggedEditor.mode,
@@ -169,9 +168,8 @@ export class ResourcesDropHandler {
169168
@IFileService private readonly fileService: IFileService,
170169
@IWorkspacesService private readonly workspacesService: IWorkspacesService,
171170
@ITextFileService private readonly textFileService: ITextFileService,
172-
@IBackupFileService private readonly backupFileService: IInternalBackupFilesService,
171+
@IBackupFileService private readonly backupFileService: IBackupFileService,
173172
@IEditorService private readonly editorService: IEditorService,
174-
@IConfigurationService private readonly configurationService: IConfigurationService,
175173
@IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService,
176174
@IHostService private readonly hostService: IHostService
177175
) {
@@ -221,9 +219,9 @@ export class ResourcesDropHandler {
221219
private async doHandleDrop(untitledOrFileResources: Array<IDraggedResource | IDraggedEditor>): Promise<boolean> {
222220

223221
// Check for dirty editors being dropped
224-
const resourcesWithBackups: IDraggedEditor[] = untitledOrFileResources.filter(resource => !resource.isExternal && !!(resource as IDraggedEditor).backupResource);
225-
if (resourcesWithBackups.length > 0) {
226-
await Promise.all(resourcesWithBackups.map(resourceWithBackup => this.handleDirtyEditorDrop(resourceWithBackup)));
222+
const resourcesWithContent: IDraggedEditor[] = untitledOrFileResources.filter(resource => !resource.isExternal && !!(resource as IDraggedEditor).content);
223+
if (resourcesWithContent.length > 0) {
224+
await Promise.all(resourcesWithContent.map(resourceWithContent => this.handleDirtyEditorDrop(resourceWithContent)));
227225
return false;
228226
}
229227

@@ -250,13 +248,11 @@ export class ResourcesDropHandler {
250248
return false;
251249
}
252250

253-
// Resolve the contents of the dropped dirty resource from source
254-
if (droppedDirtyEditor.backupResource) {
251+
// If the dropped editor is dirty with content we simply take that
252+
// content and turn it into a backup so that it loads the contents
253+
if (droppedDirtyEditor.content) {
255254
try {
256-
const backup = await this.backupFileService.resolve(droppedDirtyEditor.backupResource, { isBackupResource: true });
257-
if (backup) {
258-
await this.backupFileService.backup(droppedDirtyEditor.resource, backup.value.create(this.getDefaultEOL()).createSnapshot(true), undefined, backup.meta);
259-
}
255+
await this.backupFileService.backup(droppedDirtyEditor.resource, stringToSnapshot(droppedDirtyEditor.content));
260256
} catch (e) {
261257
// Ignore error
262258
}
@@ -265,15 +261,6 @@ export class ResourcesDropHandler {
265261
return false;
266262
}
267263

268-
private getDefaultEOL(): DefaultEndOfLine {
269-
const eol = this.configurationService.getValue('files.eol');
270-
if (eol === '\r\n') {
271-
return DefaultEndOfLine.CRLF;
272-
}
273-
274-
return DefaultEndOfLine.LF;
275-
}
276-
277264
private async handleWorkspaceFileDrop(fileOnDiskResources: URI[]): Promise<boolean> {
278265
const toOpen: IWindowOpenable[] = [];
279266
const folderURIs: IWorkspaceFolderCreationData[] = [];
@@ -352,8 +339,8 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
352339

353340
// Editors: enables cross window DND of tabs into the editor area
354341
const textFileService = accessor.get(ITextFileService);
355-
const backupFileService = accessor.get(IBackupFileService) as IInternalBackupFilesService;
356342
const editorService = accessor.get(IEditorService);
343+
const modelService = accessor.get(IModelService);
357344

358345
const draggedEditors: ISerializedDraggedEditor[] = [];
359346
files.forEach(file => {
@@ -381,15 +368,18 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
381368
mode = model.getMode();
382369
}
383370

384-
// If the resource is dirty, send over its backup
385-
// resource to restore dirty state
386-
let backupResource: string | undefined = undefined;
371+
// If the resource is dirty or untitled, send over its content
372+
// to restore dirty state. Get that from the text model directly
373+
let content: string | undefined = undefined;
387374
if (textFileService.isDirty(file.resource)) {
388-
backupResource = backupFileService.toBackupResource(file.resource).toString();
375+
const textModel = modelService.getModel(file.resource);
376+
if (textModel) {
377+
content = textModel.getValue();
378+
}
389379
}
390380

391381
// Add as dragged editor
392-
draggedEditors.push({ resource: file.resource.toString(), backupResource, viewState, encoding, mode });
382+
draggedEditors.push({ resource: file.resource.toString(), content, viewState, encoding, mode });
393383
});
394384

395385
if (draggedEditors.length) {

src/vs/workbench/services/backup/common/backup.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,3 @@ export interface IBackupFileService {
7171
*/
7272
discardBackups(): Promise<void>;
7373
}
74-
75-
// TODO@ben: should try to avoid using backup for restoring dirty between windows
76-
// Should rather have a way to open existing files with contents?
77-
export interface IInternalBackupFilesService extends IBackupFileService {
78-
toBackupResource(resource: URI): URI;
79-
resolve<T extends object>(resource: URI, options?: { isBackupResource?: boolean }): Promise<IResolvedBackup<T> | undefined>;
80-
}

src/vs/workbench/services/backup/common/backupFileService.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { hash } from 'vs/base/common/hash';
1010
import { coalesce } from 'vs/base/common/arrays';
1111
import { equals, deepClone } from 'vs/base/common/objects';
1212
import { ResourceQueue } from 'vs/base/common/async';
13-
import { IResolvedBackup, IInternalBackupFilesService } from 'vs/workbench/services/backup/common/backup';
13+
import { IResolvedBackup, IBackupFileService } from 'vs/workbench/services/backup/common/backup';
1414
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
1515
import { ITextSnapshot } from 'vs/editor/common/model';
1616
import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
@@ -103,11 +103,11 @@ export class BackupFilesModel implements IBackupFilesModel {
103103
}
104104
}
105105

106-
export class BackupFileService implements IInternalBackupFilesService {
106+
export class BackupFileService implements IBackupFileService {
107107

108108
_serviceBrand: undefined;
109109

110-
private impl: IInternalBackupFilesService;
110+
private impl: BackupFileServiceImpl | InMemoryBackupFileService;
111111

112112
constructor(
113113
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
@@ -122,7 +122,7 @@ export class BackupFileService implements IInternalBackupFilesService {
122122
return hash(str).toString(16);
123123
}
124124

125-
private initialize(): IInternalBackupFilesService {
125+
private initialize(): BackupFileServiceImpl | InMemoryBackupFileService {
126126
const backupWorkspaceResource = this.environmentService.configuration.backupWorkspaceResource;
127127
if (backupWorkspaceResource) {
128128
return new BackupFileServiceImpl(backupWorkspaceResource, this.hashPath, this.fileService);
@@ -168,16 +168,16 @@ export class BackupFileService implements IInternalBackupFilesService {
168168
return this.impl.getBackups();
169169
}
170170

171-
resolve<T extends object>(resource: URI, options?: { isBackupResource?: boolean }): Promise<IResolvedBackup<T> | undefined> {
172-
return this.impl.resolve(resource, options);
171+
resolve<T extends object>(resource: URI): Promise<IResolvedBackup<T> | undefined> {
172+
return this.impl.resolve(resource);
173173
}
174174

175175
toBackupResource(resource: URI): URI {
176176
return this.impl.toBackupResource(resource);
177177
}
178178
}
179179

180-
class BackupFileServiceImpl implements IInternalBackupFilesService {
180+
class BackupFileServiceImpl implements IBackupFileService {
181181

182182
private static readonly PREAMBLE_END_MARKER = '\n';
183183
private static readonly PREAMBLE_META_SEPARATOR = ' '; // using a character that is know to be escaped in a URI as separator
@@ -330,11 +330,11 @@ class BackupFileServiceImpl implements IInternalBackupFilesService {
330330
throw new Error(`Backup: Could not find ${JSON.stringify(matchingString)} in first ${maximumBytesToRead} bytes of ${file}`);
331331
}
332332

333-
async resolve<T extends object>(resource: URI, options?: { isBackupResource?: boolean }): Promise<IResolvedBackup<T> | undefined> {
334-
const backupResource = options?.isBackupResource ? resource : this.toBackupResource(resource);
333+
async resolve<T extends object>(resource: URI): Promise<IResolvedBackup<T> | undefined> {
334+
const backupResource = this.toBackupResource(resource);
335335

336336
const model = await this.ready;
337-
if (!options?.isBackupResource && !model.has(backupResource)) {
337+
if (!model.has(backupResource)) {
338338
return undefined; // require backup to be present
339339
}
340340

@@ -395,7 +395,7 @@ class BackupFileServiceImpl implements IInternalBackupFilesService {
395395
}
396396
}
397397

398-
export class InMemoryBackupFileService implements IInternalBackupFilesService {
398+
export class InMemoryBackupFileService implements IBackupFileService {
399399

400400
_serviceBrand: undefined;
401401

@@ -418,8 +418,8 @@ export class InMemoryBackupFileService implements IInternalBackupFilesService {
418418
this.backups.set(backupResource.toString(), content || stringToSnapshot(''));
419419
}
420420

421-
async resolve<T extends object>(resource: URI, options?: { isBackupResource?: boolean }): Promise<IResolvedBackup<T> | undefined> {
422-
const backupResource = options?.isBackupResource ? resource : this.toBackupResource(resource);
421+
async resolve<T extends object>(resource: URI): Promise<IResolvedBackup<T> | undefined> {
422+
const backupResource = this.toBackupResource(resource);
423423
const snapshot = this.backups.get(backupResource.toString());
424424
if (snapshot) {
425425
return { value: createTextBufferFactoryFromSnapshot(snapshot) };

0 commit comments

Comments
 (0)