branch: elpa/aidermacs commit 2f3788f9435245c71c64523e44c6a1126161364a Merge: 081f8e49b5 3bebfd6dcc Author: Your Name <y...@example.com> Commit: Your Name <y...@example.com>
Merge branch 'main' of github.com:tninja/aider.el --- README.org | 57 +++++++++++++---------- aider.el | 134 +++++++++++++++++++---------------------------------- screenshot.png | Bin 0 -> 1287672 bytes transient_menu.png | Bin 0 -> 88948 bytes 4 files changed, 80 insertions(+), 111 deletions(-) diff --git a/README.org b/README.org index 6de7f2843e..5dad4d2869 100644 --- a/README.org +++ b/README.org @@ -1,35 +1,44 @@ -#+TITLE: aider.el : aider (AI pair programming) in your emacs +#+TITLE: aider.el : aider (AI pair programming) inside emacs * Introduction -The Aider package provides an interactive interface to communicate with https://github.com/paul-gauthier/aider. + +- Do you feel that [[https://www.cursor.com/][cursor AI code editor]] is attractive, but you don't want to leave emacs? + +- aider.el provides an interactive interface to communicate with https://github.com/paul-gauthier/aider. + - Most of elisp code in this repo was generated by aider / aider.el + +* Why use aider.el in emacs? + +- Pop-up menu: No need to remember the command. (aider-transient-menu, bind to C-c a by default) + +[[file:./transient_menu.png]] + +- Git repo specific aider session in emacs: automatically identify your git repo of current file, and create a new aider session for it. Multiple aider sessions can exist for different git repos. + +- Region based refactor support: You can select a region in file and ask aider to refactor that. + +- .. And more: add your own elisp function to support your use case. For sure you can ask aider / aider.el to do that. * Installation -To install the Aider package, add the following to your Emacs configuration: + +- [[https://aider.chat/docs/install.html][Install aider]] +- Install dependency [[https://github.com/magit/transient][transient]] with package manager +- Install aider.el with following code #+BEGIN_SRC emacs-lisp -(require 'aider) + (use-package aider + :straight (:host github :repo "tninja/aider.el") + :config + (setq aider-args '("--model" "gpt-4o-mini"))) + (setenv "OPENAI_API_KEY" <your-openai-api-key>) #+END_SRC -* Key Functions -- [[#run-aider][run-aider]]: Create a comint-based buffer and run 'aider' for interactive conversation. -- [[#aider-switch-to-buffer][aider-switch-to-buffer]]: Switch to the Aider buffer. -- [[#aider-add-current-file][aider-add-current-file]]: Send the command "/add <current buffer file full path>" to the *aider* comint buffer. -- [[#aider-drop-current-file][aider-drop-current-file]]: Send the command "/drop <current buffer file full path>" to the *aider* comint buffer. -- [[#aider-send-command][aider-send-command]]: Prompt the user to input a command and send it to the *aider* comint buffer. -- [[#aider-code-command][aider-code-command]]: Prompt the user for a command and send it to the *aider* comint buffer prefixed with "/code ". -- [[#aider-ask-question][aider-ask-question]]: Prompt the user for a command and send it to the *aider* comint buffer prefixed with "/ask ". -- [[#aider-architect-command][aider-architect-command]]: Prompt the user for a command and send it to the *aider* comint buffer prefixed with "/architect ". -- [[#aider-undo-last-change][aider-undo-last-change]]: Undo the last change made by Aider. -- [[#aider-region-code-command][aider-region-code-command]]: Get a command from the user and send it to the *aider* comint buffer based on the selected region. - -* Usage -To start an interactive conversation with Aider, use the following command: +* Screenshot -#+BEGIN_SRC emacs-lisp -M-x run-aider -#+END_SRC +[[file:./screenshot.png]] -For more detailed usage, refer to the key functions listed above. +* Other Emacs AI coding tool -* License -This package is licensed under the Apache-2.0 license. +- [[https://github.com/copilot-emacs/copilot.el][copilot.el]]: Emacs plugin for GitHub Copilot +- [[https://github.com/shouya/ancilla.el][ancilla.el]]: AI Coding Assistant support code generation / code rewrite / discussion +- [[https://github.com/xenodium/chatgpt-shell][chatgpt-shell]]: ChatGPT and DALL-E Emacs shells + Org Babel diff --git a/aider.el b/aider.el index 749c4ea95f..4d0b0ea2a5 100644 --- a/aider.el +++ b/aider.el @@ -1,8 +1,8 @@ -;;; aider.el --- Aider package for interactive conversation with OpenAI -*- lexical-binding: t; -*- +;;; aider.el --- Aider package for interactive conversation with aider -*- lexical-binding: t; -*- ;; Author: Kang Tu <tni...@gmail.com> ;; Version: 0.1.0 -;; Package-Requires: ((emacs "24.1") (transient "0.3.0")) +;; Package-Requires: ((emacs "25.1") (transient "0.3.0")) ;; Keywords: convenience, tools ;; URL: https://github.com/tninja/aider.el @@ -18,73 +18,37 @@ :prefix "aider-" :group 'convenience) - -(defcustom aider-deepseek-api-key deepseek-api-key - "DeepSeek API key for Aider." - :type 'string - :group 'aider) - -(defcustom aider-args '("--deepseek") +(defcustom aider-args '("--model" "gpt-4o-mini") "Arguments to pass to the Aider command." :type '(repeat string) :group 'aider) -;; (defcustom aider-openai-api-key chatgpt-shell-openai-key -;; "OpenAI API key for Aider." -;; :type 'string -;; :group 'aider) - -;; (defcustom aider-args '("--model" "gpt-4o-mini") -;; "Arguments to pass to the Aider command." -;; :type '(repeat string) -;; :group 'aider) - -;; Define the keymap for Aider commands -(defvar aider-global-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "a") 'run-aider) - (define-key map (kbd "z") 'aider-switch-to-buffer) - (define-key map (kbd "s") 'aider-add-current-file) - (define-key map (kbd "d") 'aider-drop-current-file) - (define-key map (kbd "c") 'aider-send-command) - (define-key map (kbd "d") 'aider-code-command) - (define-key map (kbd "q") 'aider-ask-question) - (define-key map (kbd "t") 'aider-architect-command) - (define-key map (kbd "e") 'aider-region-code-command) - (define-key map (kbd "u") 'aider-undo-last-change) - (define-key map (kbd "r") 'aider-reset-command) - (define-key map (kbd "m") 'aider-transient-menu) - map) - "Global keymap for Aider commands.") - -;; Activate the global keymap -(define-key global-map (kbd "C-c a") aider-global-map) - ;; Transient menu for Aider commands (transient-define-prefix aider-transient-menu () "Transient menu for Aider commands." ["Aider Menu" ["Aider process" - ("a" "Run Aider" run-aider) - ("s" "Add Current File" aider-add-current-file) + ("a" "Run Aider" aider-run-aider) + ("f" "Add Current File" aider-add-current-file) ("z" "Switch to Aider Buffer" aider-switch-to-buffer) - ("d" "Drop Current File" aider-drop-current-file) + ("s" "Reset Aider" aider-reset) ;; Menu item for reset command ] ["Code change" - ("d" "Code Change" aider-code-command) - ("e" "Region Code Change" aider-region-code-command) + ("c" "Code Change" aider-code-change) + ("r" "Region Code Refactor" aider-region-refactor) ("u" "Undo Last Change" aider-undo-last-change) ;; Menu item for undo last change ] ["Discussion" ("q" "Ask Question" aider-ask-question) - ("t" "Architect Discussion" aider-architect-command) + ("t" "Architect Discussion" aider-architect-discussion) ] ["Other" - ("r" "Reset Aider" aider-reset-command) ;; Menu item for reset command - ("c" "General Command" aider-send-command) + ("g" "General Command" aider-general-command) + ("h" "Help Command" aider-help) ;; Menu item for help command ] ]) +(global-set-key (kbd "C-c a") 'aider-transient-menu) (defun aider-buffer-name () "Generate the Aider buffer name based on the path from the home folder to the git repo of the current active buffer using a git command." @@ -94,7 +58,7 @@ (relative-path (substring git-repo-path (length home-path)))) (format "*aider:%s*" (concat "~" (replace-regexp-in-string "\n" "" relative-path))))) -(defun run-aider () +(defun aider-run-aider () "Create a comint-based buffer and run 'aider' for interactive conversation." (interactive) (let* ((buffer-name (aider-buffer-name)) @@ -102,8 +66,6 @@ ;; Check if the buffer already has a running process (unless (comint-check-proc buffer-name) ;; Create a new comint buffer and start the process - ;; (setenv "OPENAI_API_KEY" aider-openai-api-key) - (setenv "DEEPSEEK_API_KEY" aider-deepseek-api-key) (apply 'make-comint-in-buffer "aider" buffer-name command nil aider-args) ;; Optionally, you can set the mode or add hooks here (with-current-buffer buffer-name @@ -123,19 +85,19 @@ (message "Aider buffer '%s' does not exist." (aider-buffer-name))))) ;; Function to reset the Aider buffer -(defun aider-reset-command () +(defun aider-reset () "Send the command \"/reset\" to the Aider buffer." (interactive) (aider--send-command "/reset")) -;; Shared helper function to send commands to *aider* buffer +;; Shared helper function to send commands to corresponding aider buffer (defun aider--send-command (command) - "Send COMMAND to the *aider* comint buffer after performing necessary checks. + "Send COMMAND to the corresponding aider comint buffer after performing necessary checks. COMMAND should be a string representing the command to send." - ;; Check if the *aider* buffer exists + ;; Check if the corresponding aider buffer exists (if-let ((aider-buffer (get-buffer (aider-buffer-name)))) (let ((aider-process (get-buffer-process aider-buffer))) - ;; Check if the *aider* buffer has an active process + ;; Check if the corresponding aider buffer has an active process (if (and aider-process (comint-check-proc aider-buffer)) (progn ;; Ensure the command ends with a newline @@ -144,14 +106,14 @@ COMMAND should be a string representing the command to send." ;; Send the command to the aider process (comint-send-string aider-buffer command) ;; Provide feedback to the user - (message "Sent command to *aider*: %s" (string-trim command)) + (message "Sent command to aider buffer: %s" (string-trim command)) (aider-switch-to-buffer)) (message "No active process found in buffer %s." (aider-buffer-name)))) (message "Buffer %s does not exist. Please start 'aider' first." (aider-buffer-name)))) -;; Function to send "/add <current buffer file full path>" to *aider* buffer +;; Function to send "/add <current buffer file full path>" to corresponding aider buffer (defun aider-add-current-file () - "Send the command \"/add <current buffer file full path>\" to the *aider* comint buffer." + "Send the command \"/add <current buffer file full path>\" to the corresponding aider comint buffer." (interactive) ;; Ensure the current buffer is associated with a file (if (not buffer-file-name) @@ -162,47 +124,44 @@ COMMAND should be a string representing the command to send." ;; Use the shared helper function to send the command (aider--send-command command))))) -;; New function to send "/drop <current buffer file full path>" to *aider* buffer -(defun aider-drop-current-file () - "Send the command \"/drop <current buffer file full path>\" to the *aider* comint buffer." +;; Function to send a custom command to corresponding aider buffer +(defun aider-general-command () + "Prompt the user to input COMMAND and send it to the corresponding aider comint buffer." (interactive) - ;; Ensure the current buffer is associated with a file - (if (not buffer-file-name) - (message "Current buffer is not associated with a file.") - (let ((file-path (expand-file-name buffer-file-name))) - ;; Construct the command - (let ((command (format "/drop %s" file-path))) - ;; Use the shared helper function to send the command - (aider--send-command command))))) - -;; Function to send a custom command to *aider* buffer -(defun aider-send-command (command) - "Prompt the user to input COMMAND and send it to the *aider* comint buffer. -COMMAND is a string representing the command to send." - (interactive - (list (read-string "Enter command to send to aider: "))) - ;; Use the shared helper function to send the command - (aider--send-command command)) + (let ((command (read-string "Enter command to send to aider: "))) + ;; Use the shared helper function to send the command + (aider-add-current-file) + (aider--send-command command))) ;; New function to get command from user and send it prefixed with "/code " -(defun aider-code-command () - "Prompt the user for a command and send it to the *aider* comint buffer prefixed with \"/code \"." +(defun aider-code-change () + "Prompt the user for a command and send it to the corresponding aider comint buffer prefixed with \"/code \"." (interactive) (let ((command (read-string "Enter code command: "))) + (aider-add-current-file) (aider--send-command (concat "/code " command)))) ;; New function to get command from user and send it prefixed with "/ask " (defun aider-ask-question () - "Prompt the user for a command and send it to the *aider* comint buffer prefixed with \"/ask \"." + "Prompt the user for a command and send it to the corresponding aider comint buffer prefixed with \"/ask \"." (interactive) - (let ((command (read-string "Enter ask command: "))) + (let ((command (read-string "Enter ask question: "))) + (aider-add-current-file) (aider--send-command (concat "/ask " command)))) +;; New function to get command from user and send it prefixed with "/help " +(defun aider-help () + "Prompt the user for a command and send it to the corresponding aider comint buffer prefixed with \"/help \"." + (interactive) + (let ((command (read-string "Enter help command: "))) + (aider--send-command (concat "/help " command)))) + ;; New function to get command from user and send it prefixed with "/architect " -(defun aider-architect-command () - "Prompt the user for a command and send it to the *aider* comint buffer prefixed with \"/architect \"." +(defun aider-architect-discussion () + "Prompt the user for a command and send it to the corresponding aider comint buffer prefixed with \"/architect \"." (interactive) (let ((command (read-string "Enter architect command: "))) + (aider-add-current-file) (aider--send-command (concat "/architect " command)))) ;; Modified function to get command from user and send it based on selected region @@ -211,8 +170,8 @@ COMMAND is a string representing the command to send." (interactive) (aider--send-command "/undo")) -(defun aider-region-code-command () - "Get a command from the user and send it to the *aider* comint buffer based on the selected region. +(defun aider-region-refactor () + "Get a command from the user and send it to the corresponding aider comint buffer based on the selected region. The command will be formatted as \"/code \" followed by the user command and the text from the selected region." (interactive) (if (use-region-p) @@ -223,6 +182,7 @@ The command will be formatted as \"/code \" followed by the user command and the (command (format "/code \"in function %s, for the following code block, %s: %s\"" function-name user-command processed-region-text))) (aider--send-command command)) + (aider-add-current-file) (message "No region selected."))) (provide 'aider) diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000..4c1461b36d Binary files /dev/null and b/screenshot.png differ diff --git a/transient_menu.png b/transient_menu.png new file mode 100644 index 0000000000..4bd0a6dae8 Binary files /dev/null and b/transient_menu.png differ