fix(coding-agent): added gap separators between noncontiguous search matches
- SearchTool now tracked the last emitted line and inserted ellipsis markers when noncontiguous match blocks were output. - Display output gap markers were padded to align with code-frame gutters. - Added a regression test that verified a no-context search emits an ellipsis between separated matches in the same file.
This commit is contained in:
@@ -328,11 +328,18 @@ export class SearchTool implements AgentTool<typeof searchSchema, SearchToolDeta
|
||||
return nextWidth;
|
||||
}, 0);
|
||||
const cacheEntries: Array<readonly [number, string]> = [];
|
||||
let lastEmittedLine: number | undefined;
|
||||
const gutterPad = " ".repeat(lineNumberWidth + 1);
|
||||
for (const match of fileMatches) {
|
||||
const pushLine = (lineNumber: number, line: string, isMatch: boolean, recordable: boolean) => {
|
||||
if (lastEmittedLine !== undefined && lineNumber > lastEmittedLine + 1) {
|
||||
modelOut.push("...");
|
||||
displayOut.push(`${gutterPad}│...`);
|
||||
}
|
||||
modelOut.push(formatMatchLine(lineNumber, line, isMatch, { useHashLines }));
|
||||
displayOut.push(formatCodeFrameLine(isMatch ? "*" : " ", lineNumber, line, lineNumberWidth));
|
||||
if (recordable) cacheEntries.push([lineNumber, line] as const);
|
||||
lastEmittedLine = lineNumber;
|
||||
};
|
||||
if (match.contextBefore) {
|
||||
for (const ctx of match.contextBefore) {
|
||||
|
||||
@@ -1419,6 +1419,24 @@ function b() {
|
||||
expect(output).toMatch(/\*5\|match two/);
|
||||
});
|
||||
|
||||
it("inserts a gap separator between non-contiguous match blocks", async () => {
|
||||
const testFile = path.join(testDir, "gaps.txt");
|
||||
const lines = Array.from({ length: 10 }, (_, idx) => (idx === 0 || idx === 5 ? "match" : `filler ${idx}`));
|
||||
fs.writeFileSync(testFile, lines.join("\n"));
|
||||
|
||||
const noContextSettings = Settings.isolated({ "search.contextBefore": 0, "search.contextAfter": 0 });
|
||||
const noContextSearchTool = wrapToolWithMetaNotice(
|
||||
new SearchTool(createTestToolSession(testDir, noContextSettings)),
|
||||
);
|
||||
const result = await noContextSearchTool.execute("test-call-12-gap", {
|
||||
pattern: "match",
|
||||
paths: [testFile],
|
||||
});
|
||||
|
||||
const output = getTextOutput(result);
|
||||
expect(output).toMatch(/\*1\|match\n\.\.\.\n\*6\|match/);
|
||||
});
|
||||
|
||||
it("should paginate files via the skip parameter", async () => {
|
||||
const skipDir = path.join(testDir, "skip-dir");
|
||||
fs.mkdirSync(skipDir, { recursive: true });
|
||||
|
||||
Reference in New Issue
Block a user