mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
This commit is contained in:
@@ -61,34 +61,4 @@ describe('replace', () => {
|
|||||||
console.log('File replaced successfully. New content:', newFileContent);
|
console.log('File replaced successfully. New content:', newFileContent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle $ literally when replacing text ending with $', async () => {
|
|
||||||
const rig = new TestRig();
|
|
||||||
await rig.setup(
|
|
||||||
'should handle $ literally when replacing text ending with $',
|
|
||||||
);
|
|
||||||
|
|
||||||
const fileName = 'regex.yml';
|
|
||||||
const originalContent = "| select('match', '^[sv]d[a-z]$')\n";
|
|
||||||
const expectedContent = "| select('match', '^[sv]d[a-z]$') # updated\n";
|
|
||||||
|
|
||||||
rig.createFile(fileName, originalContent);
|
|
||||||
|
|
||||||
const prompt =
|
|
||||||
"Open regex.yml and append ' # updated' after the line containing ^[sv]d[a-z]$ without breaking the $ character.";
|
|
||||||
|
|
||||||
const result = await rig.run(prompt);
|
|
||||||
const foundToolCall = await rig.waitForToolCall('replace');
|
|
||||||
|
|
||||||
if (!foundToolCall) {
|
|
||||||
printDebugInfo(rig, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(foundToolCall, 'Expected to find a replace tool call').toBeTruthy();
|
|
||||||
|
|
||||||
validateModelOutput(result, ['regex.yml'], 'Replace $ literal test');
|
|
||||||
|
|
||||||
const newFileContent = rig.readFile(fileName);
|
|
||||||
expect(newFileContent).toBe(expectedContent);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -509,8 +509,7 @@ export class Task {
|
|||||||
if (oldString === '' && !isNewFile) {
|
if (oldString === '' && !isNewFile) {
|
||||||
return currentContent;
|
return currentContent;
|
||||||
}
|
}
|
||||||
// Use split/join to ensure replacement
|
return currentContent.replaceAll(oldString, newString);
|
||||||
return currentContent.split(oldString).join(newString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async scheduleToolCalls(
|
async scheduleToolCalls(
|
||||||
|
|||||||
@@ -198,22 +198,6 @@ describe('EditTool', () => {
|
|||||||
'hello world',
|
'hello world',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should treat $ literally and not as replacement pattern', () => {
|
|
||||||
const current = "price is $100 and pattern end is ' '";
|
|
||||||
const oldStr = 'price is $100';
|
|
||||||
const newStr = 'price is $200';
|
|
||||||
const result = applyReplacement(current, oldStr, newStr, false);
|
|
||||||
expect(result).toBe("price is $200 and pattern end is ' '");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should treat $' literally and not as a replacement pattern", () => {
|
|
||||||
const current = 'foo';
|
|
||||||
const oldStr = 'foo';
|
|
||||||
const newStr = "bar$'baz";
|
|
||||||
const result = applyReplacement(current, oldStr, newStr, false);
|
|
||||||
expect(result).toBe("bar$'baz");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('validateToolParams', () => {
|
describe('validateToolParams', () => {
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ export function applyReplacement(
|
|||||||
if (oldString === '' && !isNewFile) {
|
if (oldString === '' && !isNewFile) {
|
||||||
return currentContent;
|
return currentContent;
|
||||||
}
|
}
|
||||||
// Use split/join to ensure replacement
|
return currentContent.replaceAll(oldString, newString);
|
||||||
return currentContent.split(oldString).join(newString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -46,11 +46,11 @@ import {
|
|||||||
type Mock,
|
type Mock,
|
||||||
} from 'vitest';
|
} from 'vitest';
|
||||||
import {
|
import {
|
||||||
|
applyReplacement,
|
||||||
SmartEditTool,
|
SmartEditTool,
|
||||||
type EditToolParams,
|
type EditToolParams,
|
||||||
calculateReplacement,
|
calculateReplacement,
|
||||||
} from './smart-edit.js';
|
} from './smart-edit.js';
|
||||||
import { applyReplacement } from './edit.js';
|
|
||||||
import { type FileDiff, ToolConfirmationOutcome } from './tools.js';
|
import { type FileDiff, ToolConfirmationOutcome } from './tools.js';
|
||||||
import { ToolErrorType } from './tool-error.js';
|
import { ToolErrorType } from './tool-error.js';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
@@ -169,22 +169,6 @@ describe('SmartEditTool', () => {
|
|||||||
'hello new world new',
|
'hello new world new',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should treat $ literally and not as replacement pattern', () => {
|
|
||||||
const current = 'regex end is $ and more';
|
|
||||||
const oldStr = 'regex end is $';
|
|
||||||
const newStr = 'regex end is $ and correct';
|
|
||||||
const result = applyReplacement(current, oldStr, newStr, false);
|
|
||||||
expect(result).toBe('regex end is $ and correct and more');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should treat $' literally and not as a replacement pattern", () => {
|
|
||||||
const current = 'foo';
|
|
||||||
const oldStr = 'foo';
|
|
||||||
const newStr = "bar$'baz";
|
|
||||||
const result = applyReplacement(current, oldStr, newStr, false);
|
|
||||||
expect(result).toBe("bar$'baz");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('calculateReplacement', () => {
|
describe('calculateReplacement', () => {
|
||||||
|
|||||||
@@ -30,7 +30,26 @@ import {
|
|||||||
} from './modifiable-tool.js';
|
} from './modifiable-tool.js';
|
||||||
import { IdeClient, IDEConnectionStatus } from '../ide/ide-client.js';
|
import { IdeClient, IDEConnectionStatus } from '../ide/ide-client.js';
|
||||||
import { FixLLMEditWithInstruction } from '../utils/llm-edit-fixer.js';
|
import { FixLLMEditWithInstruction } from '../utils/llm-edit-fixer.js';
|
||||||
import { applyReplacement } from './edit.js';
|
|
||||||
|
export function applyReplacement(
|
||||||
|
currentContent: string | null,
|
||||||
|
oldString: string,
|
||||||
|
newString: string,
|
||||||
|
isNewFile: boolean,
|
||||||
|
): string {
|
||||||
|
if (isNewFile) {
|
||||||
|
return newString;
|
||||||
|
}
|
||||||
|
if (currentContent === null) {
|
||||||
|
// Should not happen if not a new file, but defensively return empty or newString if oldString is also empty
|
||||||
|
return oldString === '' ? newString : '';
|
||||||
|
}
|
||||||
|
// If oldString is empty and it's not a new file, do not modify the content.
|
||||||
|
if (oldString === '' && !isNewFile) {
|
||||||
|
return currentContent;
|
||||||
|
}
|
||||||
|
return currentContent.replaceAll(oldString, newString);
|
||||||
|
}
|
||||||
|
|
||||||
interface ReplacementContext {
|
interface ReplacementContext {
|
||||||
params: EditToolParams;
|
params: EditToolParams;
|
||||||
|
|||||||
Reference in New Issue
Block a user