branch: elpa/aidermacs
commit fdce0f5b17c087356ad1233548543064a0a348d4
Author: Mingde (Matthew) Zeng <[email protected]>
Commit: Mingde (Matthew) Zeng <[email protected]>
Simplify ediff algorithm
---
aidermacs-backend-comint.el | 8 +-
aidermacs-backend-vterm.el | 8 +-
aidermacs.el | 192 ++++++++++++++++++++++----------------------
3 files changed, 102 insertions(+), 106 deletions(-)
diff --git a/aidermacs-backend-comint.el b/aidermacs-backend-comint.el
index 3e38f6cba1..d34ba64b8b 100644
--- a/aidermacs-backend-comint.el
+++ b/aidermacs-backend-comint.el
@@ -26,7 +26,7 @@
;; Forward declarations
(declare-function aidermacs--prepare-for-code-edit "aidermacs")
-(declare-function aidermacs--cleanup-all-temp-files "aidermacs")
+(declare-function aidermacs--cleanup-temp-buffers "aidermacs")
(declare-function aidermacs--show-ediff-for-edited-files "aidermacs")
(declare-function aidermacs--detect-edited-files "aidermacs")
(declare-function aidermacs--process-message-if-multi-line "aidermacs" (str))
@@ -116,7 +116,7 @@ that was matched at the start of the current syntax block.")
(let ((edited-files (aidermacs--detect-edited-files)))
(if edited-files
(aidermacs--show-ediff-for-edited-files edited-files)
- (aidermacs--cleanup-all-temp-files)))
+ (aidermacs--cleanup-temp-buffers)))
(setq aidermacs--comint-output-temp ""))))
(defun aidermacs-reset-font-lock-state ()
@@ -337,11 +337,11 @@ The output is collected and passed to the current
callback."
(buffer-string))))))
(defun aidermacs--cleanup-temp-files-on-interrupt-comint (orig-fun &rest args)
- "Run `aidermacs--cleanup-all-temp-files' after interrupting a comint subjob.
+ "Run `aidermacs--cleanup-temp-buffers' after interrupting a comint subjob.
ORIG-FUN is the original function being advised. ARGS are its arguments."
(apply orig-fun args)
(when (aidermacs--is-aidermacs-buffer-p)
- (aidermacs--cleanup-all-temp-files)))
+ (aidermacs--cleanup-temp-buffers)))
(provide 'aidermacs-backend-comint)
diff --git a/aidermacs-backend-vterm.el b/aidermacs-backend-vterm.el
index f7a56f71d9..39ff7f7858 100644
--- a/aidermacs-backend-vterm.el
+++ b/aidermacs-backend-vterm.el
@@ -39,7 +39,7 @@
(declare-function vterm-insert "vterm")
(declare-function aidermacs--prepare-for-code-edit "aidermacs")
-(declare-function aidermacs--cleanup-all-temp-files "aidermacs")
+(declare-function aidermacs--cleanup-temp-buffers "aidermacs")
(declare-function aidermacs--show-ediff-for-edited-files "aidermacs")
(declare-function aidermacs--detect-edited-files "aidermacs")
(declare-function aidermacs--store-output "aidermacs")
@@ -108,7 +108,7 @@ If the finish sequence is detected, store the output via
;; Check if any files were edited and show ediff if needed
(if edited-files
(aidermacs--show-ediff-for-edited-files edited-files)
- (aidermacs--cleanup-all-temp-files))
+ (aidermacs--cleanup-temp-buffers))
;; Restore the original process filter now that we've
finished processing
;; this command's output. This returns vterm to its normal
behavior.
(set-process-filter proc orig-filter)
@@ -235,7 +235,7 @@ BUFFER is the target buffer to send to. COMMAND is the
text to send."
(advice-remove 'vterm-send-return #'aidermacs--vterm-capture-keyboard-input))
(defun aidermacs--cleanup-temp-files-on-interrupt-vterm (&rest _args)
- "Run `aidermacs--cleanup-all-temp-files' after interrupting a vterm subjob.
+ "Run `aidermacs--cleanup-temp-buffers' after interrupting a vterm subjob.
_ARGS are the arguments."
(when (and (aidermacs--is-aidermacs-buffer-p)
(equal (this-command-keys) "\C-c\C-c"))
@@ -243,7 +243,7 @@ _ARGS are the arguments."
(setq-local aidermacs--vterm-processing-command nil)
;; Cancel any active timer
(aidermacs--maybe-cancel-active-timer)
- (aidermacs--cleanup-all-temp-files)))
+ (aidermacs--cleanup-temp-buffers)))
(provide 'aidermacs-backend-vterm)
;;; aidermacs-backend-vterm.el ends here
diff --git a/aidermacs.el b/aidermacs.el
index 63043f8e43..3e654bb663 100644
--- a/aidermacs.el
+++ b/aidermacs.el
@@ -102,11 +102,10 @@ This is the file name without path."
(defvar-local aidermacs-read-string-history nil
"History list for aidermacs read string inputs.")
-(defvar-local aidermacs--pre-edit-files nil
- "Alist of (filename . temp-filename) pairs storing file state before Aider
edits.")
-
-(defvar-local aidermacs--pre-edit-buffers nil
- "Alist of (filename . temp-buffer) pairs for active ediff sessions.")
+(defvar-local aidermacs--pre-edit-file-buffers nil
+ "Alist of (filename . temp-buffer) pairs storing file state before Aider
edits.
+These buffers contain the original content of files that might be modified by
Aider.
+Instead of writing to temporary files, we keep the original content in memory
buffers.")
;;;###autoload
@@ -301,108 +300,103 @@ This is useful for working in monorepos where you want
to limit aider's scope."
(aidermacs-run)))
(defun aidermacs--capture-file-state (filename)
- "Store the current state of FILENAME in a temporary file."
+ "Store the current state of FILENAME in a temporary buffer.
+Creates a read-only buffer with the file's content, appropriate major mode,
+and syntax highlighting to match the original file."
(when (and filename (file-exists-p filename))
- (let ((temp-file (make-temp-file
- (concat "aidermacs-"
- (file-name-nondirectory filename) "-"))))
- (condition-case err
- (progn
- (copy-file filename temp-file t)
- (cons filename temp-file))
- (error
- (message "Error capturing file state for %s: %s"
- filename (error-message-string err))
- (when (file-exists-p temp-file)
- (delete-file temp-file))
- nil)))))
-
-(defun aidermacs--cleanup-all-temp-files ()
- "Clean up all temporary files created for ediff sessions.
-This is called when all ediff sessions are complete."
+ (condition-case err
+ (let ((temp-buffer (generate-new-buffer
+ (format " *aidermacs-pre-edit:%s*"
+ (file-name-nondirectory filename)))))
+ (with-current-buffer temp-buffer
+ (insert-file-contents filename)
+ (set-buffer-modified-p nil)
+ ;; Use same major mode as the original file
+ (let ((buffer-file-name filename))
+ (set-auto-mode)
+ ;; Ensure syntax highlighting is applied
+ (font-lock-ensure))
+ ;; Make buffer read-only
+ (setq buffer-read-only t))
+ (cons filename temp-buffer))
+ (error
+ (message "Error capturing file state for %s: %s"
+ filename (error-message-string err))
+ nil))))
+
+(defun aidermacs--cleanup-temp-buffers ()
+ "Clean up all temporary buffers created for ediff sessions.
+This is called when all ediff sessions are complete.
+Kills all pre-edit buffers that were created to store original file content."
(interactive)
(with-current-buffer (get-buffer (aidermacs-get-buffer-name))
- (dolist (file-pair aidermacs--pre-edit-files)
- (let ((temp-file (cdr file-pair)))
- (when (and temp-file (stringp temp-file) (file-exists-p temp-file))
- (message "Deleting %s" temp-file)
- (delete-file temp-file))))
+ ;; Clean up buffers in the tracking list
+ (dolist (file-pair aidermacs--pre-edit-file-buffers)
+ (let ((temp-buffer (cdr file-pair)))
+ (when (and temp-buffer (buffer-live-p temp-buffer))
+ (kill-buffer temp-buffer))))
+ ;; Also clean up any stray pre-edit buffers that might have been missed
+ (dolist (buf (buffer-list))
+ (when (and (string-match " \\*aidermacs-pre-edit:" (buffer-name buf))
+ (buffer-live-p buf))
+ (kill-buffer buf)))
;; Clear the list after cleanup
- (setq aidermacs--pre-edit-files nil)
- (setq aidermacs--pre-edit-buffers nil)))
+ (setq aidermacs--pre-edit-file-buffers nil)))
(defun aidermacs--prepare-for-code-edit ()
- "Prepare for Aider code edits by capturing current file states."
+ "Prepare for code edits by capturing current file states in memory buffers.
+Creates temporary buffers containing the original content of all tracked
files."
(let ((files aidermacs--tracked-files))
(when files
- (setq aidermacs--pre-edit-files
+ (setq aidermacs--pre-edit-file-buffers
(cl-remove-duplicates
(mapcar (lambda (file)
(let* ((clean-file (replace-regexp-in-string "
(read-only)$" "" file))
(full-path (expand-file-name clean-file
(aidermacs-project-root))))
;; Only capture state if we don't already have it
- (or (assoc full-path aidermacs--pre-edit-files)
+ (or (assoc full-path aidermacs--pre-edit-file-buffers)
(aidermacs--capture-file-state full-path))))
files)
:test (lambda (a b) (equal (car a) (car b)))))
;; Remove nil entries from the list (where capture failed or was skipped)
- (setq aidermacs--pre-edit-files (delq nil aidermacs--pre-edit-files))
+ (setq aidermacs--pre-edit-file-buffers (delq nil
aidermacs--pre-edit-file-buffers))
;; Run again if it's nil
- (unless aidermacs--pre-edit-files
+ (unless aidermacs--pre-edit-file-buffers
(aidermacs--prepare-for-code-edit)))))
(defun aidermacs--ediff-quit-handler ()
"Handle ediff session cleanup and process next files in queue.
-This function is called when an ediff session is quit and performs two tasks:
-1. Cleans up resources (buffers and temp files) for the current ediff session
-2. Processes the next file in the ediff queue if any remain"
- ;; Clean up any pre-edit buffers
- (dolist (buf (buffer-list))
- (when (string-match "\\*aidermacs-pre-edit:\\(.*\\)\\*" (buffer-name buf))
- (when (buffer-live-p buf)
- (kill-buffer buf))))
- (aidermacs--process-next-ediff-file))
+This function is called when an ediff session is quit and processes
+the next file in the ediff queue if any remain."
+ (when (and (boundp 'ediff-buffer-A)
+ (buffer-live-p ediff-buffer-A)
+ (string-match " \\*aidermacs-pre-edit:"
+ (buffer-name ediff-buffer-A)))
+ (aidermacs--process-next-ediff-file)))
(defun aidermacs--setup-ediff-cleanup-hooks ()
"Set up hooks to ensure proper cleanup of temporary buffers after ediff."
(add-hook 'ediff-quit-hook #'aidermacs--ediff-quit-handler))
(defun aidermacs--detect-edited-files ()
- "Parse current output to find files edited by Aider."
- (let ((edited-files nil)
- (output aidermacs--current-output))
- (with-temp-buffer
- (insert output)
- (goto-char (point-min))
- (while (re-search-forward "Applied edit to \\(.+\\)" nil t)
- (push (match-string 1) edited-files)))
+ "Detect files edited by Aider by comparing buffer contents.
+Returns a list of files that have been modified compared to their
+pre-edit state stored in temporary buffers."
+ (let ((edited-files nil))
+ (dolist (file-pair aidermacs--pre-edit-file-buffers)
+ (let* ((filename (car file-pair))
+ (pre-edit-buffer (cdr file-pair))
+ (current-content (with-temp-buffer
+ (when (file-exists-p filename)
+ (insert-file-contents filename))
+ (buffer-string)))
+ (original-content (with-current-buffer pre-edit-buffer
+ (buffer-string))))
+ (unless (equal original-content current-content)
+ (push filename edited-files))))
+ ;; Return the list of edited files
(nreverse edited-files)))
-(defun aidermacs--create-pre-edit-buffer (filename temp-file)
- "Create a buffer for FILENAME using content from TEMP-FILE for ediff."
- (condition-case err
- (let ((buffer (generate-new-buffer (format "*aidermacs-pre-edit:%s*"
- (file-name-nondirectory
filename)))))
- (with-current-buffer buffer
- (condition-case err2
- (progn
- (insert-file-contents temp-file)
- (set-buffer-modified-p nil)
- ;; Use same major mode as the original file would have
- (let ((buffer-file-name filename))
- (set-auto-mode))
- ;; Ensure syntax highlighting is applied
- (font-lock-ensure)
- ;; Make sure buffer is read-only
- (setq buffer-read-only t))
- (error
- (message "Error setting up pre-edit buffer: %s"
(error-message-string err2))
- (kill-buffer buffer)
- nil)))
- buffer)
- (error
- (message "Failed to create pre-edit buffer: %s" (error-message-string
err))
- nil)))
(defvar-local aidermacs--ediff-queue nil
"Buffer-local queue of files waiting to be processed by ediff.")
@@ -413,34 +407,24 @@ This function is called when an ediff session is quit and
performs two tasks:
(if aidermacs--ediff-queue
(let ((file (pop aidermacs--ediff-queue)))
(aidermacs--show-ediff-for-file file))
- (aidermacs--cleanup-all-temp-files))))
+ (aidermacs--cleanup-temp-buffers))))
(defun aidermacs--show-ediff-for-file (file)
- "Show ediff for FILE."
+ "Uses the pre-edit buffer stored in memory to compare with the current file
state."
(let* ((full-path (expand-file-name file (aidermacs-project-root)))
- (pre-edit-pair (assoc full-path aidermacs--pre-edit-files))
- (temp-file (and pre-edit-pair (cdr pre-edit-pair))))
- (if (and temp-file
- (stringp temp-file)
- (file-exists-p temp-file))
+ (pre-edit-pair (assoc full-path aidermacs--pre-edit-file-buffers))
+ (pre-edit-buffer (and pre-edit-pair (cdr pre-edit-pair))))
+ (if (and pre-edit-buffer (buffer-live-p pre-edit-buffer))
(progn
- ;; Create buffer from temp file only when needed
- (let* ((pre-edit-buffer (aidermacs--create-pre-edit-buffer full-path
temp-file))
- (current-buffer (or (get-file-buffer full-path)
- (find-file-noselect full-path))))
+ (let ((current-buffer (or (get-file-buffer full-path)
+ (find-file-noselect full-path))))
(with-current-buffer current-buffer
(revert-buffer t t t))
(delete-other-windows (get-buffer-window (switch-to-buffer
current-buffer)))
- ;; Store buffer for cleanup
- (unless (boundp 'aidermacs--pre-edit-buffers)
- (setq-local aidermacs--pre-edit-buffers nil))
- (push (cons full-path pre-edit-buffer) aidermacs--pre-edit-buffers)
- ;; Debug info
- (message "Comparing %s with %s" temp-file full-path)
;; Start ediff session
(ediff-buffers pre-edit-buffer current-buffer)))
- ;; If no pre-edit temp file found, continue with next file
- (message "No pre-edit file found for %s in %s out of %s, skipping" file
pre-edit-pair aidermacs--pre-edit-files)
+ ;; If no pre-edit buffer found, continue with next file
+ (message "No pre-edit buffer found for %s, skipping" file)
(aidermacs--process-next-ediff-file))))
(defun aidermacs--show-ediff-for-edited-files (edited-files)
@@ -478,7 +462,7 @@ If CALLBACK is non-nil it will be called after the command
finishes."
(setq-local aidermacs--current-output nil)
(setq-local aidermacs--last-command processed-command)
;; Always prepare for potential edits
- (aidermacs--cleanup-all-temp-files)
+ (aidermacs--cleanup-temp-buffers)
(aidermacs--prepare-for-code-edit))
(aidermacs--send-command-backend buffer processed-command redirect
callback)
@@ -520,6 +504,7 @@ If the current buffer is already the aidermacs buffer, do
nothing."
(defun aidermacs-exit ()
"Send the command \"/exit\" to the aidermacs buffer."
(interactive)
+ (aidermacs--cleanup-temp-buffers)
(aidermacs--send-command "/exit" t))
@@ -1186,7 +1171,18 @@ configuring, troubleshooting, etc."
(setq-local aidermacs--current-mode 'help))
(message "Switched to help mode - aider will answer questions about using
aider"))
-;; Initialize the cleanup mechanisms
+;; Add a hook to clean up temp buffers when an aidermacs buffer is killed
+(defun aidermacs--cleanup-on-buffer-kill ()
+ "Clean up temporary buffers when an aidermacs buffer is killed."
+ (when (string-match "^\\*aidermacs:" (buffer-name))
+ (aidermacs--cleanup-temp-buffers)))
+
+(defun aidermacs--setup-cleanup-hooks ()
+ "Set up hooks to ensure proper cleanup of temporary buffers."
+ (add-hook 'kill-buffer-hook #'aidermacs--cleanup-on-buffer-kill))
+
+(aidermacs--setup-ediff-cleanup-hooks)
+(aidermacs-setup-minor-mode)
(aidermacs--setup-ediff-cleanup-hooks)
(provide 'aidermacs)