Merge from vscode 12cb89c82e88e035f4ab630f1b9fcebac338dc03 (#5125)

This commit is contained in:
Alan Ren
2019-04-19 10:26:20 -07:00
committed by GitHub
parent f248260584
commit 0e168e36fc
17 changed files with 111 additions and 49 deletions

View File

@@ -16,7 +16,7 @@ if grep -qi Microsoft /proc/version; then
if ! [ -z "$WSL_EXT_WLOC" ]; then if ! [ -z "$WSL_EXT_WLOC" ]; then
# replace \r\n with \n in WSL_EXT_WLOC, get linux path for # replace \r\n with \n in WSL_EXT_WLOC, get linux path for
WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh
$WSL_CODE $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@" "$WSL_CODE" $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@"
exit $? exit $?
fi fi
fi fi

View File

@@ -16,6 +16,9 @@ export function registerContextMenuListener(): void {
y: options ? options.y : undefined, y: options ? options.y : undefined,
positioningItem: options ? options.positioningItem : undefined, positioningItem: options ? options.positioningItem : undefined,
callback: () => { callback: () => {
// Workaround for https://github.com/Microsoft/vscode/issues/72447
// It turns out that the menu gets GC'ed if not referenced anymore
// As such we drag it into this scope so that it is not being GC'ed
if (menu) { if (menu) {
event.sender.send(CONTEXT_MENU_CLOSE_CHANNEL, contextMenuId); event.sender.send(CONTEXT_MENU_CLOSE_CHANNEL, contextMenuId);
} }

View File

@@ -753,6 +753,11 @@ export enum FileKind {
export const MIN_MAX_MEMORY_SIZE_MB = 2048; export const MIN_MAX_MEMORY_SIZE_MB = 2048;
export const FALLBACK_MAX_MEMORY_SIZE_MB = 4096; export const FALLBACK_MAX_MEMORY_SIZE_MB = 4096;
/**
* A hint to disable etag checking for reading/writing.
*/
export const ETAG_DISABLED = '';
export function etag(mtime: number, size: number): string; export function etag(mtime: number, size: number): string;
export function etag(mtime: number | undefined, size: number | undefined): string | undefined; export function etag(mtime: number | undefined, size: number | undefined): string | undefined;
export function etag(mtime: number | undefined, size: number | undefined): string | undefined { export function etag(mtime: number | undefined, size: number | undefined): string | undefined {

View File

@@ -6,6 +6,7 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { IAction } from 'vs/base/common/actions';
export const IProgressService = createDecorator<IProgressService>('progressService'); export const IProgressService = createDecorator<IProgressService>('progressService');
@@ -42,6 +43,12 @@ export interface IProgressOptions {
cancellable?: boolean; cancellable?: boolean;
} }
export interface IProgressNotificationOptions extends IProgressOptions {
location: ProgressLocation.Notification;
primaryActions?: IAction[];
secondaryActions?: IAction[];
}
export interface IProgressStep { export interface IProgressStep {
message?: string; message?: string;
increment?: number; increment?: number;

View File

@@ -3,9 +3,21 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IProgress, IProgressService2, IProgressStep, IProgressOptions } from 'vs/platform/progress/common/progress'; import { IProgress, IProgressService2, IProgressStep, ProgressLocation, IProgressOptions, IProgressNotificationOptions } from 'vs/platform/progress/common/progress';
import { MainThreadProgressShape, MainContext, IExtHostContext, ExtHostProgressShape, ExtHostContext } from '../common/extHost.protocol'; import { MainThreadProgressShape, MainContext, IExtHostContext, ExtHostProgressShape, ExtHostContext } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { Action } from 'vs/base/common/actions';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { localize } from 'vs/nls';
class ManageExtensionAction extends Action {
constructor(id: ExtensionIdentifier, label: string, commandService: ICommandService) {
super(id.value, label, undefined, true, () => {
return commandService.executeCommand('_extensions.manage', id.value);
});
}
}
@extHostNamedCustomer(MainContext.MainThreadProgress) @extHostNamedCustomer(MainContext.MainThreadProgress)
export class MainThreadProgress implements MainThreadProgressShape { export class MainThreadProgress implements MainThreadProgressShape {
@@ -16,7 +28,8 @@ export class MainThreadProgress implements MainThreadProgressShape {
constructor( constructor(
extHostContext: IExtHostContext, extHostContext: IExtHostContext,
@IProgressService2 progressService: IProgressService2 @IProgressService2 progressService: IProgressService2,
@ICommandService private readonly _commandService: ICommandService
) { ) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostProgress); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostProgress);
this._progressService = progressService; this._progressService = progressService;
@@ -27,9 +40,19 @@ export class MainThreadProgress implements MainThreadProgressShape {
this._progress.clear(); this._progress.clear();
} }
$startProgress(handle: number, options: IProgressOptions): void { $startProgress(handle: number, options: IProgressOptions, extension?: IExtensionDescription): void {
const task = this._createTask(handle); const task = this._createTask(handle);
if (options.location === ProgressLocation.Notification && extension && !extension.isUnderDevelopment) {
const notificationOptions: IProgressNotificationOptions = {
...options,
location: ProgressLocation.Notification,
secondaryActions: [new ManageExtensionAction(extension.identifier, localize('manageExtension', "Manage Extension"), this._commandService)]
};
options = notificationOptions;
}
this._progressService.withProgress(options, task, () => this._proxy.$acceptProgressCanceled(handle)); this._progressService.withProgress(options, task, () => this._proxy.$acceptProgressCanceled(handle));
} }

View File

@@ -379,7 +379,7 @@ export interface MainThreadOutputServiceShape extends IDisposable {
export interface MainThreadProgressShape extends IDisposable { export interface MainThreadProgressShape extends IDisposable {
$startProgress(handle: number, options: IProgressOptions): void; $startProgress(handle: number, options: IProgressOptions, extension?: IExtensionDescription): void;
$progressReport(handle: number, message: IProgressStep): void; $progressReport(handle: number, message: IProgressStep): void;
$progressEnd(handle: number): void; $progressEnd(handle: number): void;
} }

View File

@@ -26,7 +26,7 @@ export class ExtHostProgress implements ExtHostProgressShape {
const handle = this._handles++; const handle = this._handles++;
const { title, location, cancellable } = options; const { title, location, cancellable } = options;
const source = localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name); const source = localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name);
this._proxy.$startProgress(handle, { location: ProgressLocation.from(location), title, source, cancellable }); this._proxy.$startProgress(handle, { location: ProgressLocation.from(location), title, source, cancellable }, extension);
return this._withProgress(handle, task, !!cancellable); return this._withProgress(handle, task, !!cancellable);
} }

View File

@@ -34,6 +34,7 @@ import { IEditorInput, IEditor } from 'vs/workbench/common/editor';
import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution { export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution {
@@ -42,18 +43,21 @@ export class ExplorerViewletViewsContribution extends Disposable implements IWor
constructor( constructor(
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IContextKeyService contextKeyService: IContextKeyService @IContextKeyService contextKeyService: IContextKeyService,
@IProgressService2 progressService: IProgressService2
) { ) {
super(); super();
this.registerViews(); progressService.withProgress({ location: ProgressLocation.Explorer }, () => workspaceContextService.getCompleteWorkspace()).finally(() => {
this.registerViews();
this.openEditorsVisibleContextKey = OpenEditorsVisibleContext.bindTo(contextKeyService); this.openEditorsVisibleContextKey = OpenEditorsVisibleContext.bindTo(contextKeyService);
this.updateOpenEditorsVisibility(); this.updateOpenEditorsVisibility();
this._register(workspaceContextService.onDidChangeWorkbenchState(() => this.registerViews())); this._register(workspaceContextService.onDidChangeWorkbenchState(() => this.registerViews()));
this._register(workspaceContextService.onDidChangeWorkspaceFolders(() => this.registerViews())); this._register(workspaceContextService.onDidChangeWorkspaceFolders(() => this.registerViews()));
this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
});
} }
private registerViews(): void { private registerViews(): void {

View File

@@ -137,12 +137,12 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
const triedToMakeWriteable = isReadonly && fileOperationError.options && (fileOperationError.options as IWriteTextFileOptions).overwriteReadonly; const triedToMakeWriteable = isReadonly && fileOperationError.options && (fileOperationError.options as IWriteTextFileOptions).overwriteReadonly;
const isPermissionDenied = fileOperationError.fileOperationResult === FileOperationResult.FILE_PERMISSION_DENIED; const isPermissionDenied = fileOperationError.fileOperationResult === FileOperationResult.FILE_PERMISSION_DENIED;
// Save Elevated (TODO@remote cannot write elevated https://github.com/Microsoft/vscode/issues/48659) // Save Elevated (cannot write elevated https://github.com/Microsoft/vscode/issues/48659)
if (resource.scheme === Schemas.file && (isPermissionDenied || triedToMakeWriteable)) { if (resource.scheme === Schemas.file && (isPermissionDenied || triedToMakeWriteable)) {
actions.primary!.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable)); actions.primary!.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable));
} }
// Overwrite (TODO@remote cannot overwrite readonly https://github.com/Microsoft/vscode/issues/48659) // Overwrite (cannot overwrite readonly https://github.com/Microsoft/vscode/issues/48659)
else if (resource.scheme === Schemas.file && isReadonly) { else if (resource.scheme === Schemas.file && isReadonly) {
actions.primary!.push(this.instantiationService.createInstance(OverwriteReadonlyAction, model)); actions.primary!.push(this.instantiationService.createInstance(OverwriteReadonlyAction, model));
} }

View File

@@ -46,6 +46,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
import { findValidPasteFileTarget } from 'vs/workbench/contrib/files/browser/fileActions'; import { findValidPasteFileTarget } from 'vs/workbench/contrib/files/browser/fileActions';
import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> { export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
@@ -441,7 +442,8 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
@IInstantiationService private instantiationService: IInstantiationService, @IInstantiationService private instantiationService: IInstantiationService,
@ITextFileService private textFileService: ITextFileService, @ITextFileService private textFileService: ITextFileService,
@IWindowService private windowService: IWindowService, @IWindowService private windowService: IWindowService,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService
) { ) {
this.toDispose = []; this.toDispose = [];
@@ -472,6 +474,12 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
if (typesArray.indexOf(DataTransfers.FILES.toLowerCase()) === -1 && typesArray.indexOf(CodeDataTransfers.FILES.toLowerCase()) === -1) { if (typesArray.indexOf(DataTransfers.FILES.toLowerCase()) === -1 && typesArray.indexOf(CodeDataTransfers.FILES.toLowerCase()) === -1) {
return false; return false;
} }
if (this.environmentService.configuration.remoteAuthority) {
const resources = extractResources(originalEvent, true);
if (resources.some(r => r.resource.authority !== this.environmentService.configuration.remoteAuthority)) {
return false;
}
}
} }
// Other-Tree DND // Other-Tree DND

View File

@@ -229,7 +229,7 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride: platform.Platform = platform.platform): void { public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride: platform.Platform = platform.platform): void {
const isWorkspaceShellAllowed = this.checkWorkspaceShellPermissions(platformOverride === platform.Platform.Windows ? platform.OperatingSystem.Windows : (platformOverride === platform.Platform.Mac ? platform.OperatingSystem.Macintosh : platform.OperatingSystem.Linux)); const isWorkspaceShellAllowed = this.checkWorkspaceShellPermissions(platformOverride === platform.Platform.Windows ? platform.OperatingSystem.Windows : (platformOverride === platform.Platform.Mac ? platform.OperatingSystem.Macintosh : platform.OperatingSystem.Linux));
mergeDefaultShellPathAndArgs(shell, (key) => this._workspaceConfigurationService.inspect(key), isWorkspaceShellAllowed); mergeDefaultShellPathAndArgs(shell, (key) => this._workspaceConfigurationService.inspect(key), isWorkspaceShellAllowed, platformOverride);
} }
private _toInteger(source: any, minimum: number, maximum: number, fallback: number): number { private _toInteger(source: any, minimum: number, maximum: number, fallback: number): number {

View File

@@ -263,13 +263,13 @@ export class WorkspaceConfiguration extends Disposable {
this._workspaceIdentifier = workspaceIdentifier; this._workspaceIdentifier = workspaceIdentifier;
if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) {
if (this._workspaceIdentifier.configPath.scheme === Schemas.file) { if (this._workspaceIdentifier.configPath.scheme === Schemas.file) {
this.switch(); this.switch(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService));
} else { } else {
this.waitAndSwitch(this._workspaceIdentifier); this.waitAndSwitch(this._workspaceIdentifier);
} }
} }
await this._workspaceConfiguration.load(this._workspaceIdentifier);
this._loaded = this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration; this._loaded = this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration;
await this._workspaceConfiguration.load(this._workspaceIdentifier);
} }
reload(): Promise<void> { reload(): Promise<void> {
@@ -300,21 +300,25 @@ export class WorkspaceConfiguration extends Disposable {
private async waitAndSwitch(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> { private async waitAndSwitch(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
await this._configurationFileService.whenProviderRegistered(workspaceIdentifier.configPath.scheme); await this._configurationFileService.whenProviderRegistered(workspaceIdentifier.configPath.scheme);
if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) {
this.switch(); const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService));
await fileServiceBasedWorkspaceConfiguration.load(workspaceIdentifier);
this.switch(fileServiceBasedWorkspaceConfiguration);
this._loaded = true; this._loaded = true;
this.onDidWorkspaceConfigurationChange(); this.onDidWorkspaceConfigurationChange(false);
} }
} }
private switch(): void { private switch(fileServiceBasedWorkspaceConfiguration: FileServiceBasedWorkspaceConfiguration): void {
this._workspaceConfiguration.dispose(); this._workspaceConfiguration.dispose();
this._workspaceConfigurationChangeDisposable.dispose(); this._workspaceConfigurationChangeDisposable.dispose();
this._workspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService)); this._workspaceConfiguration = this._register(fileServiceBasedWorkspaceConfiguration);
this._workspaceConfigurationChangeDisposable = this._register(this._workspaceConfiguration.onDidChange(e => this.onDidWorkspaceConfigurationChange())); this._workspaceConfigurationChangeDisposable = this._register(this._workspaceConfiguration.onDidChange(e => this.onDidWorkspaceConfigurationChange(true)));
} }
private async onDidWorkspaceConfigurationChange(): Promise<void> { private async onDidWorkspaceConfigurationChange(reload: boolean): Promise<void> {
await this.reload(); if (reload) {
await this.reload();
}
this.updateCache(); this.updateCache();
this._onDidUpdateConfiguration.fire(); this._onDidUpdateConfiguration.fire();
} }

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { Disposable, IDisposable, toDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle'; import { Disposable, IDisposable, toDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent } from 'vs/platform/files/common/files'; import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
@@ -337,7 +337,7 @@ export class FileService extends Disposable implements IFileService {
// check for size is a weaker check because it can return a false negative if the file has changed // check for size is a weaker check because it can return a false negative if the file has changed
// but to the same length. This is a compromise we take to avoid having to produce checksums of // but to the same length. This is a compromise we take to avoid having to produce checksums of
// the file content for comparison which would be much slower to compute. // the file content for comparison which would be much slower to compute.
if (options && typeof options.mtime === 'number' && typeof options.etag === 'string' && options.mtime < stat.mtime && options.etag !== etag(stat.size, options.mtime)) { if (options && typeof options.mtime === 'number' && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED && options.mtime < stat.mtime && options.etag !== etag(stat.size, options.mtime)) {
throw new FileOperationError(localize('fileModifiedError', "File Modified Since"), FileOperationResult.FILE_MODIFIED_SINCE, options); throw new FileOperationError(localize('fileModifiedError', "File Modified Since"), FileOperationResult.FILE_MODIFIED_SINCE, options);
} }
@@ -375,7 +375,7 @@ export class FileService extends Disposable implements IFileService {
// due to the likelyhood of hitting a NOT_MODIFIED_SINCE result. // due to the likelyhood of hitting a NOT_MODIFIED_SINCE result.
// otherwise, we let it run in parallel to the file reading for // otherwise, we let it run in parallel to the file reading for
// optimal startup performance. // optimal startup performance.
if (options && options.etag) { if (options && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED) {
await statPromise; await statPromise;
} }
@@ -493,7 +493,7 @@ export class FileService extends Disposable implements IFileService {
} }
// Return early if file not modified since // Return early if file not modified since
if (options && options.etag && options.etag === stat.etag) { if (options && options.etag === stat.etag) {
throw new FileOperationError(localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE, options); throw new FileOperationError(localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE, options);
} }

View File

@@ -1491,7 +1491,11 @@ suite('Disk File Service', () => {
setTimeout(() => mkdirSync(folder.fsPath), 50); setTimeout(() => mkdirSync(folder.fsPath), 50);
}); });
test.skip('watch - folder (non recursive) - delete folder', done => { test('watch - folder (non recursive) - delete folder', done => {
if (isWindows) {
return done(); // not happy
}
const watchDir = URI.file(join(testDir, 'watch7')); const watchDir = URI.file(join(testDir, 'watch7'));
mkdirSync(watchDir.fsPath); mkdirSync(watchDir.fsPath);

View File

@@ -7,7 +7,7 @@ import 'vs/css!./media/progressService2';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IProgressService2, IProgressOptions, IProgressStep, ProgressLocation, IProgress, emptyProgress, Progress } from 'vs/platform/progress/common/progress'; import { IProgressService2, IProgressOptions, IProgressStep, ProgressLocation, IProgress, emptyProgress, Progress, IProgressNotificationOptions } from 'vs/platform/progress/common/progress';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { StatusbarAlignment, IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { StatusbarAlignment, IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { timeout } from 'vs/base/common/async'; import { timeout } from 'vs/base/common/async';
@@ -54,7 +54,7 @@ export class ProgressService2 implements IProgressService2 {
switch (location) { switch (location) {
case ProgressLocation.Notification: case ProgressLocation.Notification:
return this._withNotificationProgress(options, task, onDidCancel); return this._withNotificationProgress({ ...options, location: ProgressLocation.Notification }, task, onDidCancel);
case ProgressLocation.Window: case ProgressLocation.Window:
return this._withWindowProgress(options, task); return this._withWindowProgress(options, task);
case ProgressLocation.Explorer: case ProgressLocation.Explorer:
@@ -138,7 +138,7 @@ export class ProgressService2 implements IProgressService2 {
} }
} }
private _withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { private _withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P {
const toDispose: IDisposable[] = []; const toDispose: IDisposable[] = [];
const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => { const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => {
@@ -146,7 +146,7 @@ export class ProgressService2 implements IProgressService2 {
return undefined; // we need a message at least return undefined; // we need a message at least
} }
const actions: INotificationActions = { primary: [] }; const actions: INotificationActions = { primary: options.primaryActions || [], secondary: options.secondaryActions || [] };
if (options.cancellable) { if (options.cancellable) {
const cancelAction = new class extends Action { const cancelAction = new class extends Action {
constructor() { constructor() {

View File

@@ -16,7 +16,7 @@ import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorMo
import { EncodingMode } from 'vs/workbench/common/editor'; import { EncodingMode } from 'vs/workbench/common/editor';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, etag } from 'vs/platform/files/common/files'; import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, ETAG_DISABLED } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService'; import { IModelService } from 'vs/editor/common/services/modelService';
@@ -55,26 +55,35 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
get onDidStateChange(): Event<StateChange> { return this._onDidStateChange.event; } get onDidStateChange(): Event<StateChange> { return this._onDidStateChange.event; }
private resource: URI; private resource: URI;
private contentEncoding: string; // encoding as reported from disk private contentEncoding: string; // encoding as reported from disk
private preferredEncoding: string; // encoding as chosen by the user private preferredEncoding: string; // encoding as chosen by the user
private dirty: boolean;
private versionId: number; private versionId: number;
private bufferSavedVersionId: number; private bufferSavedVersionId: number;
private lastResolvedDiskStat: IFileStatWithMetadata;
private blockModelContentChange: boolean; private blockModelContentChange: boolean;
private createTextEditorModelPromise: Promise<TextFileEditorModel> | null;
private lastResolvedDiskStat: IFileStatWithMetadata;
private autoSaveAfterMillies?: number; private autoSaveAfterMillies?: number;
private autoSaveAfterMilliesEnabled: boolean; private autoSaveAfterMilliesEnabled: boolean;
private autoSaveDisposable?: IDisposable; private autoSaveDisposable?: IDisposable;
private saveSequentializer: SaveSequentializer;
private lastSaveAttemptTime: number;
private contentChangeEventScheduler: RunOnceScheduler; private contentChangeEventScheduler: RunOnceScheduler;
private orphanedChangeEventScheduler: RunOnceScheduler; private orphanedChangeEventScheduler: RunOnceScheduler;
private saveSequentializer: SaveSequentializer;
private disposed: boolean; private dirty: boolean;
private lastSaveAttemptTime: number;
private createTextEditorModelPromise: Promise<TextFileEditorModel> | null;
private inConflictMode: boolean; private inConflictMode: boolean;
private inOrphanMode: boolean; private inOrphanMode: boolean;
private inErrorMode: boolean; private inErrorMode: boolean;
private disposed: boolean;
constructor( constructor(
resource: URI, resource: URI,
preferredEncoding: string, preferredEncoding: string,
@@ -271,8 +280,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
name: basename(this.resource), name: basename(this.resource),
mtime: Date.now(), mtime: Date.now(),
size: 0, size: 0,
etag: etag(Date.now(), 0), etag: ETAG_DISABLED, // always allow to save content restored from a backup (see https://github.com/Microsoft/vscode/issues/72343)
value: createTextBufferFactory(''), /* will be filled later from backup */ value: createTextBufferFactory(''), // will be filled later from backup
encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding, encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding,
isReadonly: false isReadonly: false
}; };
@@ -754,10 +763,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
this.telemetryService.publicLog('filePUT', this.getTelemetryData(options.reason)); this.telemetryService.publicLog('filePUT', this.getTelemetryData(options.reason));
} }
}, error => { }, error => {
if (!error) {
error = new Error('Unknown Save Error'); // TODO@remote we should never get null as error (https://github.com/Microsoft/vscode/issues/55051)
}
this.logService.error(`doSave(${versionId}) - exit - resulted in a save error: ${error.toString()}`, this.resource); this.logService.error(`doSave(${versionId}) - exit - resulted in a save error: ${error.toString()}`, this.resource);
// Flag as error state in the model // Flag as error state in the model

View File

@@ -510,7 +510,6 @@ export abstract class TextFileService extends Disposable implements ITextFileSer
})); }));
} }
// Soft revert the dirty source files if any // Soft revert the dirty source files if any
await this.revertAll(dirtySourceModels.map(dirtySourceModel => dirtySourceModel.getResource()), { soft: true }); await this.revertAll(dirtySourceModels.map(dirtySourceModel => dirtySourceModel.getResource()), { soft: true });