未验证 提交 f8e068f3 编写于 作者: A Alex Dima

Fixes #98750: Do not remove all undo/redo elements when an undo/redo key is shared

上级 c4df96bb
......@@ -168,6 +168,11 @@ export class SingleModelEditStackElement implements IResourceUndoRedoElement {
this._data = SingleModelEditStackData.create(model, beforeCursorState);
}
public matchesResource(resource: URI): boolean {
const uri = (URI.isUri(this.model) ? this.model : this.model.uri);
return (uri.toString() === resource.toString());
}
public setModel(model: ITextModel | URI): void {
this.model = model;
}
......@@ -270,6 +275,11 @@ export class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {
return result;
}
public matchesResource(resource: URI): boolean {
const key = uriGetComparisonKey(resource);
return (this._editStackElementsMap.has(key));
}
public setModel(model: ITextModel | URI): void {
const key = uriGetComparisonKey(URI.isUri(model) ? model : model.uri);
if (this._editStackElementsMap.has(key)) {
......@@ -338,7 +348,7 @@ function getModelEOL(model: ITextModel): EndOfLineSequence {
}
}
function isKnownStackElement(element: IResourceUndoRedoElement | IWorkspaceUndoRedoElement | null): element is EditStackElement {
export function isEditStackElement(element: IResourceUndoRedoElement | IWorkspaceUndoRedoElement | null): element is EditStackElement {
if (!element) {
return false;
}
......@@ -357,7 +367,7 @@ export class EditStack {
public pushStackElement(): void {
const lastElement = this._undoRedoService.getLastElement(this._model.uri);
if (isKnownStackElement(lastElement)) {
if (isEditStackElement(lastElement)) {
lastElement.close();
}
}
......@@ -368,7 +378,7 @@ export class EditStack {
private _getOrCreateEditStackElement(beforeCursorState: Selection[] | null): EditStackElement {
const lastElement = this._undoRedoService.getLastElement(this._model.uri);
if (isKnownStackElement(lastElement) && lastElement.canAppend(this._model)) {
if (isEditStackElement(lastElement) && lastElement.canAppend(this._model)) {
return lastElement;
}
const newElement = new SingleModelEditStackElement(this._model, beforeCursorState);
......
......@@ -26,7 +26,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ILogService } from 'vs/platform/log/common/log';
import { IUndoRedoService, IUndoRedoElement, IPastFutureElements } from 'vs/platform/undoRedo/common/undoRedo';
import { StringSHA1 } from 'vs/base/common/hash';
import { SingleModelEditStackElement, MultiModelEditStackElement, EditStackElement } from 'vs/editor/common/model/editStack';
import { SingleModelEditStackElement, MultiModelEditStackElement, EditStackElement, isEditStackElement } from 'vs/editor/common/model/editStack';
import { Schemas } from 'vs/base/common/network';
import { SemanticTokensProviderStyling, toMultilineTokens2 } from 'vs/editor/common/services/semanticTokensProviderStyling';
......@@ -139,6 +139,7 @@ class DisposedModelInfo {
constructor(
public readonly uri: URI,
public readonly time: number,
public readonly sharesUndoRedoStack: boolean,
public readonly heapSize: number,
public readonly sha1: string,
public readonly versionId: number,
......@@ -352,7 +353,11 @@ export class ModelServiceImpl extends Disposable implements IModelService {
if (this._disposedModelsHeapSize > maxModelsHeapSize) {
// we must remove some old undo stack elements to free up some memory
const disposedModels: DisposedModelInfo[] = [];
this._disposedModels.forEach(entry => disposedModels.push(entry));
this._disposedModels.forEach(entry => {
if (!entry.sharesUndoRedoStack) {
disposedModels.push(entry);
}
});
disposedModels.sort((a, b) => a.time - b.time);
while (disposedModels.length > 0 && this._disposedModelsHeapSize > maxModelsHeapSize) {
const disposedModel = disposedModels.shift()!;
......@@ -369,16 +374,23 @@ export class ModelServiceImpl extends Disposable implements IModelService {
if (resource && this._disposedModels.has(MODEL_ID(resource))) {
const disposedModelData = this._removeDisposedModel(resource)!;
const elements = this._undoRedoService.getElements(resource);
if (computeModelSha1(model) === disposedModelData.sha1 && isEditStackPastFutureElements(elements)) {
const sha1IsEqual = (computeModelSha1(model) === disposedModelData.sha1);
if (sha1IsEqual || disposedModelData.sharesUndoRedoStack) {
for (const element of elements.past) {
element.setModel(model);
if (isEditStackElement(element) && element.matchesResource(resource)) {
element.setModel(model);
}
}
for (const element of elements.future) {
element.setModel(model);
if (isEditStackElement(element) && element.matchesResource(resource)) {
element.setModel(model);
}
}
this._undoRedoService.setElementsValidFlag(resource, true, (element) => (isEditStackElement(element) && element.matchesResource(resource)));
if (sha1IsEqual) {
model._overwriteVersionId(disposedModelData.versionId);
model._overwriteAlternativeVersionId(disposedModelData.alternativeVersionId);
}
this._undoRedoService.setElementsIsValid(resource, true);
model._overwriteVersionId(disposedModelData.versionId);
model._overwriteAlternativeVersionId(disposedModelData.alternativeVersionId);
} else {
this._undoRedoService.removeElements(resource);
}
......@@ -504,31 +516,39 @@ export class ModelServiceImpl extends Disposable implements IModelService {
return;
}
const model = modelData.model;
const sharesUndoRedoStack = (this._undoRedoService.getUriComparisonKey(model.uri) !== model.uri.toString());
let maintainUndoRedoStack = false;
let heapSize = 0;
if (this._shouldRestoreUndoStack() && (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote || resource.scheme === Schemas.userData)) {
if (sharesUndoRedoStack || (this._shouldRestoreUndoStack() && (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote || resource.scheme === Schemas.userData))) {
const elements = this._undoRedoService.getElements(resource);
if ((elements.past.length > 0 || elements.future.length > 0) && isEditStackPastFutureElements(elements)) {
maintainUndoRedoStack = true;
if (elements.past.length > 0 || elements.future.length > 0) {
for (const element of elements.past) {
heapSize += element.heapSize(resource);
element.setModel(resource); // remove reference from text buffer instance
if (isEditStackElement(element) && element.matchesResource(resource)) {
maintainUndoRedoStack = true;
heapSize += element.heapSize(resource);
element.setModel(resource); // remove reference from text buffer instance
}
}
for (const element of elements.future) {
heapSize += element.heapSize(resource);
element.setModel(resource); // remove reference from text buffer instance
if (isEditStackElement(element) && element.matchesResource(resource)) {
maintainUndoRedoStack = true;
heapSize += element.heapSize(resource);
element.setModel(resource); // remove reference from text buffer instance
}
}
}
}
if (!maintainUndoRedoStack) {
this._undoRedoService.removeElements(resource);
if (!sharesUndoRedoStack) {
this._undoRedoService.removeElements(resource);
}
modelData.model.dispose();
return;
}
const maxMemory = ModelServiceImpl.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK;
if (heapSize > maxMemory) {
if (!sharesUndoRedoStack && heapSize > maxMemory) {
// the undo stack for this file would never fit in the configured memory, so don't bother with it.
this._undoRedoService.removeElements(resource);
modelData.model.dispose();
......@@ -538,8 +558,8 @@ export class ModelServiceImpl extends Disposable implements IModelService {
this._ensureDisposedModelsHeapSize(maxMemory - heapSize);
// We only invalidate the elements, but they remain in the undo-redo service.
this._undoRedoService.setElementsIsValid(resource, false);
this._insertDisposedModel(new DisposedModelInfo(resource, Date.now(), heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
this._undoRedoService.setElementsValidFlag(resource, false, (element) => (isEditStackElement(element) && element.matchesResource(resource)));
this._insertDisposedModel(new DisposedModelInfo(resource, Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
modelData.model.dispose();
}
......
......@@ -57,6 +57,8 @@ export interface IUndoRedoService {
registerUriComparisonKeyComputer(uriComparisonKeyComputer: UriComparisonKeyComputer): IDisposable;
getUriComparisonKey(resource: URI): string;
/**
* Add a new element to the `undo` stack.
* This will destroy the `redo` stack.
......@@ -72,7 +74,7 @@ export interface IUndoRedoService {
hasElements(resource: URI): boolean;
setElementsIsValid(resource: URI, isValid: boolean): void;
setElementsValidFlag(resource: URI, isValid: boolean, filter: (element: IUndoRedoElement) => boolean): void;
/**
* Remove elements that target `resource`.
......
......@@ -201,6 +201,27 @@ class ResourceEditStack {
}
}
private _setElementValidFlag(element: StackElement, isValid: boolean): void {
if (element.type === UndoRedoElementType.Workspace) {
element.setValid(this.resourceLabel, this.strResource, isValid);
} else {
element.setValid(isValid);
}
}
public setElementsValidFlag(isValid: boolean, filter: (element: IUndoRedoElement) => boolean): void {
for (const element of this._past) {
if (filter(element.actual)) {
this._setElementValidFlag(element, isValid);
}
}
for (const element of this._future) {
if (filter(element.actual)) {
this._setElementValidFlag(element, isValid);
}
}
}
public pushElement(element: StackElement): void {
// remove the future
for (const futureElement of this._future) {
......@@ -352,7 +373,7 @@ export class UndoRedoService implements IUndoRedoService {
};
}
private _uriGetComparisonKey(resource: URI): string {
public getUriComparisonKey(resource: URI): string {
for (const uriComparisonKeyComputer of this._uriComparisonKeyComputers) {
const result = uriComparisonKeyComputer.getComparisonKey(resource);
if (result !== null) {
......@@ -365,7 +386,7 @@ export class UndoRedoService implements IUndoRedoService {
public pushElement(element: IUndoRedoElement): void {
if (element.type === UndoRedoElementType.Resource) {
const resourceLabel = getResourceLabel(element.resource);
const strResource = this._uriGetComparisonKey(element.resource);
const strResource = this.getUriComparisonKey(element.resource);
this._pushElement(new ResourceStackElement(element, resourceLabel, strResource));
} else {
const seen = new Set<string>();
......@@ -373,7 +394,7 @@ export class UndoRedoService implements IUndoRedoService {
const strResources: string[] = [];
for (const resource of element.resources) {
const resourceLabel = getResourceLabel(resource);
const strResource = this._uriGetComparisonKey(resource);
const strResource = this.getUriComparisonKey(resource);
if (seen.has(strResource)) {
continue;
......@@ -409,7 +430,7 @@ export class UndoRedoService implements IUndoRedoService {
}
public getLastElement(resource: URI): IUndoRedoElement | null {
const strResource = this._uriGetComparisonKey(resource);
const strResource = this.getUriComparisonKey(resource);
if (this._editStacks.has(strResource)) {
const editStack = this._editStacks.get(strResource)!;
if (editStack.hasFutureElements()) {
......@@ -426,7 +447,7 @@ export class UndoRedoService implements IUndoRedoService {
const individualMap = new Map<string, ResourceStackElement>();
for (const _element of individualArr) {
const resourceLabel = getResourceLabel(_element.resource);
const strResource = this._uriGetComparisonKey(_element.resource);
const strResource = this.getUriComparisonKey(_element.resource);
const element = new ResourceStackElement(_element, resourceLabel, strResource);
individualMap.set(element.strResource, element);
}
......@@ -445,7 +466,7 @@ export class UndoRedoService implements IUndoRedoService {
const individualMap = new Map<string, ResourceStackElement>();
for (const _element of individualArr) {
const resourceLabel = getResourceLabel(_element.resource);
const strResource = this._uriGetComparisonKey(_element.resource);
const strResource = this.getUriComparisonKey(_element.resource);
const element = new ResourceStackElement(_element, resourceLabel, strResource);
individualMap.set(element.strResource, element);
}
......@@ -460,7 +481,7 @@ export class UndoRedoService implements IUndoRedoService {
}
public removeElements(resource: URI | string): void {
const strResource = typeof resource === 'string' ? resource : this._uriGetComparisonKey(resource);
const strResource = typeof resource === 'string' ? resource : this.getUriComparisonKey(resource);
if (this._editStacks.has(strResource)) {
const editStack = this._editStacks.get(strResource)!;
editStack.dispose();
......@@ -468,18 +489,16 @@ export class UndoRedoService implements IUndoRedoService {
}
}
public setElementsIsValid(resource: URI, isValid: boolean): void {
const strResource = this._uriGetComparisonKey(resource);
public setElementsValidFlag(resource: URI, isValid: boolean, filter: (element: IUndoRedoElement) => boolean): void {
const strResource = this.getUriComparisonKey(resource);
if (this._editStacks.has(strResource)) {
const editStack = this._editStacks.get(strResource)!;
editStack.setElementsIsValid(isValid);
editStack.setElementsValidFlag(isValid, filter);
}
}
// resource
public hasElements(resource: URI): boolean {
const strResource = this._uriGetComparisonKey(resource);
const strResource = this.getUriComparisonKey(resource);
if (this._editStacks.has(strResource)) {
const editStack = this._editStacks.get(strResource)!;
return (editStack.hasPastElements() || editStack.hasFutureElements());
......@@ -488,7 +507,7 @@ export class UndoRedoService implements IUndoRedoService {
}
public getElements(resource: URI): IPastFutureElements {
const strResource = this._uriGetComparisonKey(resource);
const strResource = this.getUriComparisonKey(resource);
if (this._editStacks.has(strResource)) {
const editStack = this._editStacks.get(strResource)!;
return editStack.getElements();
......@@ -497,7 +516,7 @@ export class UndoRedoService implements IUndoRedoService {
}
public canUndo(resource: URI): boolean {
const strResource = this._uriGetComparisonKey(resource);
const strResource = this.getUriComparisonKey(resource);
if (this._editStacks.has(strResource)) {
const editStack = this._editStacks.get(strResource)!;
return editStack.hasPastElements();
......@@ -744,7 +763,7 @@ export class UndoRedoService implements IUndoRedoService {
}
public undo(resource: URI | string): Promise<void> | void {
const strResource = typeof resource === 'string' ? resource : this._uriGetComparisonKey(resource);
const strResource = typeof resource === 'string' ? resource : this.getUriComparisonKey(resource);
if (!this._editStacks.has(strResource)) {
return;
}
......@@ -763,7 +782,7 @@ export class UndoRedoService implements IUndoRedoService {
}
public canRedo(resource: URI): boolean {
const strResource = this._uriGetComparisonKey(resource);
const strResource = this.getUriComparisonKey(resource);
if (this._editStacks.has(strResource)) {
const editStack = this._editStacks.get(strResource)!;
return editStack.hasFutureElements();
......@@ -873,7 +892,7 @@ export class UndoRedoService implements IUndoRedoService {
}
public redo(resource: URI | string): Promise<void> | void {
const strResource = typeof resource === 'string' ? resource : this._uriGetComparisonKey(resource);
const strResource = typeof resource === 'string' ? resource : this.getUriComparisonKey(resource);
if (!this._editStacks.has(strResource)) {
return;
}
......
......@@ -135,14 +135,7 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri
return null;
}
return data.notebook.scheme + ':' + data.notebook.fsPath;
// const documentUri = this._resourceMapping.get(data.notebook)?.resource;
// if (documentUri) {
// return documentUri.toString();
// }
// return null;
return data.notebook.toString();
}
}));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册