@oh-my-pi/pi-coding-agent 14.5.2 → 14.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/examples/extensions/plan-mode.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/package.json +7 -7
- package/src/config/prompt-templates.ts +104 -6
- package/src/config/settings-schema.ts +14 -13
- package/src/config/settings.ts +1 -1
- package/src/cursor.ts +4 -4
- package/src/edit/index.ts +111 -109
- package/src/edit/line-hash.ts +33 -3
- package/src/edit/modes/apply-patch.ts +6 -4
- package/src/edit/modes/atom.lark +27 -0
- package/src/edit/modes/atom.ts +1094 -642
- package/src/edit/modes/hashline.ts +9 -10
- package/src/edit/modes/patch.ts +23 -19
- package/src/edit/modes/replace.ts +19 -15
- package/src/edit/renderer.ts +65 -8
- package/src/edit/streaming.ts +47 -77
- package/src/extensibility/extensions/types.ts +11 -11
- package/src/extensibility/hooks/types.ts +6 -6
- package/src/lsp/edits.ts +8 -5
- package/src/lsp/index.ts +4 -4
- package/src/lsp/utils.ts +13 -43
- package/src/mcp/discoverable-tool-metadata.ts +1 -1
- package/src/mcp/manager.ts +3 -3
- package/src/mcp/tool-bridge.ts +4 -4
- package/src/memories/index.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +1 -1
- package/src/modes/components/settings-defs.ts +3 -3
- package/src/modes/components/tree-selector.ts +2 -2
- package/src/modes/controllers/event-controller.ts +12 -0
- package/src/modes/utils/ui-helpers.ts +31 -7
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/agents/librarian.md +2 -2
- package/src/prompts/agents/plan.md +2 -2
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/agents/task.md +2 -2
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/system/system-prompt.md +34 -31
- package/src/prompts/tools/apply-patch.md +0 -2
- package/src/prompts/tools/atom.md +88 -97
- package/src/prompts/tools/bash.md +7 -4
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/find.md +6 -1
- package/src/prompts/tools/hashline.md +10 -11
- package/src/prompts/tools/patch.md +13 -13
- package/src/prompts/tools/read.md +5 -5
- package/src/prompts/tools/replace.md +3 -3
- package/src/prompts/tools/{grep.md → search.md} +4 -4
- package/src/sdk.ts +19 -9
- package/src/session/agent-session.ts +69 -1
- package/src/system-prompt.ts +15 -5
- package/src/task/executor.ts +5 -0
- package/src/task/index.ts +10 -1
- package/src/tools/ast-edit.ts +27 -50
- package/src/tools/ast-grep.ts +22 -48
- package/src/tools/bash.ts +1 -1
- package/src/tools/file-recorder.ts +6 -6
- package/src/tools/find.ts +11 -13
- package/src/tools/grouped-file-output.ts +96 -0
- package/src/tools/index.ts +7 -7
- package/src/tools/path-utils.ts +31 -4
- package/src/tools/read.ts +12 -6
- package/src/tools/renderers.ts +2 -2
- package/src/tools/{grep.ts → search.ts} +43 -86
- package/src/tools/todo-write.ts +0 -1
- package/src/tools/write.ts +8 -4
- package/src/web/search/index.ts +1 -1
package/src/edit/index.ts
CHANGED
|
@@ -19,13 +19,8 @@ import { type EditMode, normalizeEditMode, resolveEditMode } from "../utils/edit
|
|
|
19
19
|
import type { VimToolDetails } from "../vim/types";
|
|
20
20
|
import { type ApplyPatchParams, applyPatchSchema, expandApplyPatchToEntries } from "./modes/apply-patch";
|
|
21
21
|
import applyPatchGrammar from "./modes/apply-patch.lark" with { type: "text" };
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
type AtomToolEdit,
|
|
25
|
-
atomEditParamsSchema,
|
|
26
|
-
executeAtomSingle,
|
|
27
|
-
resolveAtomEntryPaths,
|
|
28
|
-
} from "./modes/atom";
|
|
22
|
+
import { type AtomParams, atomEditParamsSchema, executeAtomSingle } from "./modes/atom";
|
|
23
|
+
import atomGrammar from "./modes/atom.lark" with { type: "text" };
|
|
29
24
|
import {
|
|
30
25
|
executeHashlineSingle,
|
|
31
26
|
HashlineMismatchError,
|
|
@@ -122,45 +117,11 @@ function createEditWritethrough(session: ToolSession): WritethroughCallback {
|
|
|
122
117
|
return enableLsp ? createLspWritethrough(session.cwd, { enableFormat, enableDiagnostics }) : writethroughNoop;
|
|
123
118
|
}
|
|
124
119
|
|
|
125
|
-
/**
|
|
126
|
-
|
|
127
|
-
* If both are absent on an entry, throws a descriptive error.
|
|
128
|
-
*/
|
|
129
|
-
function resolveEntryPaths<T extends { path?: string }>(
|
|
130
|
-
edits: readonly T[],
|
|
131
|
-
topLevelPath: string | undefined,
|
|
132
|
-
): (T & { path: string })[] {
|
|
133
|
-
return edits.map((edit, i) => {
|
|
134
|
-
const path = (edit && typeof edit.path === "string" && edit.path) || topLevelPath;
|
|
135
|
-
if (!path) {
|
|
136
|
-
throw new Error(
|
|
137
|
-
`Edit ${i}: missing \`path\`. Provide \`path\` on this edit or supply a top-level \`path\` for the request.`,
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
return { ...edit, path };
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** Group items by a key, preserving insertion order. */
|
|
145
|
-
function groupBy<T, K>(items: T[], key: (item: T) => K): Map<K, T[]> {
|
|
146
|
-
const map = new Map<K, T[]>();
|
|
147
|
-
for (const item of items) {
|
|
148
|
-
const k = key(item);
|
|
149
|
-
let arr = map.get(k);
|
|
150
|
-
if (!arr) {
|
|
151
|
-
arr = [];
|
|
152
|
-
map.set(k, arr);
|
|
153
|
-
}
|
|
154
|
-
arr.push(item);
|
|
155
|
-
}
|
|
156
|
-
return map;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** Run single-file executors for each file group and aggregate results. */
|
|
160
|
-
async function executePerFile(
|
|
120
|
+
/** Run apply_patch file operations and aggregate their multi-file result. */
|
|
121
|
+
async function executeApplyPatchPerFile(
|
|
161
122
|
fileEntries: {
|
|
162
123
|
path: string;
|
|
163
|
-
run: (batchRequest: LspBatchRequest | undefined) => Promise<AgentToolResult<EditToolDetails
|
|
124
|
+
run: (batchRequest: LspBatchRequest | undefined) => Promise<AgentToolResult<EditToolDetails>>;
|
|
164
125
|
}[],
|
|
165
126
|
outerBatchRequest: LspBatchRequest | undefined,
|
|
166
127
|
onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
@@ -230,6 +191,58 @@ async function executePerFile(
|
|
|
230
191
|
};
|
|
231
192
|
}
|
|
232
193
|
|
|
194
|
+
async function executeSinglePathEntries(
|
|
195
|
+
path: string,
|
|
196
|
+
runs: ((batchRequest: LspBatchRequest | undefined) => Promise<AgentToolResult<EditToolDetails>>)[],
|
|
197
|
+
outerBatchRequest: LspBatchRequest | undefined,
|
|
198
|
+
onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
199
|
+
): Promise<AgentToolResult<EditToolDetails, TInput>> {
|
|
200
|
+
if (runs.length === 1) {
|
|
201
|
+
return runs[0](outerBatchRequest);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const contentTexts: string[] = [];
|
|
205
|
+
const diffTexts: string[] = [];
|
|
206
|
+
let firstChangedLine: number | undefined;
|
|
207
|
+
|
|
208
|
+
for (let i = 0; i < runs.length; i++) {
|
|
209
|
+
const isLast = i === runs.length - 1;
|
|
210
|
+
const batchRequest: LspBatchRequest | undefined = outerBatchRequest
|
|
211
|
+
? { id: outerBatchRequest.id, flush: isLast && outerBatchRequest.flush }
|
|
212
|
+
: undefined;
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
const result = await runs[i](batchRequest);
|
|
216
|
+
const details = result.details;
|
|
217
|
+
if (details?.diff) diffTexts.push(details.diff);
|
|
218
|
+
firstChangedLine ??= details?.firstChangedLine;
|
|
219
|
+
const text = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
220
|
+
if (text) contentTexts.push(text);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
const errorText = err instanceof Error ? err.message : String(err);
|
|
223
|
+
contentTexts.push(`Error editing ${path}: ${errorText}`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (!isLast && onUpdate) {
|
|
227
|
+
onUpdate({
|
|
228
|
+
content: [{ type: "text", text: contentTexts.join("\n") }],
|
|
229
|
+
details: {
|
|
230
|
+
diff: diffTexts.join("\n"),
|
|
231
|
+
firstChangedLine,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
content: [{ type: "text", text: contentTexts.join("\n") }],
|
|
239
|
+
details: {
|
|
240
|
+
diff: diffTexts.join("\n"),
|
|
241
|
+
firstChangedLine,
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
233
246
|
export class EditTool implements AgentTool<TInput> {
|
|
234
247
|
readonly name = "edit";
|
|
235
248
|
readonly label = "Edit";
|
|
@@ -278,8 +291,9 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
278
291
|
* and fall back to emitting a JSON function tool from `parameters`.
|
|
279
292
|
*/
|
|
280
293
|
get customFormat(): { syntax: "lark"; definition: string } | undefined {
|
|
281
|
-
if (this.mode
|
|
282
|
-
return { syntax: "lark", definition:
|
|
294
|
+
if (this.mode === "apply_patch") return { syntax: "lark", definition: applyPatchGrammar };
|
|
295
|
+
if (this.mode === "atom") return { syntax: "lark", definition: atomGrammar };
|
|
296
|
+
return undefined;
|
|
283
297
|
}
|
|
284
298
|
|
|
285
299
|
/**
|
|
@@ -316,13 +330,12 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
316
330
|
batchRequest: LspBatchRequest | undefined,
|
|
317
331
|
onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
318
332
|
) => {
|
|
319
|
-
const { edits, path
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
path: entry.path,
|
|
323
|
-
run: (br: LspBatchRequest | undefined) =>
|
|
333
|
+
const { edits, path } = params as PatchParams;
|
|
334
|
+
const runs = (edits as PatchEditEntry[]).map(
|
|
335
|
+
entry => (br: LspBatchRequest | undefined) =>
|
|
324
336
|
executePatchSingle({
|
|
325
337
|
session: tool.session,
|
|
338
|
+
path,
|
|
326
339
|
params: entry,
|
|
327
340
|
signal,
|
|
328
341
|
batchRequest: br,
|
|
@@ -331,8 +344,8 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
331
344
|
writethrough: tool.#writethrough,
|
|
332
345
|
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
333
346
|
}),
|
|
334
|
-
|
|
335
|
-
return
|
|
347
|
+
);
|
|
348
|
+
return executeSinglePathEntries(path, runs, batchRequest, onUpdate);
|
|
336
349
|
},
|
|
337
350
|
},
|
|
338
351
|
apply_patch: {
|
|
@@ -346,21 +359,25 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
346
359
|
onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
347
360
|
) => {
|
|
348
361
|
const entries = expandApplyPatchToEntries(params as ApplyPatchParams);
|
|
349
|
-
const perFile = entries.map(entry =>
|
|
350
|
-
path
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
362
|
+
const perFile = entries.map(entry => {
|
|
363
|
+
const { path, ...patchParams } = entry;
|
|
364
|
+
return {
|
|
365
|
+
path,
|
|
366
|
+
run: (br: LspBatchRequest | undefined) =>
|
|
367
|
+
executePatchSingle({
|
|
368
|
+
session: tool.session,
|
|
369
|
+
path,
|
|
370
|
+
params: patchParams,
|
|
371
|
+
signal,
|
|
372
|
+
batchRequest: br,
|
|
373
|
+
allowFuzzy: tool.#allowFuzzy,
|
|
374
|
+
fuzzyThreshold: tool.#fuzzyThreshold,
|
|
375
|
+
writethrough: tool.#writethrough,
|
|
376
|
+
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
377
|
+
}),
|
|
378
|
+
};
|
|
379
|
+
});
|
|
380
|
+
return executeApplyPatchPerFile(perFile, batchRequest, onUpdate);
|
|
364
381
|
},
|
|
365
382
|
},
|
|
366
383
|
hashline: {
|
|
@@ -371,25 +388,18 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
371
388
|
params: EditParams,
|
|
372
389
|
signal: AbortSignal | undefined,
|
|
373
390
|
batchRequest: LspBatchRequest | undefined,
|
|
374
|
-
|
|
391
|
+
_onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
375
392
|
) => {
|
|
376
|
-
const { edits, path
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const entries = [...byFile.entries()].map(([path, fileEdits]) => ({
|
|
393
|
+
const { edits, path } = params as HashlineParams;
|
|
394
|
+
return executeHashlineSingle({
|
|
395
|
+
session: tool.session,
|
|
380
396
|
path,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
batchRequest: br,
|
|
388
|
-
writethrough: tool.#writethrough,
|
|
389
|
-
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
390
|
-
}),
|
|
391
|
-
}));
|
|
392
|
-
return executePerFile(entries, batchRequest, onUpdate);
|
|
397
|
+
edits: edits as HashlineToolEdit[],
|
|
398
|
+
signal,
|
|
399
|
+
batchRequest,
|
|
400
|
+
writethrough: tool.#writethrough,
|
|
401
|
+
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
402
|
+
});
|
|
393
403
|
},
|
|
394
404
|
},
|
|
395
405
|
atom: {
|
|
@@ -400,25 +410,18 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
400
410
|
params: EditParams,
|
|
401
411
|
signal: AbortSignal | undefined,
|
|
402
412
|
batchRequest: LspBatchRequest | undefined,
|
|
403
|
-
|
|
413
|
+
_onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
404
414
|
) => {
|
|
405
|
-
const {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
415
|
+
const { input, path } = params as AtomParams & { path?: string };
|
|
416
|
+
return executeAtomSingle({
|
|
417
|
+
session: tool.session,
|
|
418
|
+
input,
|
|
409
419
|
path,
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
signal,
|
|
416
|
-
batchRequest: br,
|
|
417
|
-
writethrough: tool.#writethrough,
|
|
418
|
-
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
419
|
-
}),
|
|
420
|
-
}));
|
|
421
|
-
return executePerFile(entries, batchRequest, onUpdate);
|
|
420
|
+
signal,
|
|
421
|
+
batchRequest,
|
|
422
|
+
writethrough: tool.#writethrough,
|
|
423
|
+
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
424
|
+
});
|
|
422
425
|
},
|
|
423
426
|
},
|
|
424
427
|
replace: {
|
|
@@ -431,13 +434,12 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
431
434
|
batchRequest: LspBatchRequest | undefined,
|
|
432
435
|
onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
|
|
433
436
|
) => {
|
|
434
|
-
const { edits, path
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
path: entry.path,
|
|
438
|
-
run: (br: LspBatchRequest | undefined) =>
|
|
437
|
+
const { edits, path } = params as ReplaceParams;
|
|
438
|
+
const runs = (edits as ReplaceEditEntry[]).map(
|
|
439
|
+
entry => (br: LspBatchRequest | undefined) =>
|
|
439
440
|
executeReplaceSingle({
|
|
440
441
|
session: tool.session,
|
|
442
|
+
path,
|
|
441
443
|
params: entry,
|
|
442
444
|
signal,
|
|
443
445
|
batchRequest: br,
|
|
@@ -446,8 +448,8 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
446
448
|
writethrough: tool.#writethrough,
|
|
447
449
|
beginDeferredDiagnosticsForPath: p => tool.#beginDeferredDiagnosticsForPath(p),
|
|
448
450
|
}),
|
|
449
|
-
|
|
450
|
-
return
|
|
451
|
+
);
|
|
452
|
+
return executeSinglePathEntries(path, runs, batchRequest, onUpdate);
|
|
451
453
|
},
|
|
452
454
|
},
|
|
453
455
|
vim: {
|
package/src/edit/line-hash.ts
CHANGED
|
@@ -676,18 +676,48 @@ export const HASHLINE_BIGRAM_RE_SRC = `(?:${HASHLINE_BIGRAMS.join("|")})`;
|
|
|
676
676
|
export const HASHLINE_CONTENT_SEPARATOR = "|";
|
|
677
677
|
|
|
678
678
|
const RE_SIGNIFICANT = /[\p{L}\p{N}]/u;
|
|
679
|
+
const RE_STRUCTURAL_STRIP = /[\s{}]/g;
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Bigram returned for lines that contain only whitespace and `{`/`}`.
|
|
683
|
+
* Picks the English ordinal suffix for the line number (`1` → `st`,
|
|
684
|
+
* `2` → `nd`, `3` → `rd`, `11`/`12`/`13` → `th`, else `th`) so the
|
|
685
|
+
* line digits + bigram BPE-merge into a single ordinal token (`1st`, `42nd`,
|
|
686
|
+
* `100th`, …). Brace-only lines therefore cost one token for the whole
|
|
687
|
+
* `LINE+ID` anchor instead of two.
|
|
688
|
+
*/
|
|
689
|
+
function structuralBigram(line: number): string {
|
|
690
|
+
const mod100 = line % 100;
|
|
691
|
+
if (mod100 >= 11 && mod100 <= 13) return "th";
|
|
692
|
+
switch (line % 10) {
|
|
693
|
+
case 1:
|
|
694
|
+
return "st";
|
|
695
|
+
case 2:
|
|
696
|
+
return "nd";
|
|
697
|
+
case 3:
|
|
698
|
+
return "rd";
|
|
699
|
+
default:
|
|
700
|
+
return "th";
|
|
701
|
+
}
|
|
702
|
+
}
|
|
679
703
|
|
|
680
704
|
/**
|
|
681
705
|
* Compute a short BPE-bigram hash of a single line.
|
|
682
706
|
*
|
|
683
707
|
* Uses xxHash32 on a trailing-whitespace-trimmed, CR-stripped line, mapped into
|
|
684
|
-
* {@link HASHLINE_BIGRAMS} via modulo.
|
|
685
|
-
*
|
|
686
|
-
*
|
|
708
|
+
* {@link HASHLINE_BIGRAMS} via modulo. Lines that contain only whitespace and
|
|
709
|
+
* `{`/`}` collapse to an ordinal-suffix bigram (see {@link structuralBigram})
|
|
710
|
+
* so brace-only structure shares one merged ordinal token. For other lines
|
|
711
|
+
* containing no alphanumeric characters, the line number is mixed in to reduce hash collisions.
|
|
712
|
+
* The line input should not include a trailing newline.
|
|
687
713
|
*/
|
|
688
714
|
export function computeLineHash(idx: number, line: string): string {
|
|
689
715
|
line = line.replace(/\r/g, "").trimEnd();
|
|
690
716
|
|
|
717
|
+
if (line.replace(RE_STRUCTURAL_STRIP, "").length === 0) {
|
|
718
|
+
return structuralBigram(idx);
|
|
719
|
+
}
|
|
720
|
+
|
|
691
721
|
let seed = 0;
|
|
692
722
|
if (!RE_SIGNIFICANT.test(line)) {
|
|
693
723
|
seed = idx;
|
|
@@ -22,17 +22,19 @@ export const applyPatchSchema = Type.Object({
|
|
|
22
22
|
|
|
23
23
|
export type ApplyPatchParams = Static<typeof applyPatchSchema>;
|
|
24
24
|
|
|
25
|
+
export type ApplyPatchEntry = PatchEditEntry & { path: string };
|
|
26
|
+
|
|
25
27
|
/**
|
|
26
28
|
* Parse the envelope and lower each hunk to a `PatchEditEntry` so it can
|
|
27
29
|
* be routed through `executePatchSingle`.
|
|
28
30
|
*/
|
|
29
|
-
export function expandApplyPatchToEntries(params: ApplyPatchParams):
|
|
31
|
+
export function expandApplyPatchToEntries(params: ApplyPatchParams): ApplyPatchEntry[] {
|
|
30
32
|
const hunks = parseApplyPatch(params.input);
|
|
31
33
|
if (hunks.length === 0) {
|
|
32
34
|
throw new ApplyPatchError("No files were modified.");
|
|
33
35
|
}
|
|
34
36
|
return hunks.map(
|
|
35
|
-
(h):
|
|
37
|
+
(h): ApplyPatchEntry => ({
|
|
36
38
|
path: h.path,
|
|
37
39
|
op: h.op,
|
|
38
40
|
rename: h.rename,
|
|
@@ -41,10 +43,10 @@ export function expandApplyPatchToEntries(params: ApplyPatchParams): PatchEditEn
|
|
|
41
43
|
);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
export function expandApplyPatchToPreviewEntries(params: ApplyPatchParams):
|
|
46
|
+
export function expandApplyPatchToPreviewEntries(params: ApplyPatchParams): ApplyPatchEntry[] {
|
|
45
47
|
const hunks = parseApplyPatchStreaming(params.input);
|
|
46
48
|
return hunks.map(
|
|
47
|
-
(h):
|
|
49
|
+
(h): ApplyPatchEntry => ({
|
|
48
50
|
path: h.path,
|
|
49
51
|
op: h.op,
|
|
50
52
|
rename: h.rename,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
%import common.LF
|
|
2
|
+
|
|
3
|
+
start: file_section+
|
|
4
|
+
|
|
5
|
+
file_section: file_header (line_change | whole_file_change)
|
|
6
|
+
file_header: "---" filename LF
|
|
7
|
+
|
|
8
|
+
filename: /(.+)/
|
|
9
|
+
|
|
10
|
+
line_change: line* mutation_line line*
|
|
11
|
+
line: insert_line | delete_line | set_line | move_line | blank
|
|
12
|
+
mutation_line: insert_line | delete_line | set_line
|
|
13
|
+
|
|
14
|
+
whole_file_change: blank* whole_file_line blank*
|
|
15
|
+
whole_file_line: remove_file | move_file
|
|
16
|
+
remove_file: "!rm" LF
|
|
17
|
+
move_file: "!mv" WS destination LF
|
|
18
|
+
destination: /(?:[^ \t\r\n]+|"[^"\r\n]+"|'[^'\r\n]+')/
|
|
19
|
+
|
|
20
|
+
insert_line: "+" /(.*)/ LF
|
|
21
|
+
delete_line: "-" LID LF
|
|
22
|
+
set_line: LID "=" /(.*)/ LF
|
|
23
|
+
move_line: ("@" LID | "$" | "^") LF
|
|
24
|
+
|
|
25
|
+
LID: /[1-9][0-9]*[a-z]{2}/
|
|
26
|
+
WS: /[ \t]+/
|
|
27
|
+
blank: LF
|