branch: elpa/aidermacs
commit 3253a965662a645ba6f56dc04b8c859af405f65c
Author: Mingde (Matthew) Zeng <[email protected]>
Commit: Mingde (Matthew) Zeng <[email protected]>

    Further refactor
    
    Signed-off-by: Mingde (Matthew) Zeng <[email protected]>
---
 aidermacs-backend-comint.el | 15 ++++-------
 aidermacs-backend-vterm.el  | 52 +++++++++++++++++++-------------------
 aidermacs-backends.el       | 17 +++----------
 aidermacs-models.el         | 61 ++++++++++++++++++++-------------------------
 aidermacs.el                | 52 +++++++++++++++++++++-----------------
 5 files changed, 90 insertions(+), 107 deletions(-)

diff --git a/aidermacs-backend-comint.el b/aidermacs-backend-comint.el
index 1bdb9818da..ff7b2dfd04 100644
--- a/aidermacs-backend-comint.el
+++ b/aidermacs-backend-comint.el
@@ -39,8 +39,7 @@
                                          ("cpp" . "c++"))
   "Map external language names to Emacs names."
   :type '(alist :key-type (string :tag "Language Name/Alias")
-                :value-type (string :tag "Mode Name (without -mode)"))
-  :group 'aidermacs)
+                :value-type (string :tag "Mode Name (without -mode)")))
 
 (defconst aidermacs-search-marker "<<<<<<< SEARCH")
 (defconst aidermacs-diff-marker "=======")
@@ -52,24 +51,20 @@
 (defcustom aidermacs-comint-multiline-newline-key "S-<return>"
   "Key binding for `comint-accumulate' in Aidermacs buffers.
 This allows for multi-line input without sending the command."
-  :type 'string
-  :group 'aidermacs)
+  :type 'string)
 
 (defface aidermacs-command-separator
   '((((type graphic)) :strike-through t :extend t)
     (((type tty)) :inherit font-lock-comment-face :underline t :extend t))
-  "Face for command separator in aidermacs."
-  :group 'aidermacs)
+  "Face for command separator in aidermacs.")
 
 (defface aidermacs-command-text
   '((t :inherit bold))
-  "Face for commands sent to aidermacs buffer."
-  :group 'aidermacs)
+  "Face for commands sent to aidermacs buffer.")
 
 (defface aidermacs-search-replace-block
   '((t :inherit 'diff-refine-added :bold t))
-  "Face for search/replace block content."
-  :group 'aidermacs)
+  "Face for search/replace block content.")
 
 (defvar aidermacs-font-lock-keywords
   '(("^\x2500+\n?" 0 '(face aidermacs-command-separator) t)
diff --git a/aidermacs-backend-vterm.el b/aidermacs-backend-vterm.el
index 1ba32ba250..400450a864 100644
--- a/aidermacs-backend-vterm.el
+++ b/aidermacs-backend-vterm.el
@@ -63,8 +63,7 @@
 
 (defcustom aidermacs-vterm-multiline-newline-key "S-<return>"
   "Key binding to enter a newline without sending in vterm."
-  :type 'string
-  :group 'aidermacs)
+  :type 'string)
 
 (defvar aidermacs-prompt-regexp)
 
@@ -88,7 +87,7 @@ If the finish sequence is detected, store the output via
              ;; Only check if we have a new prompt or haven't checked this 
position yet
              (last-check (or aidermacs--vterm-last-check-point start-point))
              (should-check (> prompt-point last-check))
-             ;; Simplified pattern that just looks for a shell prompt
+             ;; Pattern that looks for a shell prompt
              (expected aidermacs-prompt-regexp))
         ;; Update the last check point
         (setq aidermacs--vterm-last-check-point prompt-point)
