diff --git a/packages/editor/src/browser/doc-model/editor-document-model.ts b/packages/editor/src/browser/doc-model/editor-document-model.ts index 377beedabc..7f66785552 100644 --- a/packages/editor/src/browser/doc-model/editor-document-model.ts +++ b/packages/editor/src/browser/doc-model/editor-document-model.ts @@ -157,7 +157,7 @@ export class EditorDocumentModel extends Disposable implements IEditorDocumentMo }); } this._previousVersionId = e.versionId; - this.notifyChangeEvent(e.changes); + this.notifyChangeEvent(e.changes, e.isRedoing, e.isUndoing); }); this.addDispose(monacoModel); @@ -215,7 +215,7 @@ export class EditorDocumentModel extends Disposable implements IEditorDocumentMo (this.monacoModel as any)._commandManager.clear(); this._persistVersionId = this.monacoModel.getAlternativeVersionId(); this.savingTasks = []; - this.notifyChangeEvent(); + this.notifyChangeEvent([], false, false); this.baseContent = content; } @@ -366,7 +366,7 @@ export class EditorDocumentModel extends Disposable implements IEditorDocumentMo setPersist(versionId: number) { this._persistVersionId = versionId; - this.notifyChangeEvent(); + this.notifyChangeEvent([], false, false); } async reload() { @@ -451,7 +451,7 @@ export class EditorDocumentModel extends Disposable implements IEditorDocumentMo return this._baseContentMd5!; } - private notifyChangeEvent(changes: IEditorDocumentModelContentChange[] = []) { + private notifyChangeEvent(changes: IEditorDocumentModelContentChange[] = [], isRedoing: boolean, isUndoing: boolean) { if (!this.closeAutoSave && this.savable && this.editorPreferences['editor.autoSave'] === 'afterDelay') { this.tryAutoSaveAfterDelay(); } @@ -461,6 +461,8 @@ export class EditorDocumentModel extends Disposable implements IEditorDocumentMo dirty: this.dirty, changes, eol: this.eol, + isRedoing, + isUndoing, versionId: this.monacoModel.getVersionId(), })); diff --git a/packages/editor/src/browser/doc-model/types.ts b/packages/editor/src/browser/doc-model/types.ts index ef659c673d..59e8611e8d 100644 --- a/packages/editor/src/browser/doc-model/types.ts +++ b/packages/editor/src/browser/doc-model/types.ts @@ -243,6 +243,8 @@ export interface IEditorDocumentModelContentChangedEventPayload { changes: IEditorDocumentModelContentChange[]; eol: string; versionId: number; + isRedoing: boolean; + isUndoing: boolean; } export class EditorDocumentModelOptionChangedEvent extends BasicEvent {} diff --git a/packages/extension/src/browser/vscode/api/main.thread.doc.ts b/packages/extension/src/browser/vscode/api/main.thread.doc.ts index 319392c685..c17dad93bf 100644 --- a/packages/extension/src/browser/vscode/api/main.thread.doc.ts +++ b/packages/extension/src/browser/vscode/api/main.thread.doc.ts @@ -127,12 +127,15 @@ export class MainThreadExtensionDocumentData extends WithEventBus implements IMa if (!this.isDocSyncEnabled(e.payload.uri)) { return; } + this.proxy.$fireModelChangedEvent({ changes: e.payload.changes, uri: e.payload.uri.toString(), eol: e.payload.eol, dirty: e.payload.dirty, versionId: e.payload.versionId, + isRedoing: e.payload.isRedoing, + isUndoing: e.payload.isUndoing, }); } diff --git a/packages/extension/src/common/vscode/doc.ts b/packages/extension/src/common/vscode/doc.ts index 9dbd061a4f..826459bb30 100644 --- a/packages/extension/src/common/vscode/doc.ts +++ b/packages/extension/src/common/vscode/doc.ts @@ -16,6 +16,14 @@ export interface IModelChangedEvent { * The new version id the model has transitioned to. */ readonly versionId: number; + /** + * Flag that indicates that this event was generated while undoing. + */ + readonly isUndoing: boolean; + /** + * Flag that indicates that this event was generated while redoing. + */ + readonly isRedoing: boolean; } export interface IMainThreadDocumentsShape extends IDisposable { @@ -51,6 +59,8 @@ export interface IExtensionDocumentModelChangedEvent { versionId: number; eol: string; dirty: boolean; + isRedoing: boolean; + isUndoing: boolean; } export interface IExtensionDocumentModelOptionsChangedEvent { diff --git a/packages/extension/src/common/vscode/ext-types.ts b/packages/extension/src/common/vscode/ext-types.ts index 1abf136519..79076263ef 100644 --- a/packages/extension/src/common/vscode/ext-types.ts +++ b/packages/extension/src/common/vscode/ext-types.ts @@ -1811,6 +1811,11 @@ export enum TextDocumentSaveReason { FocusOut = 3, } +export enum TextDocumentChangeReason { + Undo = 1, + Redo = 2, +} + export { TextEditorRevealType } from './editor'; @es5ClassCompat diff --git a/packages/extension/src/hosted/api/vscode/doc/doc-manager.host.ts b/packages/extension/src/hosted/api/vscode/doc/doc-manager.host.ts index 03fb01f00a..9d7c0b8f9b 100644 --- a/packages/extension/src/hosted/api/vscode/doc/doc-manager.host.ts +++ b/packages/extension/src/hosted/api/vscode/doc/doc-manager.host.ts @@ -4,7 +4,7 @@ import type vscode from 'vscode'; import { ExtensionDocumentDataManager, IExtensionDocumentModelChangedEvent, IExtensionDocumentModelOpenedEvent, IExtensionDocumentModelOptionsChangedEvent, IExtensionDocumentModelRemovedEvent, IExtensionDocumentModelSavedEvent, IExtensionDocumentModelWillSaveEvent, IMainThreadDocumentsShape, IMainThreadWorkspace, MainThreadAPIIdentifier } from '../../../../common/vscode'; import { TextEdit as TextEditConverter, toRange } from '../../../../common/vscode/converter'; -import { TextEdit, Uri } from '../../../../common/vscode/ext-types'; +import { TextDocumentChangeReason, TextEdit, Uri } from '../../../../common/vscode/ext-types'; import type * as model from '../../../../common/vscode/model.api'; import { ExtHostDocumentData, setWordDefinitionFor } from './ext-data.host'; import { BinaryBuffer } from '@opensumi/ide-core-common/lib/utils/buffer'; @@ -16,7 +16,6 @@ export class ExtensionDocumentDataManagerImpl implements ExtensionDocumentDataMa private readonly rpcProtocol: IRPCProtocol; private readonly _proxy: IMainThreadDocumentsShape; private readonly _workspaceProxy: IMainThreadWorkspace; - private readonly _logService: any; private _documents: Map = new Map(); private _contentProviders: Map = new Map(); @@ -37,12 +36,6 @@ export class ExtensionDocumentDataManagerImpl implements ExtensionDocumentDataMa this.rpcProtocol = rpcProtocol; this._proxy = this.rpcProtocol.getProxy(MainThreadAPIIdentifier.MainThreadDocuments); this._workspaceProxy = this.rpcProtocol.getProxy(MainThreadAPIIdentifier.MainThreadWorkspace); - this._logService = { - trace() { - // tslint:disable-next-line:no-console - console.log.apply(console, arguments as any); - }, - }; } get allDocumentData() { @@ -166,27 +159,38 @@ export class ExtensionDocumentDataManagerImpl implements ExtensionDocumentDataMa } $fireModelChangedEvent(e: IExtensionDocumentModelChangedEvent) { - const { uri, changes, versionId, eol, dirty } = e; + const { uri, changes, versionId, eol, dirty, isRedoing, isUndoing } = e; const document = this._documents.get(uri); - if (document) { - document.onEvents({ - eol, - versionId, - changes, - }); - document._acceptIsDirty(dirty); - this._onDidChangeTextDocument.fire({ - document: document.document, - contentChanges: changes.map((change) => { - return { - ...change, - range: toRange(change.range) as any, - }; - }), - }); - } else { - // TODO: 增加消息后台未接受到的情况 + if (!document) { + return; } + document.onEvents({ + eol, + versionId, + changes, + isRedoing, + isUndoing, + }); + document._acceptIsDirty(dirty); + + let reason: vscode.TextDocumentChangeReason | undefined; + + if (isRedoing) { + reason = TextDocumentChangeReason.Redo; + } else if (isUndoing) { + reason = TextDocumentChangeReason.Undo; + } + + this._onDidChangeTextDocument.fire({ + document: document.document, + contentChanges: changes.map((change) => { + return { + ...change, + range: toRange(change.range) as any, + }; + }), + reason, + }); } $fireModelOpenedEvent(e: IExtensionDocumentModelOpenedEvent) { diff --git a/packages/types/sumi-worker/sumi-worker.d.ts b/packages/types/sumi-worker/sumi-worker.d.ts index 0a3f959e07..5cb7861da3 100644 --- a/packages/types/sumi-worker/sumi-worker.d.ts +++ b/packages/types/sumi-worker/sumi-worker.d.ts @@ -1679,6 +1679,14 @@ declare module 'sumi-worker' { dispose(): void; } + export enum TextDocumentChangeReason { + /** The text change is caused by an undo operation. */ + Undo = 1, + + /** The text change is caused by an redo operation. */ + Redo = 2, + } + /** * An event describing a transactional [document](#TextDocument) change. */ @@ -1693,6 +1701,12 @@ declare module 'sumi-worker' { * An array of content changes. */ readonly contentChanges: ReadonlyArray; + + /** + * The reason why the document was changed. + * Is `undefined` if the reason is not known. + */ + readonly reason: TextDocumentChangeReason | undefined; } /** diff --git a/packages/types/vscode/typings/vscode.d.ts b/packages/types/vscode/typings/vscode.d.ts index 47ab5919e5..fa7e7ab347 100644 --- a/packages/types/vscode/typings/vscode.d.ts +++ b/packages/types/vscode/typings/vscode.d.ts @@ -2197,6 +2197,14 @@ declare module 'vscode' { dispose(): void; } + export enum TextDocumentChangeReason { + /** The text change is caused by an undo operation. */ + Undo = 1, + + /** The text change is caused by an redo operation. */ + Redo = 2, + } + /** * An event describing a transactional [document](#TextDocument) change. */ @@ -2211,6 +2219,12 @@ declare module 'vscode' { * An array of content changes. */ readonly contentChanges: ReadonlyArray; + + /** + * The reason why the document was changed. + * Is `undefined` if the reason is not known. + */ + readonly reason: TextDocumentChangeReason | undefined; } /**