import { DocumentId } from '../../../platform/inlineEdits/common/dataTypes/documentId'; import { DuplicateAdditionsMode } from '../../../platform/inlineEdits/common/dataTypes/xtabPromptOptions'; import { NoNextEditReason, StreamedEdit } from '../../../platform/inlineEdits/common/statelessNextEditProvider'; import { ILogger } from '../../../platform/log/common/logService'; import { URI } from '../../../util/vs/base/common/uri'; import { LineReplacement } from '../../../util/vs/editor/common/core/edits/lineEdit'; import { OffsetRange } from '../../../util/vs/editor/common/core/ranges/offsetRange'; import { AbstractText } from '../../../util/vs/editor/common/core/text/abstractText'; import { CurrentDocument } from '../common/xtabCurrentDocument'; declare class Patch { /** * Expected to be file path relative to workspace root. */ readonly filePath: string; readonly lineNumZeroBased: number; /** * Zero-based index of the model-emitted patch this object represents. Patches * derived from the same model header (e.g. the early + continuation patches of a * progressive ghost-text reveal) share the same `patchIndex`. */ readonly patchIndex: number; removedLines: string[]; addedLines: string[]; /** * True for the early cursor-line replacement produced by {@link Patch.progressiveRevealParts}. * Such a patch is a 1-for-1 additive edit whose single added line IS the change we want to * surface, so the duplicate-additions policy is skipped for it (see {@link shouldApplyDuplicatePolicy}). */ isProgressiveRevealEarlyEdit: boolean; private constructor(); static ofLine(line: string, patchIndex: number): Patch | null; /** * Builds the two patches of a progressive ghost-text reveal from the first model patch: * - `early`: the cursor-line replacement (`removedLines[0]` -> `addedLines[0]`), yielded * immediately so the additive cursor-line edit shows ASAP. It is a 1-for-1 replacement, * so it shifts no line anchors below it. * - `continuation`: the remaining removed/added lines, anchored on the next line. It carries * `removedLines.slice(1)` (empty for the common single-removed-line case, making it a pure * insertion) and collects the remaining added lines as they stream in. * * Both share the source patch's `patchIndex`. The union of the two is byte-identical to * applying the original patch. */ static progressiveRevealParts(source: Patch): { early: Patch; continuation: Patch; }; addLine(line: string): boolean; toString(): string; } /** * Information about a single duplicate-addition removal. * * `kind` identifies which heuristic shape fired: * - `'suffix'`: trailing additions matched the lines after the deletion. * - `'prefix'`: leading addition matched the first line after the deletion. * - `'middle'`: a pair of additions inside the patch matched the start of * the following lines (streaming model partially copied the continuation). * * `removedLines` are the actual addition lines that were dropped (in order), * preserved for diagnostics/logging. */ export interface DuplicateAdditionRemoval { readonly kind: 'suffix' | 'prefix' | 'middle'; readonly newAdditions: string[]; readonly removedLines: readonly string[]; } /** * Checks whether the patch's added lines duplicate the file content immediately * following the deleted range, and if so, trims the duplicated lines. * * The diff-patch model can occasionally regress and emit additions that copy * the existing continuation code. When that happens, applying the patch * produces visibly duplicated lines in the file (e.g. an extra closing brace * after a code block). * * Three duplication shapes are detected, mirroring the heuristic used in the * offline analysis tooling. Only one shape is applied per patch — the checks * run in priority order and the first match wins. This avoids cascading * removals where one shape's trimming exposes a spurious match for another. * * Priority order: * 1. **Suffix** — last `k` additions match first `k` following lines (most * common case: trailing `}` re-emitted). Picks the longest matching `k`. * No additional ambiguity guard is applied: the prior heuristic * preserved single-token suffixes when they consumed the entire * addition (e.g. `addedLines = ['}']` with `following = ['}']`), but * that's the headline-bug case — applying the patch would insert a * stray closing token into already-balanced code. The trade-off is a * rare false positive when the file is mid-typing and unbalanced; the * common case (file is balanced, model is duplicating) is the one we * optimize for. * 2. **Prefix** — first addition matches first following line, and the line * is "meaningful" (>1 non-whitespace char) to avoid dropping legitimate * single-token lines (e.g. an inner-scope `}` followed by an outer `}`). * 3. **Middle** — a consecutive pair of additions starting at offset > 0 * (and not at the end) matches the first two following lines. Both * following lines must be meaningful, again to avoid trivial matches. * The match is then **greedily extended**: only the verified-equal * lines are dropped; any addition lines beyond the equal range are * preserved (the model may have appended new content after the * streaming-style regenerated context). * * Returns a `DuplicateAdditionRemoval` describing what was dropped, or * `undefined` if no duplication was detected. */ export declare function tryRemoveDuplicateAdditions(replacement: LineReplacement, currentText: AbstractText): DuplicateAdditionRemoval | undefined; export declare namespace XtabPatchResponseHandler { /** * Splits a coarse patch replacement into the minimal set of sub-replacements * by running a line diff between the removed and added lines. * * The diff-patch model emits a patch as a contiguous block of `-`/`+` lines, * which `resolveEdit` turns into a single `LineReplacement` spanning every * removed line. When only a subset of those lines actually changed (the model * re-emitted surrounding context), a line-level diff recovers the minimal * hunks, yielding several small replacements with the untouched lines left as * context — a nicer suggestion shape. * * @param replacement The resolved (possibly dedup-trimmed) replacement; its * `newLines` are the added lines and its `lineRange` anchors the result in * the document. * @param removedLines The original line content removed by the patch. Its * length is expected to match `replacement.lineRange.length`. * * Returns the original replacement unchanged when there is nothing to gain: * a pure insertion or deletion (one side empty), a diff that times out, or a * diff that collapses to a single hunk. */ function splitReplacement(replacement: LineReplacement, removedLines: readonly string[]): LineReplacement[]; function handleResponse(linesStream: AsyncIterable, currentDocument: CurrentDocument, activeDocumentId: DocumentId, workspaceRoot: URI | undefined, window: OffsetRange | undefined, parentTracer: ILogger, duplicateAdditionsMode?: DuplicateAdditionsMode, enableProgressiveGhostText?: boolean, splitPatchOnDiff?: boolean, enableProgressiveGhostTextMultiLine?: boolean): AsyncGenerator; /** * Checks whether the first patch qualifies for ghost-text progressive reveal: it targets the * cursor line in the active document, has at least one added line, and additively edits the * cursor line (the removed line is a subsequence of the first added line). * * By default only single-removed-line patches qualify. When `allowMultiLineRemoval` is set, * patches that remove more than one line also qualify — the cursor-line change is revealed * first and the remaining removed/added lines stream as a continuation — except for the * empty-line shift-up shape (see {@link isEmptyCursorLineShiftUp}). */ function isGhostTextPatch(patch: Patch, cursorLineZeroBased: number, activeDocRelativePath: string, allowMultiLineRemoval: boolean): boolean; /** * @param cursorLineZeroBased When provided (along with activeDocRelativePath), * enables ghost-text progressive reveal for the first patch: if the first patch * is a ghost-text (a removed line at the cursor that is additively edited), * the cursor-line replacement is yielded immediately and any further removed/added * lines are collected into a separate continuation patch. * @param allowMultiLineRemoval When set, progressive reveal also fires for first patches * that remove more than one line (see {@link isGhostTextPatch}); the continuation then * carries the remaining removed lines instead of being a pure insertion. */ function extractEdits(linesStream: AsyncIterable, cursorLineZeroBased?: number, activeDocRelativePath?: string, allowMultiLineRemoval?: boolean): AsyncGenerator; } export {}; //# sourceMappingURL=xtabPatchResponseHandler.d.ts.map