@@ -125,31 +124,32 @@ This sets a temporary process filter that checks for the 
finish sequence
 after each output chunk, reducing the need for timers."
   (when (and (aidermacs--is-aidermacs-buffer-p)
              (not (string-empty-p aidermacs--last-command)))
-      (let* ((start-point (condition-case nil
-                              (vterm--get-prompt-point)
-                            (error (point-min))))
-             (proc (get-buffer-process (current-buffer)))
-             (orig-filter (process-filter proc)))
-        ;; Store the command for tracking in the correct buffer
-        (with-current-buffer (process-buffer proc)
-          ;; Initialize tracking variables
-          (setq aidermacs--vterm-last-check-point nil)
-          ;; Cancel any existing timer first
-          (aidermacs--maybe-cancel-active-timer)
-          ;; Create a new timer immediately to start checking for command 
completion
-          (setq aidermacs--vterm-active-timer
-                (run-with-timer
-                 aidermacs-vterm-check-interval
-                 aidermacs-vterm-check-interval
-                 (lambda () (aidermacs--vterm-check-finish-sequence-repeated 
proc orig-filter start-point))))))))
+    (let* ((start-point (condition-case nil
+                            (vterm--get-prompt-point)
+                          (error (point-min))))
+           (proc (get-buffer-process (current-buffer)))
+           (orig-filter (process-filter proc)))
+      ;; Store the command for tracking in the correct buffer
+      (with-current-buffer (process-buffer proc)
+        ;; Initialize tracking variables
+        (setq aidermacs--vterm-last-check-point nil)
+        ;; Cancel any existing timer first
+        (aidermacs--maybe-cancel-active-timer)
+        ;; Create a new timer immediately to start checking for command 
completion
+        (setq aidermacs--vterm-active-timer
+              (run-with-timer
+               aidermacs-vterm-check-interval
+               aidermacs-vterm-check-interval
+               (lambda () (aidermacs--vterm-check-finish-sequence-repeated 
proc orig-filter start-point))))))))
 
 (defun aidermacs--maybe-cancel-active-timer (&optional buffer)
   "Cancel the active timer if it exists.
-Use BUFFER if provided, otherwise retrieve it from `aidermacs-get-buffer-name'"
-  (with-current-buffer (get-buffer (or buffer (aidermacs-get-buffer-name)))
-    (when (timerp aidermacs--vterm-active-timer)
-      (cancel-timer aidermacs--vterm-active-timer)
-      (setq aidermacs--vterm-active-timer nil))))
+Use BUFFER if provided, otherwise retrieve it from 
`aidermacs-get-buffer-name'."
+  (when-let ((buf (get-buffer (or buffer (aidermacs-get-buffer-name)))))
+    (with-current-buffer buf
+      (when (timerp aidermacs--vterm-active-timer)
+        (cancel-timer aidermacs--vterm-active-timer)
+        (setq aidermacs--vterm-active-timer nil)))))
 
 (defun aidermacs-run-vterm (program args buffer-name)
   "Create a vterm-based buffer and run aidermacs program.
@@ -243,7 +243,7 @@ _ARGS are the arguments."
     (define-key map (kbd "C-c C-c") #'aidermacs-vterm-send-C-c)
     (when (featurep 'evil)
       (evil-define-minor-mode-key map 'insert
-          (kbd "RET") (function aidermacs-vterm-send-return)))
+                                  (kbd "RET") (function 
aidermacs-vterm-send-return)))
     map)
   "Keymap used when `aidermacs-vterm-mode' is enabled.")
 
diff --git a/aidermacs-backends.el b/aidermacs-backends.el
index 878700625e..f6d3c64cf7 100644
--- a/aidermacs-backends.el
+++ b/aidermacs-backends.el
@@ -32,28 +32,17 @@
 (declare-function aidermacs--prepare-for-code-edit "aidermacs" ())
 (declare-function aidermacs--get-files-in-session "aidermacs" (callback))
 
