From 4fb0bb22ac3cdc71ca15c634cd6c1d4dd30cd5df Mon Sep 17 00:00:00 2001 From: duanfuxiang Date: Tue, 1 Apr 2025 11:41:29 +0800 Subject: [PATCH] update edit aply file content --- src/ApplyView.tsx | 2 +- src/components/apply-view/ApplyViewRoot.tsx | 2 +- src/components/chat-view/Chat.tsx | 67 ++++++++++++--------- src/components/inline-edit/InlineEdit.tsx | 3 +- src/utils/apply.ts | 30 +++++---- 5 files changed, 54 insertions(+), 50 deletions(-) diff --git a/src/ApplyView.tsx b/src/ApplyView.tsx index 3ad76c5..9bb4366 100644 --- a/src/ApplyView.tsx +++ b/src/ApplyView.tsx @@ -7,7 +7,7 @@ import { AppProvider } from './contexts/AppContext' export type ApplyViewState = { file: TFile - originalContent: string + oldContent: string newContent: string onClose: (applied: boolean) => void } diff --git a/src/components/apply-view/ApplyViewRoot.tsx b/src/components/apply-view/ApplyViewRoot.tsx index 58c57bc..f3f674c 100644 --- a/src/components/apply-view/ApplyViewRoot.tsx +++ b/src/components/apply-view/ApplyViewRoot.tsx @@ -28,7 +28,7 @@ export default function ApplyViewRoot({ const app = useApp() const [diff, setDiff] = useState( - diffLines(state.originalContent, state.newContent), + diffLines(state.oldContent, state.newContent), ) const handleAccept = async () => { diff --git a/src/components/chat-view/Chat.tsx b/src/components/chat-view/Chat.tsx index 9d2aee3..1323420 100644 --- a/src/components/chat-view/Chat.tsx +++ b/src/components/chat-view/Chat.tsx @@ -48,7 +48,7 @@ import { PromptGenerator, addLineNumbers } from '../../utils/prompt-generator' import { fetchUrlsContent, webSearch } from '../../utils/web-search' // Simple file reading function that returns a placeholder content for testing -const readFileContent = async (app: App, filePath: string): Promise => { +const readFileContentByPath = async (app: App, filePath: string): Promise => { const file = app.vault.getFileByPath(filePath) if (!file) { throw new Error(`File not found: ${filePath}`) @@ -367,24 +367,23 @@ const Chat = forwardRef((props, ref) => { >({ mutationFn: async ({ applyMsgId, toolArgs }) => { try { - const activeFile = app.workspace.getActiveFile() - if (!activeFile) { - throw new Error( - 'No file is currently open to apply changes. Please open a file and try again.', - ) + let opFile = app.workspace.getActiveFile() + if ('filepath' in toolArgs && toolArgs.filepath) { + opFile = app.vault.getFileByPath(toolArgs.filepath) } - const activeFileContent = await readTFileContent(activeFile, app.vault) - if (toolArgs.type === 'write_to_file' || toolArgs.type === 'insert_content') { - const applyRes = await ApplyEditToFile( - activeFile, - activeFileContent, + if (!opFile) { + throw new Error(`File not found: ${toolArgs.filepath}`) + } + const fileContent = await readTFileContent(opFile, app.vault) + const appliedFileContent = await ApplyEditToFile( + fileContent, toolArgs.content, toolArgs.startLine, toolArgs.endLine ) - if (!applyRes) { + if (!appliedFileContent) { throw new Error('Failed to apply edit changes') } // return a Promise, which will be resolved after user makes a choice @@ -393,9 +392,9 @@ const Chat = forwardRef((props, ref) => { type: APPLY_VIEW_TYPE, active: true, state: { - file: activeFile, - originalContent: activeFileContent, - newContent: applyRes, + file: opFile, + oldContent: fileContent, + newContent: appliedFileContent, onClose: (applied: boolean) => { const applyStatus = applied ? ApplyStatus.Applied : ApplyStatus.Rejected const applyEditContent = applied ? 'Changes successfully applied' @@ -418,13 +417,15 @@ const Chat = forwardRef((props, ref) => { }) }) } else if (toolArgs.type === 'search_and_replace') { - const fileContent = activeFile.path === toolArgs.filepath ? activeFileContent : await readFileContent(app, toolArgs.filepath) - const applyRes = await SearchAndReplace( - activeFile, + if (!opFile) { + throw new Error(`File not found: ${toolArgs.filepath}`) + } + const fileContent = await readTFileContent(opFile, app.vault) + const appliedFileContent = await SearchAndReplace( fileContent, toolArgs.operations ) - if (!applyRes) { + if (!appliedFileContent) { throw new Error('Failed to search_and_replace') } // return a Promise, which will be resolved after user makes a choice @@ -433,9 +434,9 @@ const Chat = forwardRef((props, ref) => { type: APPLY_VIEW_TYPE, active: true, state: { - file: activeFile, - originalContent: activeFileContent, - newContent: applyRes, + file: opFile, + oldContent: fileContent, + newContent: appliedFileContent, onClose: (applied: boolean) => { const applyStatus = applied ? ApplyStatus.Applied : ApplyStatus.Rejected const applyEditContent = applied ? 'Changes successfully applied' @@ -458,12 +459,15 @@ const Chat = forwardRef((props, ref) => { }) }) } else if (toolArgs.type === 'apply_diff') { - const diffResult = await diffStrategy.applyDiff( - activeFileContent, + if (!opFile) { + throw new Error(`File not found: ${toolArgs.filepath}`) + } + const fileContent = await readTFileContent(opFile, app.vault) + const appliedResult = await diffStrategy.applyDiff( + fileContent, toolArgs.diff ) - if (!diffResult.success) { - console.log(diffResult) + if (!appliedResult || !appliedResult.success) { throw new Error(`Failed to apply_diff`) } // return a Promise, which will be resolved after user makes a choice @@ -472,9 +476,9 @@ const Chat = forwardRef((props, ref) => { type: APPLY_VIEW_TYPE, active: true, state: { - file: activeFile, - originalContent: activeFileContent, - newContent: diffResult.content, + file: opFile, + oldContent: fileContent, + newContent: appliedResult.content, onClose: (applied: boolean) => { const applyStatus = applied ? ApplyStatus.Applied : ApplyStatus.Rejected const applyEditContent = applied ? 'Changes successfully applied' @@ -497,7 +501,10 @@ const Chat = forwardRef((props, ref) => { }) }) } else if (toolArgs.type === 'read_file') { - const fileContent = await readFileContent(app, toolArgs.filepath) + if (!opFile) { + throw new Error(`File not found: ${toolArgs.filepath}`) + } + const fileContent = await readTFileContent(opFile, app.vault) const formattedContent = `[read_file for '${toolArgs.filepath}'] Result:\n${addLineNumbers(fileContent)}\n`; return { type: 'read_file', diff --git a/src/components/inline-edit/InlineEdit.tsx b/src/components/inline-edit/InlineEdit.tsx index 95ded77..bee4a48 100644 --- a/src/components/inline-edit/InlineEdit.tsx +++ b/src/components/inline-edit/InlineEdit.tsx @@ -241,8 +241,7 @@ export const InlineEdit: React.FC = ({ const endLine = parsedBlock?.endLine || defaultEndLine; const updatedContent = await ApplyEditToFile( - activeFile, - await plugin.app.vault.read(activeFile), + await plugin.app.vault.cachedRead(activeFile), finalContent, startLine, endLine diff --git a/src/utils/apply.ts b/src/utils/apply.ts index 2d524db..b8e78b5 100644 --- a/src/utils/apply.ts +++ b/src/utils/apply.ts @@ -4,32 +4,31 @@ import { SearchAndReplaceToolArgs } from '../types/apply'; /** * Applies changes to a file by replacing content within specified line range - * @param content - The new content to insert + * @param updateContent - The new content to insert * @param currentFile - The file being modified - * @param currentFileContent - The current content of the file + * @param rawContent - The current content of the file * @param startLine - Starting line number (1-based indexing, optional) * @param endLine - Ending line number (1-based indexing, optional) * @returns Promise resolving to the modified content or null if operation fails */ export const ApplyEditToFile = async ( - currentFile: TFile, - currentFileContent: string, - content: string, + rawContent: string, + updateContent: string, startLine?: number, endLine?: number, ): Promise => { try { - // 如果文件为空,直接返回新内容 - if (!currentFileContent || currentFileContent.trim() === '') { - return content; + // if file is empty, return new content + if (!rawContent || rawContent.trim() === '') { + return updateContent; } - // 如果要清空文件,直接返回空字符串 - if (content === '') { + // if content is empty, return empty string + if (updateContent === '') { return ''; } - const lines = currentFileContent.split('\n') + const lines = rawContent.split('\n') const effectiveStartLine = Math.max(1, startLine ?? 1) const effectiveEndLine = Math.min(endLine ?? lines.length, lines.length) @@ -41,7 +40,7 @@ export const ApplyEditToFile = async ( // Construct new content return [ ...lines.slice(0, effectiveStartLine - 1), - content, + updateContent, ...lines.slice(effectiveEndLine) ].join('\n') } catch (error) { @@ -58,16 +57,15 @@ function escapeRegExp(string: string): string { /** * 搜索和替换文件内容 * @param currentFile - 当前文件 - * @param currentFileContent - 当前文件内容 + * @param rawContent - 当前文件内容 * @param search - 搜索内容 * @param replace - 替换内容 */ export const SearchAndReplace = async ( - currentFile: TFile, - currentFileContent: string, + rawContent: string, operations: SearchAndReplaceToolArgs['operations'] ) => { - let lines = currentFileContent.split("\n") + let lines = rawContent.split("\n") for (const op of operations) { const flags = op.regexFlags ?? (op.ignoreCase ? "gi" : "g")