(file_path: string, edits: FileEdit[])
| 104 | return t2; |
| 105 | } |
| 106 | async function loadDiffData(file_path: string, edits: FileEdit[]): Promise<DiffData> { |
| 107 | const valid = edits.filter(e => e.old_string != null && e.new_string != null); |
| 108 | const single = valid.length === 1 ? valid[0]! : undefined; |
| 109 | |
| 110 | // SedEditPermissionRequest passes the entire file as old_string. Scanning for |
| 111 | // a needle ≥ CHUNK_SIZE allocates O(needle) for the overlap buffer — skip the |
| 112 | // file read entirely and diff the inputs we already have. |
| 113 | if (single && single.old_string.length >= CHUNK_SIZE) { |
| 114 | return diffToolInputsOnly(file_path, [single]); |
| 115 | } |
| 116 | try { |
| 117 | const handle = await openForScan(file_path); |
| 118 | if (handle === null) return diffToolInputsOnly(file_path, valid); |
| 119 | try { |
| 120 | // Multi-edit and empty old_string genuinely need full-file for sequential |
| 121 | // replacements — structuredPatch needs before/after strings. replace_all |
| 122 | // routes through the chunked path below (shows first-occurrence window; |
| 123 | // matches within the slice still replace via edit.replace_all). |
| 124 | if (!single || single.old_string === '') { |
| 125 | const file = await readCapped(handle); |
| 126 | if (file === null) return diffToolInputsOnly(file_path, valid); |
| 127 | const normalized = valid.map(e => normalizeEdit(file, e)); |
| 128 | return { |
| 129 | patch: getPatchForDisplay({ |
| 130 | filePath: file_path, |
| 131 | fileContents: file, |
| 132 | edits: normalized |
| 133 | }), |
| 134 | firstLine: firstLineOf(file), |
| 135 | fileContent: file |
| 136 | }; |
| 137 | } |
| 138 | const ctx = await scanForContext(handle, single.old_string, CONTEXT_LINES); |
| 139 | if (ctx.truncated || ctx.content === '') { |
| 140 | return diffToolInputsOnly(file_path, [single]); |
| 141 | } |
| 142 | const normalized = normalizeEdit(ctx.content, single); |
| 143 | const hunks = getPatchForDisplay({ |
| 144 | filePath: file_path, |
| 145 | fileContents: ctx.content, |
| 146 | edits: [normalized] |
| 147 | }); |
| 148 | return { |
| 149 | patch: adjustHunkLineNumbers(hunks, ctx.lineOffset - 1), |
| 150 | firstLine: ctx.lineOffset === 1 ? firstLineOf(ctx.content) : null, |
| 151 | fileContent: ctx.content |
| 152 | }; |
| 153 | } finally { |
| 154 | await handle.close(); |
| 155 | } |
| 156 | } catch (e) { |
| 157 | logError(e as Error); |
| 158 | return diffToolInputsOnly(file_path, valid); |
| 159 | } |
| 160 | } |
| 161 | function diffToolInputsOnly(filePath: string, edits: FileEdit[]): DiffData { |
| 162 | return { |
| 163 | patch: edits.flatMap(e => getPatchForDisplay({ |
no test coverage detected