Skip to content

Commit

Permalink
Implement WorkspaceEditMetadata and add new preference for autosave…
Browse files Browse the repository at this point in the history
… on refactoring (#12193)

Signed-off-by: Jonah Iden <[email protected]>
  • Loading branch information
jonah-iden authored Feb 22, 2023
1 parent 30edea7 commit f496793
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 14 deletions.
6 changes: 6 additions & 0 deletions packages/editor/src/browser/editor-preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ const fileContributionSchema: PreferenceSchema['properties'] = {
'minimum': 0,
'markdownDescription': nls.localizeByDefault('Controls the delay in milliseconds after which an editor with unsaved changes is saved automatically. Only applies when `#files.autoSave#` is set to `{0}`.', 'afterDelay')
},
'files.refactoring.autoSave': {
'type': 'boolean',
'default': true,
'description': nls.localizeByDefault('Controls if files that were part of a refactoring are saved automatically')
}
};

interface FileContributionEditorPreferences {
Expand All @@ -131,6 +136,7 @@ interface FileContributionEditorPreferences {
'files.eol': '\n' | '\r\n' | 'auto';
'files.autoSave': 'off' | 'afterDelay' | 'onFocusChange' | 'onWindowChange';
'files.autoSaveDelay': number;
'files.refactoring.autoSave': boolean
}
// #endregion

Expand Down
2 changes: 1 addition & 1 deletion packages/monaco/src/browser/monaco-bulk-edit-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class MonacoBulkEditService implements IBulkEditService {
editsIn = await this._previewHandler(edits, options);
return { ariaSummary: '', success: true };
} else {
return this.workspace.applyBulkEdit(edits);
return this.workspace.applyBulkEdit(edits, options);
}
}

Expand Down
23 changes: 21 additions & 2 deletions packages/monaco/src/browser/monaco-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { injectable, inject, postConstruct } from '@theia/core/shared/inversify'
import URI from '@theia/core/lib/common/uri';
import { Emitter } from '@theia/core/lib/common/event';
import { FileSystemPreferences } from '@theia/filesystem/lib/browser';
import { EditorManager } from '@theia/editor/lib/browser';
import { EditorManager, EditorPreferences } from '@theia/editor/lib/browser';
import { MonacoTextModelService } from './monaco-text-model-service';
import { WillSaveMonacoModelEvent, MonacoEditorModel, MonacoModelContentChangedEvent } from './monaco-editor-model';
import { MonacoEditor } from './monaco-editor';
Expand All @@ -31,6 +31,7 @@ import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { FileSystemProviderCapabilities } from '@theia/filesystem/lib/common/files';
import * as monaco from '@theia/monaco-editor-core';
import {
IBulkEditOptions,
IBulkEditResult, ResourceEdit, ResourceFileEdit as MonacoResourceFileEdit,
ResourceTextEdit as MonacoResourceTextEdit
} from '@theia/monaco-editor-core/esm/vs/editor/browser/services/bulkEditService';
Expand Down Expand Up @@ -111,6 +112,9 @@ export class MonacoWorkspace {
@inject(FileSystemPreferences)
protected readonly filePreferences: FileSystemPreferences;

@inject(EditorPreferences)
protected readonly editorPreferences: EditorPreferences;

@inject(MonacoTextModelService)
protected readonly textModelService: MonacoTextModelService;

Expand Down Expand Up @@ -226,7 +230,7 @@ export class MonacoWorkspace {
});
}