-(defgroup aidermacs-backends nil
-  "Backend customization for aidermacs."
-  :group 'aidermacs)
-
 (defcustom aidermacs-backend 'comint
   "Backend to use for the aidermacs process.
 Options are `comint' (the default) or `vterm'.  When set to `vterm',
 aidermacs launches a fully functional vterm buffer instead
 of using a comint process."
   :type '(choice (const :tag "Comint" comint)
-                 (const :tag "VTerm" vterm))
-  :group 'aidermacs-backends)
-
-;; Core output management functionality
-(defgroup aidermacs-output nil
-  "Output handling for aidermacs."
-  :group 'aidermacs)
+                 (const :tag "VTerm" vterm)))
 
 (defcustom aidermacs-output-limit 10
   "Maximum number of output entries to keep in history."
-  :type 'integer
-  :group 'aidermacs-output)
+  :type 'integer)
 
 (defvar-local aidermacs--output-history nil
   "List to store aidermacs output history.
@@ -94,7 +83,7 @@ This is used to avoid having to run /ls repeatedly.")
 Remove any files that don't exist."
   (let* ((project-root (aidermacs-project-root))
          (is-remote (file-remote-p project-root))
-        (valid-files nil))
+         (valid-files nil))
     (dolist (file aidermacs--tracked-files)
       (let* ((is-readonly (string-match-p " (read-only)$" file))
              (actual-file (if is-readonly
diff --git a/aidermacs-models.el b/aidermacs-models.el
index d3af67230c..0fdcdafa9e 100644
--- a/aidermacs-models.el
+++ b/aidermacs-models.el
@@ -32,30 +32,22 @@
 (declare-function aidermacs-buffer-name "aidermacs" ())
 (declare-function aidermacs-exit "aidermacs" ())
 
-(defgroup aidermacs-models nil
-  "Model selection customization for aidermacs."
-  :group 'aidermacs)
-
 (defcustom aidermacs-default-model "sonnet"
   "Default AI model to use for aidermacs sessions when not in Architect mode."
-  :type 'string
-  :group 'aidermacs-models)
+  :type 'string)
 
 (defcustom aidermacs-architect-model "sonnet"
   "Default AI model to use for architectural reasoning in aidermacs sessions."
-  :type 'string
-  :group 'aidermacs-models)
+  :type 'string)
 
 (defcustom aidermacs-editor-model aidermacs-default-model
   "Default AI model to use for code editing in aidermacs sessions.
 Defaults to `aidermacs-default-model` if not explicitly set."
-  :type 'string
-  :group 'aidermacs-models)
+  :type 'string)
 
 (defcustom aidermacs-use-architect-mode nil
   "If non-nil, use separate Architect/Editor mode."
-  :type 'boolean
-  :group 'aidermacs-models)
+  :type 'boolean)
 
 (defcustom aidermacs-popular-models
   '("sonnet"
@@ -66,8 +58,7 @@ Defaults to `aidermacs-default-model` if not explicitly set."
   "List of available AI models for selection.
 Each model should be in the format expected by the aidermacs CLI.
 Also based on aidermacs LLM benchmark: 
https://aidermacs.chat/docs/leaderboards/";
-  :type '(repeat string)
-  :group 'aidermacs-models)
+  :type '(repeat string))
 
 (defvar aidermacs--cached-models aidermacs-popular-models
   "Cache of available AI models.")
@@ -79,28 +70,31 @@ Returns a list of model names with appropriate prefixes 
based on the
 API provider."
   (let* ((url-parsed (url-generic-parse-url url))
          (hostname (url-host url-parsed))
-         (prefix (cond ((string= hostname "api.openai.com") "openai")
-                       ((string= hostname "openrouter.ai") "openrouter")
-                       ((string= hostname "api.deepseek.com") "deepseek")
-                       ((string= hostname "api.anthropic.com") "anthropic")
-                       ((string= hostname "generativelanguage.googleapis.com") 
"gemini")
-                       (t (error "Unknown API host: %s" hostname))))
-         (token (cond ((string= hostname "api.openai.com") (getenv 
"OPENAI_API_KEY"))
-                      ((string= hostname "openrouter.ai") (getenv 
"OPENROUTER_API_KEY"))
-                      ((string= hostname "api.deepseek.com") (getenv 
"DEEPSEEK_API_KEY"))
-                      ((string= hostname "api.anthropic.com") (getenv 
"ANTHROPIC_API_KEY"))
-                      ((string= hostname "generativelanguage.googleapis.com") 
(getenv "GEMINI_API_KEY"))
-                      (t (error "Unknown API host: %s" hostname)))))
+         (prefix (pcase hostname
+                   ("api.openai.com" "openai")
+                   ("openrouter.ai" "openrouter")
+                   ("api.deepseek.com" "deepseek")
+                   ("api.anthropic.com" "anthropic")
+                   ("generativelanguage.googleapis.com" "gemini")
+                   (_ (error "Unknown API host: %s" hostname))))
+         (token (pcase hostname
+                  ("api.openai.com" (getenv "OPENAI_API_KEY"))
+                  ("openrouter.ai" (getenv "OPENROUTER_API_KEY"))
+                  ("api.deepseek.com" (getenv "DEEPSEEK_API_KEY"))
+                  ("api.anthropic.com" (getenv "ANTHROPIC_API_KEY"))
+                  ("generativelanguage.googleapis.com" (getenv 
"GEMINI_API_KEY"))
+                  (_ (error "Unknown API host: %s" hostname)))))
     (with-local-quit
       (with-current-buffer
           (let ((url-request-extra-headers
-                 (cond ((string= hostname "api.anthropic.com")
-                        `(("x-api-key" . ,token)
-                          ("anthropic-version" . "2023-06-01")))
-                       ((string= hostname "generativelanguage.googleapis.com")
-                        nil)  ; No auth headers for Gemini, key is in URL
-                       (t
-                        `(("Authorization" . ,(concat "Bearer " token)))))))
+                 (pcase hostname
+                   ("api.anthropic.com"
+                    `(("x-api-key" . ,token)
+                      ("anthropic-version" . "2023-06-01")))
+                   ("generativelanguage.googleapis.com"
+                    nil)  ; No auth headers for Gemini, key is in URL
+                   (_
+                    `(("Authorization" . ,(concat "Bearer " token)))))))
             (url-retrieve-synchronously
              (if (string= hostname "generativelanguage.googleapis.com")
                  (concat url "/models?key=" token)
@@ -121,7 +115,6 @@ API provider."
                                     (alist-get 'name model))))))
                   models))))))
 
-
 (defun aidermacs--select-model ()
   "Provide model selection with completion.
 This is a private function used internally."
diff --git a/aidermacs.el b/aidermacs.el
index 2f7f5180f1..91a6d31980 100644
--- a/aidermacs.el
+++ b/aidermacs.el
@@ -10,17 +10,16 @@
 
 ;;; Commentary:
 
-;; Aidermacs integrates with Aider for AI-assisted code modification
-;; in Emacs. Provides interface to interact with Aider through Emacs
-;; buffer with commands for file management, code generation, and
-;; question answering.
-;;
-;; Features:
-;; - AI-assisted code modification
-;; - Multiple backends (Comint and VTerm)
-;; - File management commands
-;; - Transient menus for quick access
-;; - Minor mode for prompt files
+;; Aidermacs integrates with Aider (https://aider.chat/) for AI-assisted code
+;; modification in Emacs. Aider lets you pair program with LLMs to edit code
+;; in your local git repository. It works with both new projects and existing
+;; code bases, supporting Claude, DeepSeek, ChatGPT, and can connect to almost
+;; any LLM including local models. Think of it as having a helpful coding
+;; partner that can understand your code, suggest improvements, fix bugs, and
+;; even write new code for you. Whether you're working on a new feature,
+;; debugging, or just need help understanding some code, Aidermacs provides an
+;; intuitive way to collaborate with AI while staying in your familiar Emacs
+;; environment.
 
 ;; Originally forked from Kang Tu <[email protected]>'s Aider.el.
 
@@ -201,7 +200,7 @@ If USE-EXISTING is non-nil, use an existing buffer instead 
of creating new."
                     (file-exists-p (car dir-info))))
              buffer-dirs)
             (lambda (a b)
-              ;; Sort by path length (deeper paths first)
+              ;; Sort by length of filenames (deeper filenames first)
               (> (length (car a)) (length (car b)))))))
          (display-root (cond
                         ;; Use current directory for new subtree session
@@ -218,6 +217,11 @@ If USE-EXISTING is non-nil, use an existing buffer instead 
of creating new."
   "Run aidermacs process using the selected backend.
 This function sets up the appropriate arguments and launches the process."
   (interactive)
+  ;; Set up necessary hooks when aidermacs is actually run
+  (aidermacs--setup-ediff-cleanup-hooks)
+  (aidermacs--setup-cleanup-hooks)
+  (aidermacs-setup-minor-mode)
+  
   (let* ((buffer-name (aidermacs-get-buffer-name))
          ;; Process extra args: split each string on whitespace.
          (flat-extra-args
@@ -351,8 +355,10 @@ the next file in the ediff queue if any remain."
     (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))
+  "Set up hooks to ensure proper cleanup of temporary buffers after ediff.
+Only adds the hook if it's not already present."
+  (unless (member #'aidermacs--ediff-quit-handler ediff-quit-hook)
+    (add-hook 'ediff-quit-hook #'aidermacs--ediff-quit-handler)))
 
 (defun aidermacs--detect-edited-files ()
   "Parse current output to find files edited by Aider.
@@ -973,7 +979,7 @@ snippets, or other content to the session."
       (insert ";; Just edit and save - changes will be available to aider\n\n")
       (write-file filename))
     (let ((command (aidermacs--prepare-file-paths-for-command "/read" (list 
filename))))
-      (aidermacs--send-command command))
+      (aidermacs--send-command command t t))
     (find-file-other-window filename)
     (message "Created and added scratchpad to session: %s" filename)))
 
@@ -1046,7 +1052,7 @@ Otherwise, send the line under cursor."
   (with-restriction start end
     (save-excursion
       (goto-char (point-min))
-      (while (search-forward "^[[:space:]]*\\(.+\\)[[:space:]]*$" nil t)
+      (while (search-forward "^[[:space:]]*\\([^[:space:]].*\\)[[:space:]]*$" 
nil t)
         (aidermacs--send-command (match-string 1))))))
 
 (defun aidermacs-send-block-or-region ()
@@ -1130,6 +1136,7 @@ These are exact filename matches (including the dot 
prefix)."
   "Set up automatic enabling of `aidermacs-minor-mode' for specific files.
 This adds a hook to automatically enable the minor mode for files
 matching patterns in `aidermacs-auto-mode-files'.
+Only adds the hook if it's not already present.
 
 The minor mode provides convenient keybindings for working with
 prompt files and other Aider-related files:
@@ -1138,7 +1145,8 @@ prompt files and other Aider-related files:
 \\[aidermacs-send-block-or-region] - Send block/region as whole
 \\[aidermacs-switch-to-buffer] - Switch to Aidermacs buffer"
   (interactive)
-  (add-hook 'find-file-hook #'aidermacs--maybe-enable-minor-mode))
+  (unless (member #'aidermacs--maybe-enable-minor-mode find-file-hook)
+    (add-hook 'find-file-hook #'aidermacs--maybe-enable-minor-mode)))
 
 ;;;###autoload
 (defun aidermacs-switch-to-code-mode ()
@@ -1191,12 +1199,10 @@ configuring, troubleshooting, etc."
     (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)
+  "Set up hooks to ensure proper cleanup of temporary buffers.
+Only adds the hook if it's not already present."
+  (unless (member #'aidermacs--cleanup-on-buffer-kill kill-buffer-hook)
+    (add-hook 'kill-buffer-hook #'aidermacs--cleanup-on-buffer-kill)))
 
 (provide 'aidermacs)
 ;;; aidermacs.el ends here

Reply via email to