Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions src/extension/inlineEdits/common/editRebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { SingleEdits } from '../../../platform/inlineEdits/common/dataTypes/edit';
import * as errors from '../../../util/common/errors';
import { ITracer } from '../../../util/common/tracing';
import { ILogger } from '../../../platform/log/common/logService';
import { AnnotatedStringEdit, AnnotatedStringReplacement, IEditData, StringEdit, StringReplacement, VoidEditData } from '../../../util/vs/editor/common/core/edits/stringEdit';
import { OffsetRange } from '../../../util/vs/editor/common/core/ranges/offsetRange';
import { StringText } from '../../../util/vs/editor/common/core/text/abstractText';
Expand All @@ -30,20 +30,20 @@ export class EditDataWithIndex implements IEditData<EditDataWithIndex> {
}
}

export function tryRebase(originalDocument: string, editWindow: OffsetRange | undefined, originalEdits: readonly StringReplacement[], detailedEdits: AnnotatedStringReplacement<EditDataWithIndex>[][], userEditSince: StringEdit, currentDocumentContent: string, currentSelection: readonly OffsetRange[], resolution: 'strict' | 'lenient', tracer: ITracer, nesConfigs: NesRebaseConfigs = {}): { rebasedEdit: StringReplacement; rebasedEditIndex: number }[] | 'outsideEditWindow' | 'rebaseFailed' | 'error' | 'inconsistentEdits' {
export function tryRebase(originalDocument: string, editWindow: OffsetRange | undefined, originalEdits: readonly StringReplacement[], detailedEdits: AnnotatedStringReplacement<EditDataWithIndex>[][], userEditSince: StringEdit, currentDocumentContent: string, currentSelection: readonly OffsetRange[], resolution: 'strict' | 'lenient', logger: ILogger, nesConfigs: NesRebaseConfigs = {}): { rebasedEdit: StringReplacement; rebasedEditIndex: number }[] | 'outsideEditWindow' | 'rebaseFailed' | 'error' | 'inconsistentEdits' {
const start = Date.now();
try {
return _tryRebase(originalDocument, editWindow, originalEdits, detailedEdits, userEditSince, currentDocumentContent, currentSelection, resolution, tracer, nesConfigs);
return _tryRebase(originalDocument, editWindow, originalEdits, detailedEdits, userEditSince, currentDocumentContent, currentSelection, resolution, logger, nesConfigs);
} catch (err) {
tracer.trace(`Rebase error: ${errors.toString(err)}`);
logger.trace(`Rebase error: ${errors.toString(err)}`);
return 'error';
} finally {
tracer.trace(`Rebase duration: ${Date.now() - start}ms`);
logger.trace(`Rebase duration: ${Date.now() - start}ms`);
}
}

function _tryRebase(originalDocument: string, editWindow: OffsetRange | undefined, originalEdits: readonly StringReplacement[], detailedEdits: AnnotatedStringReplacement<EditDataWithIndex>[][], userEditSinceOrig: StringEdit, currentDocumentContent: string, currentSelection: readonly OffsetRange[], resolution: 'strict' | 'lenient', tracer: ITracer, nesConfigs: NesRebaseConfigs) {
if (!checkEditConsistency(originalDocument, userEditSinceOrig, currentDocumentContent, tracer, true)) {
function _tryRebase(originalDocument: string, editWindow: OffsetRange | undefined, originalEdits: readonly StringReplacement[], detailedEdits: AnnotatedStringReplacement<EditDataWithIndex>[][], userEditSinceOrig: StringEdit, currentDocumentContent: string, currentSelection: readonly OffsetRange[], resolution: 'strict' | 'lenient', logger: ILogger, nesConfigs: NesRebaseConfigs) {
if (!checkEditConsistency(originalDocument, userEditSinceOrig, currentDocumentContent, logger, true)) {
return 'inconsistentEdits';
}
const userEditSince = userEditSinceOrig.removeCommonSuffixAndPrefix(originalDocument);
Expand Down Expand Up @@ -101,19 +101,19 @@ function _tryRebase(originalDocument: string, editWindow: OffsetRange | undefine
}
}
if (resolution === 'strict' && resultEdits.length > 0 && new SingleEdits(originalEdits).apply(originalDocument) !== StringEdit.create(resultEdits.map(r => r.rebasedEdit)).apply(currentDocumentContent)) {
tracer.trace('Result consistency check failed.');
logger.trace('Result consistency check failed');
return 'inconsistentEdits';
}
return resultEdits;
}

export function checkEditConsistency(original: string, edit: StringEdit, current: string, tracer: ITracer, enabled = TROUBLESHOOT_EDIT_CONSISTENCY) {
export function checkEditConsistency(original: string, edit: StringEdit, current: string, logger: ILogger, enabled = TROUBLESHOOT_EDIT_CONSISTENCY) {
if (!enabled) {
return true;
}
const consistent = edit.apply(original) === current;
if (!consistent) {
tracer.trace('Edit consistency check failed.');
logger.trace('Edit consistency check failed');
}
return consistent;
}
Expand Down
22 changes: 11 additions & 11 deletions src/extension/inlineEdits/common/rejectionCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { DocumentId } from '../../../platform/inlineEdits/common/dataTypes/documentId';
import { IObservableDocument, ObservableWorkspace } from '../../../platform/inlineEdits/common/observableWorkspace';
import { autorunWithChanges } from '../../../platform/inlineEdits/common/utils/observable';
import { createTracer, ITracer } from '../../../util/common/tracing';
import { ILogger, ILogService } from '../../../platform/log/common/logService';
import { Disposable, IDisposable, toDisposable } from '../../../util/vs/base/common/lifecycle';
import { mapObservableArrayCached } from '../../../util/vs/base/common/observable';
import { StringEdit, StringReplacement } from '../../../util/vs/editor/common/core/edits/stringEdit';
Expand All @@ -15,18 +15,18 @@ import { StringText } from '../../../util/vs/editor/common/core/text/abstractTex
export class RejectionCollector extends Disposable {
private readonly _garbageCollector = this._register(new LRUGarbageCollector(20));
private readonly _documentCaches = new Map<DocumentId, DocumentRejectionTracker>();
private readonly _tracer: ITracer;
private readonly _logger: ILogger;

constructor(
public readonly workspace: ObservableWorkspace,
trace: (s: string) => void,
logService: ILogService,
) {
super();

this._tracer = createTracer(['NES', 'RejectionCollector'], trace);
this._logger = logService.createSubLogger(['NES', 'RejectionCollector']);

mapObservableArrayCached(this, workspace.openDocuments, (doc, store) => {
const state = new DocumentRejectionTracker(doc, this._garbageCollector, this._tracer);
const state = new DocumentRejectionTracker(doc, this._garbageCollector, this._logger);
this._documentCaches.set(state.doc.id, state);

store.add(autorunWithChanges(this, {
Expand All @@ -48,23 +48,23 @@ export class RejectionCollector extends Disposable {
public reject(docId: DocumentId, edit: StringReplacement): void {
const docCache = this._documentCaches.get(docId);
if (!docCache) {
this._tracer.trace(`Rejecting, no document cache: ${edit}`);
this._logger.trace(`Rejecting, no document cache: ${edit}`);
return;
}
const e = edit.removeCommonSuffixAndPrefix(docCache.doc.value.get().value);
this._tracer.trace(`Rejecting: ${e}`);
this._logger.trace(`Rejecting: ${e}`);
docCache.reject(e);
}

public isRejected(docId: DocumentId, edit: StringReplacement): boolean {
const docCache = this._documentCaches.get(docId);
if (!docCache) {
this._tracer.trace(`Checking rejection, no document cache: ${edit}`);
this._logger.trace(`Checking rejection, no document cache: ${edit}`);
return false;
}
const e = edit.removeCommonSuffixAndPrefix(docCache.doc.value.get().value);
const isRejected = docCache.isRejected(e);
this._tracer.trace(`Checking rejection, ${isRejected ? 'rejected' : 'not rejected'}: ${e}`);
this._logger.trace(`Checking rejection, ${isRejected ? 'rejected' : 'not rejected'}: ${e}`);
return isRejected;
}

Expand All @@ -79,7 +79,7 @@ class DocumentRejectionTracker {
constructor(
public readonly doc: IObservableDocument,
private readonly _garbageCollector: LRUGarbageCollector,
private readonly _tracer: ITracer,
private readonly _logger: ILogger,
) {
}

Expand All @@ -95,7 +95,7 @@ class DocumentRejectionTracker {
return;
}
const r = new RejectedEdit(edit.toEdit(), () => {
this._tracer.trace(`Evicting: ${edit}`);
this._logger.trace(`Evicting: ${edit}`);
this._rejectedEdits.delete(r);
});
this._rejectedEdits.add(r);
Expand Down
25 changes: 12 additions & 13 deletions src/extension/inlineEdits/node/nextEditCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { ConfigKey, IConfigurationService } from '../../../platform/configuratio
import { DocumentId } from '../../../platform/inlineEdits/common/dataTypes/documentId';
import { IObservableDocument, ObservableWorkspace } from '../../../platform/inlineEdits/common/observableWorkspace';
import { autorunWithChanges } from '../../../platform/inlineEdits/common/utils/observable';
import { ILogService } from '../../../platform/log/common/logService';
import { ILogger, ILogService } from '../../../platform/log/common/logService';
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
import { LRUCache } from '../../../util/common/cache';
import { createTracer, ITracer } from '../../../util/common/tracing';
import { Disposable, toDisposable } from '../../../util/vs/base/common/lifecycle';
import { mapObservableArrayCached } from '../../../util/vs/base/common/observableInternal';
import { AnnotatedStringReplacement, StringEdit, StringReplacement } from '../../../util/vs/editor/common/core/edits/stringEdit';
Expand Down Expand Up @@ -149,25 +148,25 @@ export class NextEditCache extends Disposable {
class DocumentEditCache {

private readonly _trackedCachedEdits: CachedEdit[] = [];
private _tracer: ITracer;
private _logger: ILogger;

constructor(
private readonly _nextEditCache: NextEditCache,
public readonly docId: DocumentId,
private readonly _doc: IObservableDocument,
private readonly _sharedCache: LRUCache<CachedEdit>,
private readonly _logService: ILogService,
_logService: ILogService,
) {
this._tracer = createTracer(['NES', 'DocumentEditCache'], (s) => this._logService.trace(s));
this._logger = _logService.createSubLogger(['NES', 'DocumentEditCache']);
}

public handleEdit(edit: StringEdit): void {
const tracer = this._tracer.sub('handleEdit');
const logger = this._logger.createSubLogger('handleEdit');
for (const cachedEdit of this._trackedCachedEdits) {
if (cachedEdit.userEditSince) {
cachedEdit.userEditSince = cachedEdit.userEditSince.compose(edit);
cachedEdit.rebaseFailed = false;
if (!checkEditConsistency(cachedEdit.documentBeforeEdit.value, cachedEdit.userEditSince, this._doc.value.get().value, tracer)) {
if (!checkEditConsistency(cachedEdit.documentBeforeEdit.value, cachedEdit.userEditSince, this._doc.value.get().value, logger)) {
cachedEdit.userEditSince = undefined;
}
}
Expand All @@ -189,7 +188,7 @@ class DocumentEditCache {
const key = this._getKey(documentContents.value);
const cachedEdit: CachedEdit = { docId: this.docId, edit: nextEdit, edits: nextEdits, detailedEdits: [], userEditSince, subsequentN, source, documentBeforeEdit: documentContents, editWindow, cacheTime: Date.now(), isFromCursorJump: opts.isFromCursorJump };
if (userEditSince) {
if (!checkEditConsistency(cachedEdit.documentBeforeEdit.value, userEditSince, this._doc.value.get().value, this._tracer.sub('setKthNextEdit'))) {
if (!checkEditConsistency(cachedEdit.documentBeforeEdit.value, userEditSince, this._doc.value.get().value, this._logger.createSubLogger('setKthNextEdit'))) {
cachedEdit.userEditSince = undefined;
} else {
this._trackedCachedEdits.unshift(cachedEdit);
Expand Down Expand Up @@ -241,10 +240,10 @@ class DocumentEditCache {
}

public tryRebaseCacheEntry(cachedEdit: CachedEdit, currentDocumentContents: StringText, currentSelection: readonly OffsetRange[], nesConfigs: INesConfigs): CachedEdit | undefined {
const tracer = this._tracer.sub('tryRebaseCacheEntry');
const logger = this._logger.createSubLogger('tryRebaseCacheEntry');
if (cachedEdit.userEditSince && !cachedEdit.rebaseFailed) {
const originalEdits = cachedEdit.edits || (cachedEdit.edit ? [cachedEdit.edit] : []);
const res = tryRebase(cachedEdit.documentBeforeEdit.value, cachedEdit.editWindow, originalEdits, cachedEdit.detailedEdits, cachedEdit.userEditSince, currentDocumentContents.value, currentSelection, 'strict', tracer, nesConfigs);
const res = tryRebase(cachedEdit.documentBeforeEdit.value, cachedEdit.editWindow, originalEdits, cachedEdit.detailedEdits, cachedEdit.userEditSince, currentDocumentContents.value, currentSelection, 'strict', logger, nesConfigs);
if (res === 'rebaseFailed') {
cachedEdit.rebaseFailed = true;
} else if (res === 'inconsistentEdits' || res === 'error') {
Expand All @@ -264,7 +263,7 @@ class DocumentEditCache {
}

public isRejectedNextEdit(currentDocumentContents: StringText, edit: StringReplacement, nesConfigs: INesConfigs) {
const tracer = this._tracer.sub('isRejectedNextEdit');
const logger = this._logger.createSubLogger('isRejectedNextEdit');
const resultEdit = edit.removeCommonSuffixAndPrefix(currentDocumentContents.value);
for (const rejectedEdit of this._trackedCachedEdits.filter(edit => edit.rejected)) {
if (!rejectedEdit.userEditSince) {
Expand All @@ -274,13 +273,13 @@ class DocumentEditCache {
if (!edits.length) {
continue; // cached 'no edits'
}
const rejectedEdits = tryRebase(rejectedEdit.documentBeforeEdit.value, undefined, edits, rejectedEdit.detailedEdits, rejectedEdit.userEditSince, currentDocumentContents.value, [], 'lenient', tracer, nesConfigs);
const rejectedEdits = tryRebase(rejectedEdit.documentBeforeEdit.value, undefined, edits, rejectedEdit.detailedEdits, rejectedEdit.userEditSince, currentDocumentContents.value, [], 'lenient', logger, nesConfigs);
if (typeof rejectedEdits === 'string') {
continue;
}
const rejected = rejectedEdits.some(rejected => rejected.rebasedEdit.removeCommonSuffixAndPrefix(currentDocumentContents.value).equals(resultEdit));
if (rejected) {
tracer.trace('Found rejected edit that matches current edit');
logger.trace('Found rejected edit that matches current edit');
return true;
}
}
Expand Down
Loading