async applyBulkEdit(edits: ResourceEdit[]): Promise<IBulkEditResult & { success: boolean }> {
async applyBulkEdit(edits: ResourceEdit[], options?: IBulkEditOptions): Promise<IBulkEditResult & { success: boolean }> {
try {
let totalEdits = 0;
let totalFiles = 0;
Expand All @@ -248,6 +252,17 @@ export class MonacoWorkspace {
await this.performSnippetEdits(<MonacoResourceTextEdit[]>snippetEdits);
}

// when enabled (option AND setting) loop over all dirty working copies and trigger save
// for those that were involved in this bulk edit operation.
const resources = new Set<string>(
edits
.filter((edit): edit is MonacoResourceTextEdit => edit instanceof MonacoResourceTextEdit)
.map(edit => edit.resource.toString())
);
if (resources.size > 0 && options?.respectAutoSaveConfig && this.editorPreferences.get('files.refactoring.autoSave') === true) {
await this.saveAll(resources);
}

const ariaSummary = this.getAriaSummary(totalEdits, totalFiles);
return { ariaSummary, success: true };
} catch (e) {
Expand All @@ -259,6 +274,10 @@ export class MonacoWorkspace {
}
}

protected async saveAll(resources: Set<string>): Promise<void> {
await Promise.all(Array.from(resources.values()).map(uri => this.textModelService.get(uri)?.save()));
}

protected getAriaSummary(totalEdits: number, totalFiles: number): string {
if (totalEdits === 0) {
return 'Made no edits';
Expand Down
11 changes: 7 additions & 4 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1246,7 +1246,7 @@ export interface TextEditorsMain {
$tryRevealRange(id: string, range: Range, revealType: TextEditorRevealType): Promise<void>;
$trySetSelections(id: string, selections: Selection[]): Promise<void>;
$tryApplyEdits(id: string, modelVersionId: number, edits: SingleEditOperation[], opts: ApplyEditsOptions): Promise<boolean>;
$tryApplyWorkspaceEdit(workspaceEditDto: WorkspaceEditDto): Promise<boolean>;
$tryApplyWorkspaceEdit(workspaceEditDto: WorkspaceEditDto, metadata?: WorkspaceEditMetadataDto): Promise<boolean>;
$tryInsertSnippet(id: string, template: string, selections: Range[], opts: UndoStopOptions): Promise<boolean>;
$saveAll(includeUntitled?: boolean): Promise<boolean>;
// $getDiffInformation(id: string): Promise<editorCommon.ILineChange[]>;
Expand Down Expand Up @@ -1418,7 +1418,7 @@ export interface CodeActionDto {
disabled?: string;
}

export interface WorkspaceEditMetadataDto {
export interface WorkspaceEditEntryMetadataDto {
needsConfirmation: boolean;
label: string;
description?: string;
Expand All @@ -1434,14 +1434,14 @@ export interface WorkspaceFileEditDto {
oldResource?: UriComponents;
newResource?: UriComponents;
options?: FileOperationOptions;
metadata?: WorkspaceEditMetadataDto;
metadata?: WorkspaceEditEntryMetadataDto;
}

export interface WorkspaceTextEditDto {
resource: UriComponents;
modelVersionId?: number;
textEdit: TextEdit & { insertAsSnippet?: boolean };
metadata?: WorkspaceEditMetadataDto;
metadata?: WorkspaceEditEntryMetadataDto;
}
export namespace WorkspaceTextEditDto {
export function is(arg: WorkspaceTextEditDto | WorkspaceFileEditDto): arg is WorkspaceTextEditDto {
Expand All @@ -1452,6 +1452,9 @@ export namespace WorkspaceTextEditDto {
&& typeof arg.textEdit === 'object';
}
}
export interface WorkspaceEditMetadataDto {
isRefactoring?: boolean;
}

export interface WorkspaceEditDto {
edits: Array<WorkspaceTextEditDto | WorkspaceFileEditDto>;
Expand Down
5 changes: 3 additions & 2 deletions packages/plugin-ext/src/main/browser/text-editors-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
DecorationOptions,
WorkspaceEditDto,
DocumentsMain,
WorkspaceEditMetadataDto,
} from '../../common/plugin-api-rpc';
import { Range, TextDocumentShowOptions } from '../../common/plugin-api-rpc-model';
import { EditorsAndDocumentsMain } from './editors-and-documents-main';
Expand Down Expand Up @@ -126,11 +127,11 @@ export class TextEditorsMainImpl implements TextEditorsMain, Disposable {
return Promise.resolve(this.editorsAndDocuments.getEditor(id)!.applyEdits(modelVersionId, edits, opts));
}

async $tryApplyWorkspaceEdit(dto: WorkspaceEditDto): Promise<boolean> {
async $tryApplyWorkspaceEdit(dto: WorkspaceEditDto, metadata?: WorkspaceEditMetadataDto): Promise<boolean> {
const workspaceEdit = toMonacoWorkspaceEdit(dto);
try {
const edits = ResourceEdit.convert(workspaceEdit);
const { success } = await this.bulkEditService.apply(edits);
const { success } = await this.bulkEditService.apply(edits, { respectAutoSaveConfig: metadata?.isRefactoring });
return success;
} catch {
return false;
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,8 @@ export function createAPIFactory(
saveAll(includeUntitled?: boolean): PromiseLike<boolean> {
return editors.saveAll(includeUntitled);
},
applyEdit(edit: theia.WorkspaceEdit): PromiseLike<boolean> {
return editors.applyWorkspaceEdit(edit);
applyEdit(edit: theia.WorkspaceEdit, metadata?: theia.WorkspaceEditMetadata): PromiseLike<boolean> {
return editors.applyWorkspaceEdit(edit, metadata);
},
registerTextDocumentContentProvider(scheme: string, provider: theia.TextDocumentContentProvider): theia.Disposable {
return workspaceExt.registerTextDocumentContentProvider(scheme, provider);
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-ext/src/plugin/text-editors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ export class TextEditorsExtImpl implements TextEditorsExt {
return new TextEditorDecorationType(this.proxy, options);
}

applyWorkspaceEdit(edit: theia.WorkspaceEdit): Promise<boolean> {
applyWorkspaceEdit(edit: theia.WorkspaceEdit, metadata?: theia.WorkspaceEditMetadata): Promise<boolean> {
const dto = Converters.fromWorkspaceEdit(edit, this.editorsAndDocuments);
return this.proxy.$tryApplyWorkspaceEdit(dto);
return this.proxy.$tryApplyWorkspaceEdit(dto, metadata);
}

saveAll(includeUntitled?: boolean): PromiseLike<boolean> {
Expand Down
13 changes: 12 additions & 1 deletion packages/plugin/src/theia.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7205,9 +7205,10 @@ export module '@theia/plugin' {
* not be attempted, when a single edit fails.
*
* @param edit A workspace edit.
* @param metadata Optional {@link WorkspaceEditMetadata metadata} for the edit.
* @return A thenable that resolves when the edit could be applied.
*/
export function applyEdit(edit: WorkspaceEdit): Thenable<boolean>;
export function applyEdit(edit: WorkspaceEdit, metadata?: WorkspaceEditMetadata): Thenable<boolean>;

/**
* Register a filesystem provider for a given scheme, e.g. `ftp`.
Expand Down Expand Up @@ -9749,6 +9750,16 @@ export module '@theia/plugin' {
iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon;
}

/**
* Additional data about a workspace edit.
*/
export interface WorkspaceEditMetadata {
/**
* Signal to the editor that this edit is a refactoring.
*/
isRefactoring?: boolean;
}

/**
* A workspace edit is a collection of textual and files changes for
* multiple resources and documents.
Expand Down

0 comments on commit f496793

Please sign in to comment.