diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index b3e8ad245f2ce..16cc54f9b6904 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Action } from 'vs/base/common/actions'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { VIEWLET_ID, IFilesConfiguration, VIEW_ID } from 'vs/workbench/contrib/files/common/files'; +import { VIEWLET_ID, IFilesConfiguration, VIEW_ID, UndoEnablement } from 'vs/workbench/contrib/files/common/files'; import { IFileService } from 'vs/platform/files/common/files'; import { EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor'; import { IQuickInputService, ItemActivation } from 'vs/platform/quickinput/common/quickInput'; @@ -1037,10 +1037,11 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => { } else { const resourceFileEdits = sourceTargetPairs.map(pair => new ResourceFileEdit(pair.source, pair.target, { copy: true })); const options = { + confirmBeforeUndo: configurationService.getValue().explorer.enableUndo === UndoEnablement.Warn, progressLabel: sourceTargetPairs.length > 1 ? nls.localize({ key: 'copyingBulkEdit', comment: ['Placeholder will be replaced by the number of files being copied'] }, "Copying {0} files", sourceTargetPairs.length) : nls.localize({ key: 'copyingFileBulkEdit', comment: ['Placeholder will be replaced by the name of the file copied.'] }, "Copying {0}", resources.basenameOrAuthority(sourceTargetPairs[0].target)), - undoLabel: sourceTargetPairs.length > 1 ? nls.localize({ key: 'copyBulkEdit', comment: ['Placeholder will be replaced by the number of files being copied'] }, "Copy {0} files", sourceTargetPairs.length) - : nls.localize({ key: 'copyFileBulkEdit', comment: ['Placeholder will be replaced by the name of the file copied.'] }, "Copy {0}", resources.basenameOrAuthority(sourceTargetPairs[0].target)) + undoLabel: sourceTargetPairs.length > 1 ? nls.localize({ key: 'copyBulkEdit', comment: ['Placeholder will be replaced by the number of files being copied'] }, "Paste {0} files", sourceTargetPairs.length) + : nls.localize({ key: 'copyFileBulkEdit', comment: ['Placeholder will be replaced by the name of the file copied.'] }, "Paste {0}", resources.basenameOrAuthority(sourceTargetPairs[0].target)) }; await explorerService.applyBulkEdit(resourceFileEdits, options); } diff --git a/src/vs/workbench/contrib/files/browser/fileImportExport.ts b/src/vs/workbench/contrib/files/browser/fileImportExport.ts index 84e56881796f9..c054249caa61d 100644 --- a/src/vs/workbench/contrib/files/browser/fileImportExport.ts +++ b/src/vs/workbench/contrib/files/browser/fileImportExport.ts @@ -10,7 +10,7 @@ import { ByteSize, FileSystemProviderCapabilities, IFileService, IFileStatWithMe import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IProgress, IProgressService, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; -import { VIEW_ID } from 'vs/workbench/contrib/files/common/files'; +import { IFilesConfiguration, UndoEnablement, VIEW_ID } from 'vs/workbench/contrib/files/common/files'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Limiter, Promises, RunOnceWorker } from 'vs/base/common/async'; import { newWriteableBufferStream, VSBuffer } from 'vs/base/common/buffer'; @@ -32,6 +32,7 @@ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { once } from 'vs/base/common/functional'; import { coalesce } from 'vs/base/common/arrays'; import { canceled } from 'vs/base/common/errors'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; //#region Browser File Upload (drag and drop, input element) @@ -387,6 +388,7 @@ export class ExternalFileImport { @IFileService private readonly fileService: IFileService, @IHostService private readonly hostService: IHostService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IConfigurationService private readonly configurationService: IConfigurationService, @IDialogService private readonly dialogService: IDialogService, @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, @IExplorerService private readonly explorerService: IExplorerService, @@ -530,12 +532,13 @@ export class ExternalFileImport { await this.explorerService.applyBulkEdit(resourceFileEdits, { undoLabel: resourcesFiltered.length === 1 ? - localize('copyFile', "Copy {0}", basename(resourcesFiltered[0])) : - localize('copynFile', "Copy {0} resources", resourcesFiltered.length), + localize('importFile', "Import {0}", basename(resourcesFiltered[0])) : + localize('importnFile', "Import {0} resources", resourcesFiltered.length), progressLabel: resourcesFiltered.length === 1 ? localize('copyingFile', "Copying {0}", basename(resourcesFiltered[0])) : localize('copyingnFile', "Copying {0} resources", resourcesFiltered.length), - progressLocation: ProgressLocation.Window + progressLocation: ProgressLocation.Window, + confirmBeforeUndo: this.configurationService.getValue().explorer.enableUndo === UndoEnablement.Warn, }); // if we only add one file, just open it directly diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 4599241012b31..b15053083b8da 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -10,7 +10,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IFileEditorInput, IEditorFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; import { AutoSaveConfiguration, HotExitConfiguration, FILES_EXCLUDE_CONFIG, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; -import { SortOrder, LexicographicOptions, FILE_EDITOR_INPUT_ID, BINARY_TEXT_FILE_MODE } from 'vs/workbench/contrib/files/common/files'; +import { SortOrder, LexicographicOptions, FILE_EDITOR_INPUT_ID, BINARY_TEXT_FILE_MODE, UndoEnablement, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files'; import { TextFileEditorTracker } from 'vs/workbench/contrib/files/browser/editors/textFileEditorTracker'; import { TextFileSaveErrorHandler } from 'vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler'; import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; @@ -34,6 +34,7 @@ import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; import { FileEditorInputSerializer, FileEditorWorkingCopyEditorHandler } from 'vs/workbench/contrib/files/browser/editors/fileEditorHandler'; import { ModesRegistry } from 'vs/editor/common/languages/modesRegistry'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; class FileUriLabelContribution implements IWorkbenchContribution { @@ -369,6 +370,17 @@ configurationRegistry.registerConfiguration({ 'description': nls.localize('confirmDelete', "Controls whether the explorer should ask for confirmation when deleting a file via the trash."), 'default': true }, + 'explorer.enableUndo': { + 'type': 'string', + 'enum': [UndoEnablement.Warn, UndoEnablement.Allow, UndoEnablement.Disable], + 'description': nls.localize('confirmUndo', "Controls how the explorer participates in undoing file and folder edits."), + 'default': UndoEnablement.Warn, + 'enumDescriptions': [ + nls.localize('enableUndo.warn', 'Explorer will prompt before undoing all file and folder creation events.'), + nls.localize('enableUndo.allow', 'Explorer will undo file and folder creation events without prompting.'), + nls.localize('enableUndo.disable', 'Explorer does not participte in undo events.'), + ], + }, 'explorer.expandSingleFolderWorkspaces': { 'type': 'boolean', 'description': nls.localize('expandSingleFolderWorkspaces', "Controls whether the explorer should expand multi-root workspaces containing only one folder during initilization"), @@ -445,7 +457,10 @@ configurationRegistry.registerConfiguration({ UndoCommand.addImplementation(110, 'explorer', (accessor: ServicesAccessor) => { const undoRedoService = accessor.get(IUndoRedoService); const explorerService = accessor.get(IExplorerService); - if (explorerService.hasViewFocus() && undoRedoService.canUndo(UNDO_REDO_SOURCE)) { + const configurationService = accessor.get(IConfigurationService); + + const explorerCanUndo = configurationService.getValue().explorer.enableUndo !== UndoEnablement.Disable; + if (explorerService.hasViewFocus() && undoRedoService.canUndo(UNDO_REDO_SOURCE) && explorerCanUndo) { undoRedoService.undo(UNDO_REDO_SOURCE); return true; } @@ -456,7 +471,10 @@ UndoCommand.addImplementation(110, 'explorer', (accessor: ServicesAccessor) => { RedoCommand.addImplementation(110, 'explorer', (accessor: ServicesAccessor) => { const undoRedoService = accessor.get(IUndoRedoService); const explorerService = accessor.get(IExplorerService); - if (explorerService.hasViewFocus() && undoRedoService.canRedo(UNDO_REDO_SOURCE)) { + const configurationService = accessor.get(IConfigurationService); + + const explorerCanUndo = configurationService.getValue().explorer.enableUndo !== UndoEnablement.Disable; + if (explorerService.hasViewFocus() && undoRedoService.canRedo(UNDO_REDO_SOURCE) && explorerCanUndo) { undoRedoService.redo(UNDO_REDO_SOURCE); return true; } diff --git a/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts index 32d92f635dc68..010a811838a0b 100644 --- a/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -88,6 +88,7 @@ export interface IFilesConfiguration extends PlatformIFilesConfiguration, IWorkb autoReveal: boolean | 'focusNoScroll'; enableDragAndDrop: boolean; confirmDelete: boolean; + enableUndo: UndoEnablement; expandSingleFolderWorkspaces: boolean; sortOrder: SortOrder; sortOrderLexicographicOptions: LexicographicOptions; @@ -113,6 +114,12 @@ export const enum SortOrder { Modified = 'modified' } +export const enum UndoEnablement { + Warn = 'warn', + Allow = 'allow', + Disable = 'disable', +} + export const enum LexicographicOptions { Default = 'default', Upper = 'upper',