mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-03 09:35:40 -05:00
Merge from vscode bead496a613e475819f89f08e9e882b841bc1fe8 (#14883)
* Merge from vscode bead496a613e475819f89f08e9e882b841bc1fe8 * Bump distro * Upgrade GCC to 4.9 due to yarn install errors * Update build image * Fix bootstrap base url * Bump distro * Fix build errors * Update source map file * Disable checkbox for blocking migration issues (#15131) * disable checkbox for blocking issues * wip * disable checkbox fixes * fix strings * Remove duplicate tsec command * Default to off for tab color if settings not present * re-skip failing tests * Fix mocha error * Bump sqlite version & fix notebooks search view * Turn off esbuild warnings * Update esbuild log level * Fix overflowactionbar tests * Fix ts-ignore in dropdown tests * cleanup/fixes * Fix hygiene * Bundle in entire zone.js module * Remove extra constructor param * bump distro for web compile break * bump distro for web compile break v2 * Undo log level change * New distro * Fix integration test scripts * remove the "no yarn.lock changes" workflow * fix scripts v2 * Update unit test scripts * Ensure ads-kerberos2 updates in .vscodeignore * Try fix unit tests * Upload crash reports * remove nogpu * always upload crashes * Use bash script * Consolidate data/ext dir names * Create in tmp directory Co-authored-by: chlafreniere <hichise@gmail.com> Co-authored-by: Christopher Suh <chsuh@microsoft.com> Co-authored-by: chgagnon <chgagnon@microsoft.com>
This commit is contained in:
@@ -4,23 +4,43 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { FileChangeType, IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileChangeType, FileOperation, IFileService } from 'vs/platform/files/common/files';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, FileSystemEvents, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IWorkingCopyFileOperationParticipant, IWorkingCopyFileService, SourceTargetPair, IFileOperationUndoRedoInfo } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { reviveWorkspaceEditDto2 } from 'vs/workbench/api/browser/mainThreadEditors';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { raceCancellation } from 'vs/base/common/async';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadFileSystemEventService {
|
||||
|
||||
static readonly MementoKeyAdditionalEdits = `file.particpants.additionalEdits`;
|
||||
|
||||
private readonly _listener = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IFileService fileService: IFileService,
|
||||
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService
|
||||
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
|
||||
@IBulkEditService bulkEditService: IBulkEditService,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@IDialogService dialogService: IDialogService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ILogService logService: ILogService,
|
||||
@IEnvironmentService envService: IEnvironmentService
|
||||
) {
|
||||
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService);
|
||||
@@ -53,14 +73,124 @@ export class MainThreadFileSystemEventService {
|
||||
}));
|
||||
|
||||
|
||||
// BEFORE file operation
|
||||
this._listener.add(workingCopyFileService.addFileOperationParticipant({
|
||||
participate: async (files, operation, undoRedoGroupId, isUndoing, _progress, timeout, token) => {
|
||||
if (!isUndoing) {
|
||||
return proxy.$onWillRunFileOperation(operation, files, undoRedoGroupId, timeout, token);
|
||||
const fileOperationParticipant = new class implements IWorkingCopyFileOperationParticipant {
|
||||
async participate(files: SourceTargetPair[], operation: FileOperation, undoInfo: IFileOperationUndoRedoInfo | undefined, timeout: number, token: CancellationToken) {
|
||||
if (undoInfo?.isUndoing) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cts = new CancellationTokenSource(token);
|
||||
const timer = setTimeout(() => cts.cancel(), timeout);
|
||||
|
||||
const data = await progressService.withProgress({
|
||||
location: ProgressLocation.Notification,
|
||||
title: this._progressLabel(operation),
|
||||
cancellable: true,
|
||||
delay: Math.min(timeout / 2, 3000)
|
||||
}, () => {
|
||||
// race extension host event delivery against timeout AND user-cancel
|
||||
const onWillEvent = proxy.$onWillRunFileOperation(operation, files, timeout, token);
|
||||
return raceCancellation(onWillEvent, cts.token);
|
||||
}, () => {
|
||||
// user-cancel
|
||||
cts.cancel();
|
||||
|
||||
}).finally(() => {
|
||||
cts.dispose();
|
||||
clearTimeout(timer);
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
// cancelled or no reply
|
||||
return;
|
||||
}
|
||||
|
||||
const needsConfirmation = data.edit.edits.some(edit => edit.metadata?.needsConfirmation);
|
||||
let showPreview = storageService.getBoolean(MainThreadFileSystemEventService.MementoKeyAdditionalEdits, StorageScope.GLOBAL);
|
||||
|
||||
if (envService.extensionTestsLocationURI) {
|
||||
// don't show dialog in tests
|
||||
showPreview = false;
|
||||
}
|
||||
|
||||
if (showPreview === undefined) {
|
||||
// show a user facing message
|
||||
|
||||
let message: string;
|
||||
if (data.extensionNames.length === 1) {
|
||||
if (operation === FileOperation.CREATE) {
|
||||
message = localize('ask.1.create', "Extension '{0}' wants to make refactoring changes with this file creation", data.extensionNames[0]);
|
||||
} else if (operation === FileOperation.COPY) {
|
||||
message = localize('ask.1.copy', "Extension '{0}' wants to make refactoring changes with this file copy", data.extensionNames[0]);
|
||||
} else if (operation === FileOperation.MOVE) {
|
||||
message = localize('ask.1.move', "Extension '{0}' wants to make refactoring changes with this file move", data.extensionNames[0]);
|
||||
} else /* if (operation === FileOperation.DELETE) */ {
|
||||
message = localize('ask.1.delete', "Extension '{0}' wants to make refactoring changes with this file deletion", data.extensionNames[0]);
|
||||
}
|
||||
} else {
|
||||
if (operation === FileOperation.CREATE) {
|
||||
message = localize('ask.N.create', "{0} extensions want to make refactoring changes with this file creation", data.extensionNames.length);
|
||||
} else if (operation === FileOperation.COPY) {
|
||||
message = localize('ask.N.copy', "{0} extensions want to make refactoring changes with this file copy", data.extensionNames.length);
|
||||
} else if (operation === FileOperation.MOVE) {
|
||||
message = localize('ask.N.move', "{0} extensions want to make refactoring changes with this file move", data.extensionNames.length);
|
||||
} else /* if (operation === FileOperation.DELETE) */ {
|
||||
message = localize('ask.N.delete', "{0} extensions want to make refactoring changes with this file deletion", data.extensionNames.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (needsConfirmation) {
|
||||
// edit which needs confirmation -> always show dialog
|
||||
const answer = await dialogService.show(Severity.Info, message, [localize('preview', "Show Preview"), localize('cancel', "Skip Changes")], { cancelId: 1 });
|
||||
showPreview = true;
|
||||
if (answer.choice === 1) {
|
||||
// no changes wanted
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// choice
|
||||
const answer = await dialogService.show(Severity.Info, message,
|
||||
[localize('ok', "OK"), localize('preview', "Show Preview"), localize('cancel', "Skip Changes")],
|
||||
{
|
||||
cancelId: 2,
|
||||
checkbox: { label: localize('again', "Don't ask again") }
|
||||
}
|
||||
);
|
||||
if (answer.choice === 2) {
|
||||
// no changes wanted, don't persist cancel option
|
||||
return;
|
||||
}
|
||||
showPreview = answer.choice === 1;
|
||||
if (answer.checkboxChecked /* && answer.choice !== 2 */) {
|
||||
storageService.store(MainThreadFileSystemEventService.MementoKeyAdditionalEdits, showPreview, StorageScope.GLOBAL, StorageTarget.USER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logService.info('[onWill-handler] applying additional workspace edit from extensions', data.extensionNames);
|
||||
|
||||
await bulkEditService.apply(
|
||||
reviveWorkspaceEditDto2(data.edit),
|
||||
{ undoRedoGroupId: undoInfo?.undoRedoGroupId, showPreview }
|
||||
);
|
||||
}
|
||||
|
||||
private _progressLabel(operation: FileOperation): string {
|
||||
switch (operation) {
|
||||
case FileOperation.CREATE:
|
||||
return localize('msg-create', "Running 'File Create' participants...");
|
||||
case FileOperation.MOVE:
|
||||
return localize('msg-rename', "Running 'File Rename' participants...");
|
||||
case FileOperation.COPY:
|
||||
return localize('msg-copy', "Running 'File Copy' participants...");
|
||||
case FileOperation.DELETE:
|
||||
return localize('msg-delete', "Running 'File Delete' participants...");
|
||||
}
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
// BEFORE file operation
|
||||
this._listener.add(workingCopyFileService.addFileOperationParticipant(fileOperationParticipant));
|
||||
|
||||
// AFTER file operation
|
||||
this._listener.add(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => proxy.$onDidRunFileOperation(e.operation, e.files)));
|
||||
@@ -71,6 +201,19 @@ export class MainThreadFileSystemEventService {
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(class ResetMemento extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'files.participants.resetChoice',
|
||||
title: localize('label', "Reset choice for 'File operation needs preview'"),
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
run(accessor: ServicesAccessor) {
|
||||
accessor.get(IStorageService).remove(MainThreadFileSystemEventService.MementoKeyAdditionalEdits, StorageScope.GLOBAL);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
|
||||
id: 'files',
|
||||
|
||||
Reference in New Issue
Block a user