branch: elpa/aidermacs commit 73eda045ac57c97a71f78dbafbadc948d8f9ec57 Merge: 47918c434d 764a99dd5e Author: Reindert-Jan Ekker <rjek...@gmail.com> Commit: GitHub <nore...@github.com>
Merge branch 'main' into match-theme --- .gitignore | 4 ++ CHANGELOG.md | 16 +++++ README.md | 67 ++++++++++------- aidermacs-backend-comint.el | 15 +++- aidermacs-backend-vterm.el | 18 +++-- aidermacs-backends.el | 171 +++++++++++++++++++++----------------------- aidermacs-models.el | 6 +- aidermacs.el | 56 +++++++++------ 8 files changed, 208 insertions(+), 145 deletions(-) diff --git a/.gitignore b/.gitignore index 7364d48a21..05d1193288 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ .env __pycache__ /*.elc + +# ELPA-generated files. +/aidermacs-pkg.el +/aidermacs-autoloads.el diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..4955e59dc5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# CHANGELOG + +## 1.0 - Initial Release + +### Features + +- **Built-in Ediff Integration:** Review AI-generated changes with Emacs' familiar `ediff` interface. +- **Intelligent Model Selection:** Automatically discover and integrate with multiple AI providers (OpenAI, Anthropic, DeepSeek, Google Gemini, OpenRouter). +- **Flexible Terminal Backend Support:** Choose between `comint` and `vterm` backends for the best terminal compatibility and performance. +- **Enhanced File Management:** Easily manage files within your Aider session with commands for adding, dropping, listing, and more. Full support for remote files via Tramp (SSH, Docker, etc.). +- **Streamlined Transient Menu Selection:** Access all Aidermacs features through a redesigned and ergonomic transient menu system. +- **Prompt Files Minor Mode:** Work seamlessly with prompt files and other Aider-related files with convenient keybindings and automatic mode activation. +- **Claude 3.7 Sonnet Thinking Tokens:** Enable and configure thinking tokens using the `/think-tokens` in-chat command or the `--thinking-tokens` command-line argument. +- **Architect Mode Confirmation:** Control whether to automatically accept Architect mode changes with the `aidermacs-auto-accept-architect` variable. +- **Re-Enable Auto-Commits:** Aider automatically commits AI-generated changes by default. We consider this behavior *very* intrusive, so we've disabled it. You can re-enable auto-commits by setting `aidermacs-auto-commits` to `t`. +- **Customizing Aider Options with `aidermacs-extra-args`:** Pass any Aider-supported command-line options. diff --git a/README.md b/README.md index ed82176d0b..3d9c67f1dd 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,24 @@ Here's what the community is saying about Aidermacs: ## Configuration +#### Pre-Run Hook + +You can use the `aidermacs-before-run-backend-hook` to run custom setup code before starting the Aider backend. This is particularly useful for: + +- Setting environment variables +- Injecting secrets +- Performing any other pre-run configuration + +Example usage to securely set an OpenAI API key from password-store: + +```elisp +(add-hook 'aidermacs-before-run-backend-hook + (lambda () + (setenv "OPENAI_API_KEY" (password-store-get "code/openai_api_key")))) +``` + +This approach keeps sensitive information out of your dotfiles while still making it available to Aidermacs. + ### Default Model Selection You can customize the default AI model used by Aidermacs by setting the `aidermacs-default-model` variable: @@ -133,7 +151,19 @@ When Architect mode is enabled, the `aidermacs-default-model` setting is ignored (setq aidermacs-editor-model "deepseek/deepseek-chat") ;; defaults to aidermacs-default-model ``` -*Note: This configuration will be overwritten by the existence of an `.aider.conf.yml` file (see [details](#Overwrite-Configuration-with-Configuration-File)).* +*Note: These configurations will be overwritten by the existence of an `.aider.conf.yml` file (see [details](#Overwrite-Configuration-with-Configuration-File)).* + +#### Architect Mode Confirmation + +By default, Aidermacs requires explicit confirmation before applying changes proposed in Architect mode. This gives you a chance to review the AI's plan before any code is modified. + +If you prefer to automatically accept all Architect mode changes without confirmation (similar to Aider's default behavior), you can enable this with: + +```emacs-lisp +(setq aidermacs-auto-accept-architect t) +``` + +*Note: These configurations will be overwritten by the existence of an `.aider.conf.yml` file (see [details](#Overwrite-Configuration-with-Configuration-File)).* ### Terminal Backend Selection @@ -252,30 +282,19 @@ Aidermacs supports project-specific configurations via `.aider.conf.yml` files. ### Claude 3.7 Sonnet Thinking Tokens -Aider can work with Sonnet 3.7's [new thinking tokens](https://www.anthropic.com/news/claude-3-7-sonnet), but does not ask Sonnet to use thinking tokens by default. - -Enabling thinking currently requires manual configuration. Create an `.aider.model.settings.yml` in your home dir, project's root, or the current directory, then add the following to the file. Adjust the `budget_tokens` value to change the target number of thinking tokens. - -```yaml -- name: anthropic/claude-3-7-sonnet-20250219 - edit_format: diff - weak_model_name: anthropic/claude-3-5-haiku-20241022 - use_repo_map: true - examples_as_sys_msg: true - use_temperature: false - extra_params: - extra_headers: - anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25,output-128k-2025-02-19 - max_tokens: 64000 - thinking: - type: enabled - budget_tokens: 32000 # Adjust this number - cache_control: true - editor_model_name: anthropic/claude-3-7-sonnet-20250219 - editor_edit_format: editor-diff -``` +Aider can work with Sonnet 3.7's [new thinking tokens](https://www.anthropic.com/news/claude-3-7-sonnet). You can now enable and configure thinking tokens more easily using the following methods: + +1. **In-Chat Command:** Use the `/think-tokens` command followed by the desired token budget. For example: `/think-tokens 8k` or `/think-tokens 10000`. Supported formats include `8096`, `8k`, `10.5k`, and `0.5M`. + +2. **Command-Line Argument:** Set the `--thinking-tokens` argument when starting Aidermacs. For example, you can add this to your `aidermacs-extra-args`: + + ```emacs-lisp + (setq aidermacs-extra-args '("--thinking-tokens" "16k")) + ``` + +These methods provide a more streamlined way to control thinking tokens without requiring manual configuration of `.aider.model.settings.yml` files. -More streamlined support will be coming soon. +*Note: If you are using an `.aider.conf.yml` file, you can also set the `thinking_tokens` option there.* ## Usage diff --git a/aidermacs-backend-comint.el b/aidermacs-backend-comint.el index 4b73907d4b..d891d04e7f 100644 --- a/aidermacs-backend-comint.el +++ b/aidermacs-backend-comint.el @@ -1,6 +1,6 @@ ;;; aidermacs-backend-comint.el --- Comint backend for aidermacs -*- lexical-binding: t; -*- ;; Author: Mingde (Matthew) Zeng <matthew...@posteo.net> -;; Version: 1.0.0 +;; Version: 1.0 ;; Keywords: ai emacs llm aider ai-pair-programming tools ;; URL: https://github.com/MatthewZMD/aidermacs ;; SPDX-License-Identifier: Apache-2.0 @@ -31,6 +31,15 @@ (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)) +(declare-function aidermacs--parse-output-for-files "aidermacs-backends" (output)) +(declare-function aidermacs--store-output "aidermacs-backends" (output)) +(declare-function aidermacs--is-aidermacs-buffer-p "aidermacs-backends" (&optional buffer)) + +(defvar aidermacs--last-command) + +(defgroup aidermacs-backend-comint nil + "Comint backend for Aidermacs." + :group 'aidermacs) (defcustom aidermacs-language-name-map '(("elisp" . "emacs-lisp") ("bash" . "sh") @@ -41,6 +50,8 @@ :type '(alist :key-type (string :tag "Language Name/Alias") :value-type (string :tag "Mode Name (without -mode)"))) +;; FIXME: Hmm... seems to use standard diff3 markers. Maybe some code +;; in `smerge-mode.el' could be (re)used? (defconst aidermacs-search-marker "<<<<<<< SEARCH") (defconst aidermacs-diff-marker "=======") (defconst aidermacs-replace-marker ">>>>>>> REPLACE") @@ -63,7 +74,7 @@ This allows for multi-line input without sending the command." "Face for commands sent to aidermacs buffer.") (defface aidermacs-search-replace-block - '((t :inherit 'diff-refine-added :bold t)) + '((t :inherit diff-refine-added :bold t)) "Face for search/replace block content.") (defvar aidermacs-font-lock-keywords diff --git a/aidermacs-backend-vterm.el b/aidermacs-backend-vterm.el index 24dee78147..d4fbc3af1a 100644 --- a/aidermacs-backend-vterm.el +++ b/aidermacs-backend-vterm.el @@ -1,6 +1,6 @@ ;;; aidermacs-backend-vterm.el --- VTerm backend for aidermacs -*- lexical-binding: t; -*- ;; Author: Mingde (Matthew) Zeng <matthew...@posteo.net> -;; Version: 1.0.0 +;; Version: 1.0 ;; Keywords: ai emacs llm aider ai-pair-programming tools ;; URL: https://github.com/MatthewZMD/aidermacs ;; SPDX-License-Identifier: Apache-2.0 @@ -47,26 +47,30 @@ (declare-function aidermacs--is-aidermacs-buffer-p "aidermacs") (declare-function aidermacs-get-buffer-name "aidermacs") -;; useful because we want to override "RET" key for evil mode insert state +(declare-function aidermacs--parse-output-for-files "aidermacs-backends" (output)) + (declare-function evil-define-minor-mode-key "evil-core") +(defvar aidermacs-prompt-regexp) +(defvar aidermacs--last-command) + +(defgroup aidermacs-backend-vterm nil + "VTerm backend for Aidermacs." + :group 'aidermacs) + (defvar-local aidermacs--vterm-active-timer nil "Store the active timer for vterm output processing.") (defvar-local aidermacs--vterm-last-check-point nil "Store the last position checked in the vterm buffer.") - (defvar-local aidermacs-vterm-check-interval 0.7 "Interval in seconds between checks for command completion in vterm.") - (defcustom aidermacs-vterm-multiline-newline-key "S-<return>" "Key binding to enter a newline without sending in vterm." :type 'string) -(defvar aidermacs-prompt-regexp) - (defun aidermacs--vterm-check-finish-sequence-repeated (proc orig-filter start-point) "Check for the finish sequence in PROC's buffer. PROC is the process to check. ORIG-FILTER is the original process filter. @@ -145,7 +149,7 @@ after each output chunk, reducing the need for timers." (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'." - (when-let ((buf (get-buffer (or buffer (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) diff --git a/aidermacs-backends.el b/aidermacs-backends.el index 2556c6e256..9f37f4da0d 100644 --- a/aidermacs-backends.el +++ b/aidermacs-backends.el @@ -1,6 +1,6 @@ ;;; aidermacs-backends.el --- Backend dispatcher for aidermacs -*- lexical-binding: t; -*- ;; Author: Mingde (Matthew) Zeng <matthew...@posteo.net> -;; Version: 1.0.0 +;; Version: 1.0 ;; Keywords: ai emacs llm aider ai-pair-programming tools ;; URL: https://github.com/MatthewZMD/aidermacs ;; SPDX-License-Identifier: Apache-2.0 @@ -32,6 +32,10 @@ (declare-function aidermacs--prepare-for-code-edit "aidermacs" ()) (declare-function aidermacs--get-files-in-session "aidermacs" (callback)) +(defgroup aidermacs-backends nil + "Backend dispatcher 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', @@ -54,6 +58,10 @@ Each entry is a cons cell (timestamp . output-text).") (defvar-local aidermacs--current-output "" "Accumulator for current output being captured as a string.") +(defcustom aidermacs-before-run-backend-hook nil + "Hook run before the aidermacs backend is startd." + :type 'hook) + (defun aidermacs-get-output-history (&optional limit) "Get the output history, optionally limited to LIMIT entries. LIMIT is the maximum number of entries to return. @@ -81,91 +89,81 @@ This is used to avoid having to run /ls repeatedly.") (defun aidermacs--parse-output-for-files (output) "Parse OUTPUT for files and add them to `aidermacs--tracked-files'." (when output - (let ((tracked-files aidermacs--tracked-files)) - (with-temp-buffer - (insert output) - (goto-char (point-min)) - - ;; Applied edit to <filename> - (while (search-forward "Applied edit to" nil t) - (beginning-of-line) - (when-let ((file (and (looking-at ".*Applied edit to \\(\\./\\)?\\(.+\\)") - (match-string-no-properties 2)))) - (add-to-list 'tracked-files file)) - (forward-line 1)) - - ;; Combined file tracking logic - (goto-char (point-min)) - (while (re-search-forward - "\\(Added\\|Removed\\|Moved\\) \\(\\./\\)?\\([^ ]+\\) \\(to\\|from\\) \\(the chat\\|editable\\|read-only\\) files?" - nil t) - (let* ((action (match-string 1)) - (file (match-string 3)) - (state (match-string 5))) - (cond - ;; Added files - ((string= action "Added") - (add-to-list 'tracked-files - (if (string= state "read-only") - (concat file " (read-only)") - file))) - - ;; Removed files - ((string= action "Removed") - (setq tracked-files (delete file tracked-files))) - - ;; Moved files - ((string= action "Moved") - (let* ((from-state (if (string= state "editable") "read-only" "editable")) - (old-file (if (string= from-state "read-only") - (concat file " (read-only)") - file)) - (new-file (if (string= state "read-only") - (concat file " (read-only)") - file))) - (setq tracked-files (delete old-file tracked-files)) - (add-to-list 'tracked-files new-file)))))) - - ;; <file> is already in the chat as an editable file - (goto-char (point-min)) - (while (search-forward " is already in the chat as an editable file" nil t) - (beginning-of-line) - (when-let ((file (and (looking-at "\\(\\./\\)?\\(.+\\) is already in the chat as an editable file") - (match-string-no-properties 2)))) - (add-to-list 'tracked-files file)) - (forward-line 1)) - - ;; Add file to the chat? - (goto-char (point-min)) - (while (search-forward "Add file to the chat?" nil t) - (save-excursion - (forward-line -1) - (let ((potential-file (string-trim (buffer-substring (line-beginning-position) (line-end-position))))) - (when (not (string-empty-p potential-file)) - (add-to-list 'tracked-files potential-file) - (aidermacs--prepare-for-code-edit)))) - (forward-line 1)) - - ;; Handle udiff format - (goto-char (point-min)) - (while (search-forward "--- " nil t) - (message "processing %s " tracked-files) - (let* ((line-end (line-end-position)) - (current-udiff-file (when (looking-at "\\(\\./\\)?\\(.+\\)") - (match-string-no-properties 2)))) - (when current-udiff-file - (forward-line 1) - (when (looking-at "\\+\\+\\+ \\(\\./\\)?\\(.+\\)") - (let ((plus-file (match-string-no-properties 2))) - (when (string= (file-name-nondirectory current-udiff-file) - (file-name-nondirectory plus-file)) - (add-to-list 'tracked-files current-udiff-file)))))))) + (let ((lines (split-string output "\n")) + (last-line "") + (in-udiff nil) + (current-udiff-file nil)) + (dolist (line lines) + (cond + ;; Applied edit to <filename> + ((string-match "Applied edit to \\(\\./\\)?\\(.+\\)" line) + (when-let ((file (match-string 2 line))) + (add-to-list 'aidermacs--tracked-files file))) + + ;; Added <filename> to the chat. + ((string-match "Added \\(\\./\\)?\\(.+\\) to the chat" line) + (when-let ((file (match-string 2 line))) + (add-to-list 'aidermacs--tracked-files file))) + + ;; Removed <filename> from the chat (with or without ./ prefix) + ((string-match "Removed \\(\\./\\)?\\(.+\\) from the chat" line) + (when-let ((file (match-string 2 line))) + (setq aidermacs--tracked-files (delete file aidermacs--tracked-files)))) + + ;; Added <filename> to read-only files. + ((string-match "Added \\(\\./\\)?\\(.+\\) to read-only files" line) + (when-let ((file (match-string 2 line))) + (add-to-list 'aidermacs--tracked-files (concat file " (read-only)")))) + + ;; Moved <file> from editable to read-only files in the chat + ((string-match "Moved \\(\\./\\)?\\(.+\\) from editable to read-only files in the chat" line) + (when-let ((file (match-string 2 line))) + (let ((editable-file (replace-regexp-in-string " (read-only)$" "" file))) + (setq aidermacs--tracked-files (delete editable-file aidermacs--tracked-files)) + (add-to-list 'aidermacs--tracked-files (concat file " (read-only)"))))) + + ;; Moved <file> from read-only to editable files in the chat + ((string-match "Moved \\(\\./\\)?\\(.+\\) from read-only to editable files in the chat" line) + (when-let ((file (match-string 2 line))) + (let ((read-only-file (concat file " (read-only)"))) + (setq aidermacs--tracked-files (delete read-only-file aidermacs--tracked-files)) + (add-to-list 'aidermacs--tracked-files file)))) + + ;; <file>\nAdd file to the chat? + ((string-match "Add file to the chat?" line) + (add-to-list 'aidermacs--tracked-files last-line) + (aidermacs--prepare-for-code-edit)) + + ;; <file> is already in the chat as an editable file + ((string-match "\\(\\./\\)?\\(.+\\) is already in the chat as an editable file" line) + (when-let ((file (match-string 2 line))) + (add-to-list 'aidermacs--tracked-files file))) + + ;; Handle udiff format + ;; Detect start of udiff with "--- filename" + ((string-match "^--- \\(\\./\\)?\\(.+\\)" line) + (setq in-udiff t + current-udiff-file (match-string 2 line))) + + ;; Confirm udiff file with "+++ filename" line + ((and in-udiff + current-udiff-file + (string-match "^\\+\\+\\+ \\(\\./\\)?\\(.+\\)" line)) + (let ((plus-file (match-string 2 line))) + ;; Only add if the filenames match (ignoring ./ prefix) + (when (string= (file-name-nondirectory current-udiff-file) + (file-name-nondirectory plus-file)) + (add-to-list 'aidermacs--tracked-files current-udiff-file) + (setq in-udiff nil + current-udiff-file nil))))) + + (setq last-line line)) ;; Verify all tracked files exist (let* ((project-root (aidermacs-project-root)) (is-remote (file-remote-p project-root)) (valid-files nil)) - (dolist (file tracked-files) + (dolist (file aidermacs--tracked-files) (let* ((is-readonly (string-match-p " (read-only)$" file)) (actual-file (if is-readonly (substring file 0 (- (length file) 12)) @@ -173,15 +171,7 @@ This is used to avoid having to run /ls repeatedly.") (full-path (expand-file-name actual-file project-root))) (when (or (file-exists-p full-path) is-remote) (push file valid-files)))) - (setq tracked-files valid-files)) - (setq aidermacs--tracked-files tracked-files)))) - -(defun aidermacs-reset-tracked-files () - "Reset the list of tracked files and force a refresh." - (interactive) - (setq aidermacs--tracked-files nil) - (aidermacs--get-files-in-session (lambda (files) - (message "Refreshed file list: %s" files)))) + (setq aidermacs--tracked-files valid-files))))) (defun aidermacs--store-output (output) "Store output string in the history with timestamp. @@ -210,6 +200,7 @@ If there's a callback function, call it with the output." PROGRAM is the aidermacs executable path. ARGS are command line arguments. BUFFER-NAME is the name for the aidermacs buffer." (message "Running %s with %s" program args) + (run-hooks 'aidermacs-before-run-backend-hook) (cond ((eq aidermacs-backend 'vterm) (aidermacs-run-vterm program args buffer-name)) diff --git a/aidermacs-models.el b/aidermacs-models.el index 0fdcdafa9e..60f4db8305 100644 --- a/aidermacs-models.el +++ b/aidermacs-models.el @@ -1,6 +1,6 @@ ;;; aidermacs-models.el --- Model selection for aidermacs -*- lexical-binding: t; -*- ;; Author: Mingde (Matthew) Zeng <matthew...@posteo.net> -;; Version: 1.0.0 +;; Version: 1.0 ;; Keywords: ai emacs llm aider ai-pair-programming tools ;; URL: https://github.com/MatthewZMD/aidermacs ;; SPDX-License-Identifier: Apache-2.0 @@ -32,6 +32,10 @@ (declare-function aidermacs-buffer-name "aidermacs" ()) (declare-function aidermacs-exit "aidermacs" ()) +(defgroup aidermacs-models nil + "Model selection for Aidermacs." + :group 'aidermacs) + (defcustom aidermacs-default-model "sonnet" "Default AI model to use for aidermacs sessions when not in Architect mode." :type 'string) diff --git a/aidermacs.el b/aidermacs.el index 238bd39478..cbcd75dffd 100644 --- a/aidermacs.el +++ b/aidermacs.el @@ -1,6 +1,6 @@ ;;; aidermacs.el --- AI pair programming with Aider -*- lexical-binding: t; -*- ;; Author: Mingde (Matthew) Zeng <matthew...@posteo.net> -;; Version: 1.0.0 +;; Version: 1.0 ;; Package-Requires: ((emacs "29.1")) ;; Keywords: ai emacs llm aider ai-pair-programming tools ;; URL: https://github.com/MatthewZMD/aidermacs @@ -35,10 +35,15 @@ (require 'ansi-color) (require 'cl-lib) (require 'tramp) +(require 'find-dired) (require 'aidermacs-backends) (require 'aidermacs-models) +(defgroup aidermacs nil + "AI pair programming with Aider." + :group 'aidermacs) + (defvar-local aidermacs--current-mode nil "Buffer-local variable to track the current aidermacs mode. Possible values: `code', `ask', `architect', `help'.") @@ -78,10 +83,15 @@ This is useful for working in monorepos where you want to limit aider's scope." When nil, disable auto-commits requiring manual git commits." :type 'boolean) +(defcustom aidermacs-auto-accept-architect nil + "When non-nil, automatically accept architect mode changes. +When nil, require explicit confirmation before applying changes." + :type 'boolean) + (defun aidermacs-project-root () "Get the project root using project.el, VC, or fallback to file directory. This function tries multiple methods to determine the project root." - (or (when-let ((proj (project-current))) + (or (when-let* ((proj (project-current))) (project-root proj)) (vc-git-root default-directory) (when buffer-file-name @@ -255,8 +265,10 @@ This function sets up the appropriate arguments and launches the process." "--editor-model" aidermacs-editor-model) (unless has-model-arg (list "--model" aidermacs-default-model))) - (when (not aidermacs-auto-commits) + (unless aidermacs-auto-commits '("--no-auto-commits")) + (unless aidermacs-auto-accept-architect + '("--no-auto-accept-architect")) (when aidermacs-subtree-only '("--subtree-only"))))) (final-args (append backend-args flat-extra-args))) @@ -376,7 +388,7 @@ Returns a list of files that have been modified according to the output." ;; Case 1: Find "Applied edit to" lines (while (search-forward "Applied edit to" nil t) (beginning-of-line) - (when-let ((file (and (looking-at ".*Applied edit to \\(\\./\\)?\\([^[:space:]]+\\)") + (when-let* ((file (and (looking-at ".*Applied edit to \\(\\./\\)?\\([^[:space:]]+\\)") (match-string-no-properties 2)))) (push file edited-files)) (forward-line 1)) @@ -514,7 +526,7 @@ If the current buffer is already the aidermacs buffer, do nothing." (buffer (pop-to-buffer buffer)) (t - (error "No aidermacs buffer exists."))))) + (error "No aidermacs buffer exists"))))) (defun aidermacs-clear-chat-history () "Send the command \"/clear\" to the aidermacs buffer." @@ -643,7 +655,8 @@ Sends the \"/ls\" command and displays the results in a Dired buffer." ;; The executed command is on the 2nd line; it can get ;; quite long, so we delete it to avoid cluttering the ;; buffer. - (goto-line 2) + (goto-char (point-min)) + (forward-line 1) ;; Move to the 2nd line (when (looking-at "^ *find " t) (let ((inhibit-read-only t)) (delete-region (line-beginning-position) (line-end-position))))) @@ -665,6 +678,7 @@ Sends the \"/ls\" command and displays the results in a Dired buffer." (defun aidermacs-drop-all-files () "Drop all files from the current chat session." (interactive) + (setq aidermacs--tracked-files nil) (aidermacs--send-command "/drop")) (defun aidermacs-batch-drop-dired-marked-files () @@ -719,7 +733,7 @@ Use highlighted region as context unless IGNORE-CONTEXT is set to non-nil." (let* ((region-text (when (and (use-region-p) (not ignore-context)) (buffer-substring-no-properties (region-beginning) (region-end)))) (context (when region-text - (format " regarding this section:\n```\n%s\n```\n" region-text))) + (format " in %s regarding this section:\n```\n%s\n```\n" (buffer-name) region-text))) (user-command (read-string (concat command " " prompt-prefix context (when guide (format " (%s)" guide)) ": ")))) (concat command (and (not (string-empty-p user-command)) @@ -728,7 +742,7 @@ Use highlighted region as context unless IGNORE-CONTEXT is set to non-nil." (defun aidermacs-direct-change () "Prompt the user for an input and send it to aidemracs prefixed with \"/code \"." (interactive) - (when-let ((command (aidermacs--form-prompt "/code" "Make this change" "will edit file"))) + (when-let* ((command (aidermacs--form-prompt "/code" "Make this change" "will edit file"))) (aidermacs--ensure-current-file-tracked) (aidermacs--send-command command))) @@ -738,7 +752,7 @@ If a region is active, include the region text in the question. If cursor is inside a function, include the function name as context. If called from the aidermacs buffer, use general question instead." (interactive) - (when-let ((command (aidermacs--form-prompt "/ask" "Propose a solution" "won't edit file"))) + (when-let* ((command (aidermacs--form-prompt "/ask" "Propose a solution" "won't edit file"))) (aidermacs--ensure-current-file-tracked) (aidermacs--send-command command))) @@ -747,26 +761,26 @@ If called from the aidermacs buffer, use general question instead." If region is active, inspect that region. If point is in a function, inspect that function." (interactive) - (when-let ((command (aidermacs--form-prompt "/architect" "Design a solution" "confirm before edit"))) + (when-let* ((command (aidermacs--form-prompt "/architect" "Design a solution" "confirm before edit"))) (aidermacs--ensure-current-file-tracked) (aidermacs--send-command command))) (defun aidermacs-question-general () "Prompt the user for a general question without code context." (interactive) - (when-let ((command (aidermacs--form-prompt "/ask" nil "empty for ask mode" t))) + (when-let* ((command (aidermacs--form-prompt "/ask" nil "empty for ask mode" t))) (aidermacs--send-command command))) (defun aidermacs-help () "Prompt the user for an input prefixed with \"/help \"." (interactive) - (when-let ((command (aidermacs--form-prompt "/help" nil "question how to use aider, empty for all commands" t))) + (when-let* ((command (aidermacs--form-prompt "/help" nil "question how to use aider, empty for all commands" t))) (aidermacs--send-command command))) (defun aidermacs-debug-exception () "Prompt the user for an input and send it to aidemracs prefixed with \"/debug \"." (interactive) - (when-let ((command (aidermacs--form-prompt "/ask" "Debug exception"))) + (when-let* ((command (aidermacs--form-prompt "/ask" "Debug exception"))) (aidermacs--send-command command))) (defun aidermacs-accept-change () @@ -939,7 +953,7 @@ Otherwise: - Otherwise generate unit tests for the entire file" (interactive) (if (not buffer-file-name) - (user-error "Current buffer is not visiting a file.") + (user-error "Current buffer is not visiting a file") (let ((function-name (which-function))) (cond ;; Test file case @@ -972,7 +986,7 @@ Otherwise: "Report the current test failure to aidermacs and ask it to fix the code. This function assumes the cursor is on or inside a test function." (interactive) - (if-let ((test-function-name (which-function))) + (if-let* ((test-function-name (which-function))) (let* ((initial-input (format "The test '%s' is failing. Please analyze and fix the code to make the test pass. Don't break any other test" test-function-name)) (command (aidermacs--form-prompt "/architect" initial-input))) @@ -1002,7 +1016,7 @@ snippets, or other content to the session." (message "Created and added scratchpad to session: %s" filename))) (defun aidermacs-add-file-to-session (&optional file) - "Interactively add a file to an existing aidermacs session using /read. + "Interactively add a FILE to an existing aidermacs session using /read. This allows you to add the file's content to a specific session." (interactive (let* ((initial (when buffer-file-name @@ -1046,7 +1060,7 @@ Otherwise implement TODOs for the entire current file." (message "Current buffer is not visiting a file.") (let* ((current-line (string-trim (thing-at-point 'line t))) (is-comment (aidermacs--is-comment-line current-line))) - (when-let ((command (aidermacs--form-prompt + (when-let* ((command (aidermacs--form-prompt "/architect" (concat "Please implement the TODO items." (and is-comment @@ -1119,10 +1133,10 @@ sample prompt." ;;;###autoload (defvar aidermacs-minor-mode-map (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-n") 'aidermacs-send-line-or-region) - (define-key map (kbd "C-<return>") 'aidermacs-send-line-or-region) - (define-key map (kbd "C-c C-c") 'aidermacs-send-block-or-region) - (define-key map (kbd "C-c C-z") 'aidermacs-switch-to-buffer) + (define-key map (kbd "C-c C-n") #'aidermacs-send-line-or-region) + (define-key map (kbd "C-<return>") #'aidermacs-send-line-or-region) + (define-key map (kbd "C-c C-c") #'aidermacs-send-block-or-region) + (define-key map (kbd "C-c C-z") #'aidermacs-switch-to-buffer) map) "Keymap for `aidermacs-minor-mode'.")