branch: elpa/aidermacs
commit 24f04aba1a08351ca52e955868ef673c31975679
Merge: da760ca70c 22f59e2b8a
Author: Matthew Zeng <matthew...@posteo.net>
Commit: GitHub <nore...@github.com>

    Merge pull request #56 from rschmukler/rschmukler/tramp
    
    Add Tramp Support
---
 README.md             | 20 +++++++++++++
 aidermacs-backends.el |  5 ++--
 aidermacs.el          | 81 +++++++++++++++++++++++++++++++--------------------
 3 files changed, 73 insertions(+), 33 deletions(-)

diff --git a/README.md b/README.md
index 9cc1625618..dff10bbce2 100644
--- a/README.md
+++ b/README.md
@@ -141,6 +141,25 @@ You can customize keybindings for multiline input, this 
key allows you to enter
 (setq aidermacs-vterm-multiline-newline-key "S-<return>")
 ```
 
+### Remote File Support with Tramp
+
+Aidermacs fully supports working with remote files through Emacs' Tramp mode. 
This allows you to use Aidermacs on files hosted on remote servers via SSH, 
Docker, and other protocols supported by Tramp.
+
+When working with remote files:
+- File paths are automatically localized for the remote system
+- All Aidermacs features work seamlessly across local and remote files
+- Edits are applied directly to the remote files
+- Diffs and change reviews work as expected
+
+Example usage:
+```emacs-lisp
+;; Open a remote file via SSH
+(find-file "/ssh:user@remotehost:/path/to/file.py")
+
+;; Start Aidermacs session - it will automatically detect the remote context
+M-x aidermacs-transient-menu
+```
+
 ### Diff and Change Review
 
 Control whether to show diffs for AI-generated changes with 
`aidermacs-show-diff-after-change`:
@@ -379,6 +398,7 @@ With `Aidermacs`, you get:
    - Interactively select files to add with `M-x 
aidermacs-add-files-interactively`
    - Add content from any file to a specific session with `M-x 
aidermacs-add-file-to-session`
    - Create a temporary file for adding code snippets or notes to the Aider 
session with `M-x aidermacs-create-session-scratchpad`
+   - Full support for remote files via Tramp (SSH, Docker, etc.)
    - and more
 
 7. Greater Configurability
diff --git a/aidermacs-backends.el b/aidermacs-backends.el
index 2b127d3545..8e4f7e4880 100644
--- a/aidermacs-backends.el
+++ b/aidermacs-backends.el
@@ -91,7 +91,8 @@ This is used to avoid having to run /ls repeatedly.")
 (defun aidermacs--verify-tracked-files ()
   "Verify files in `aidermacs--tracked-files` exist.
 Remove any files that don't exist."
-  (let ((project-root (aidermacs-project-root))
+  (let* ((project-root (aidermacs-project-root))
+         (is-remote (file-remote-p project-root))
         (valid-files nil))
     (dolist (file aidermacs--tracked-files)
       (let* ((is-readonly (string-match-p " (read-only)$" file))
@@ -99,7 +100,7 @@ Remove any files that don't exist."
                               (substring file 0 (- (length file) 12))
                             file))
              (full-path (expand-file-name actual-file project-root)))
-        (when (file-exists-p full-path)
+        (when (or (file-exists-p full-path) is-remote)
           (push file valid-files))))
     (setq aidermacs--tracked-files valid-files)))
 
diff --git a/aidermacs.el b/aidermacs.el
index 5c9243991a..e9bc0be1a2 100644
--- a/aidermacs.el
+++ b/aidermacs.el
@@ -34,6 +34,7 @@
 (require 'which-func)
 (require 'ansi-color)
 (require 'cl-lib)
+(require 'tramp)
 
 (require 'aidermacs-backends)
 (require 'aidermacs-models)
@@ -575,28 +576,18 @@ 
https://aidermacs.chat/docs/usage/commands.html#entering-multi-line-chat-message
     str))
 
 ;;;###autoload
-(defun aidermacs-act-on-current-file (command-prefix)
-  "Send a command with the current file path to the aidermacs buffer.
-COMMAND-PREFIX is the command to prepend to the file path.
-The full command will be \"COMMAND-PREFIX <current buffer file full path>\"."
-  ;; Ensure the current buffer is associated with a file
+(defun aidermacs-drop-current-file ()
+  "Drop the current file from aidermacs session."
+  (interactive)
   (if (not buffer-file-name)
       (message "Current buffer is not associated with a file.")
-    (let* ((file-path (buffer-file-name))
-           ;; Use buffer-file-name directly
+    (let* ((file-path (aidermacs--localize-tramp-path buffer-file-name))
            (formatted-path (if (string-match-p " " file-path)
                                (format "\"%s\"" file-path)
                              file-path))
-           (command (format "%s %s" command-prefix formatted-path)))
-      ;; Use the shared helper function to send the command
+           (command (format "/drop %s" formatted-path)))
       (aidermacs--send-command command))))
 
-;;;###autoload
-(defun aidermacs-drop-current-file ()
-  "Drop the current file from aidermacs session."
-  (interactive)
-  (aidermacs-act-on-current-file "/drop"))
-
 ;;;###autoload
 (defun aidermacs-general-command ()
   "Prompt the user to input COMMAND and send it to the aidemracs."
@@ -624,8 +615,9 @@ Returns a deduplicated list of such file names."
     (with-temp-buffer
       (insert output)
       (goto-char (point-min))
-      (let ((files '())
-            (base (aidermacs-project-root)))
+      (let* ((files '())
+             (base (aidermacs-project-root))
+             (is-remote (file-remote-p base)))
         ;; Parse read-only files section
         (when (search-forward "Read-only files:" nil t)
           (forward-line 1)
@@ -633,11 +625,15 @@ Returns a deduplicated list of such file names."
                       (string-match-p "^[[:space:]]" (thing-at-point 'line t)))
             (let* ((line (string-trim (thing-at-point 'line t)))
                    (file (car (split-string line))))
-              (when (and file (file-exists-p (expand-file-name file base)))
-                ;; Store relative path with read-only marker
-                (push (concat (file-relative-name (expand-file-name file base) 
base)
-                             " (read-only)")
-                      files)))
+              ;; For remote files, we don't try to verify existence or convert 
paths
+              (when file
+                (if is-remote
+                    (push (concat file " (read-only)") files)
+                  ;; For local files, verify existence and convert to relative 
path
+                  (when (file-exists-p (expand-file-name file base))
+                    (push (concat (file-relative-name (expand-file-name file 
base) base)
+                                  " (read-only)")
+                          files)))))
             (forward-line 1)))
 
         ;; Parse files in chat section
@@ -647,9 +643,13 @@ Returns a deduplicated list of such file names."
                       (string-match-p "^[[:space:]]" (thing-at-point 'line t)))
             (let* ((line (string-trim (thing-at-point 'line t)))
                    (file (car (split-string line))))
-              (when (and file (file-exists-p (expand-file-name file base)))
-                ;; Store relative path
-                (push (file-relative-name (expand-file-name file base) base) 
files)))
+              ;; For remote files, we don't try to verify existence or convert 
paths
+              (when file
+                (if is-remote
+                    (push file files)
+                  ;; For local files, verify existence and convert to relative 
path
+                  (when (file-exists-p (expand-file-name file base))
+                    (push (file-relative-name (expand-file-name file base) 
base) files)))))
             (forward-line 1)))
 
         ;; Remove duplicates and return
@@ -682,7 +682,8 @@ Sends the \"/ls\" command and returns the list of files via 
callback."
    (lambda (files)
      (if-let* ((file (completing-read "Select file to drop: " files nil t))
                (clean-file (replace-regexp-in-string " (read-only)$" "" file)))
-         (aidermacs--send-command (format "/drop ./%s" clean-file))
+         (let ((command (aidermacs--prepare-file-paths-for-command "/drop" 
(list (concat "./" clean-file)))))
+           (aidermacs--send-command command))
        (message "No files available to drop")))))
 
 
@@ -841,17 +842,33 @@ PREFIX is the text to prepend.  COMMAND is the text to 
send."
   (aidermacs-add-current-file)
   (aidermacs--send-command (concat prefix command)))
 
+(defun aidermacs--localize-tramp-path (file)
+  "If FILE is a TRAMP path, extract the local part of the path.
+Otherwise, return FILE unchanged."
+  (if (and (fboundp 'tramp-tramp-file-p) (tramp-tramp-file-p file))
+      (let ((local-name (tramp-file-name-localname (tramp-dissect-file-name 
file))))
+        local-name)
+    file))
+
+(defun aidermacs--prepare-file-paths-for-command (command files)
+  "Prepare FILES for use with COMMAND in aider.
+Handles TRAMP paths by extracting local parts and formats the command string."
+  (let ((localized-files (mapcar #'aidermacs--localize-tramp-path (delq nil 
files))))
+    (if localized-files
+        (format "%s %s" command
+                (mapconcat #'identity localized-files " "))
+      (format "%s" command))))
+
 (defun aidermacs--add-files-helper (files read-only &optional message)
   "Helper function to add files with read-only flag.
 FILES is a list of file paths to add.  READ-ONLY determines if files are added
 as read-only.  Optional MESSAGE can override the default success message."
   (let* ((cmd (if read-only "/read-only" "/add"))
+         (command (aidermacs--prepare-file-paths-for-command cmd files))
          (files (delq nil files)))
     (if files
         (progn
-          (aidermacs--send-command
-           (format "%s %s" cmd
-                   (mapconcat #'identity files " ")))
+          (aidermacs--send-command command)
           (message (or message
                        (format "Added %d files as %s"
                                (length files)
@@ -1010,7 +1027,8 @@ snippets, or other content to the session."
       (insert ";; Add your code snippets, functions, or other content here\n")
       (insert ";; Just edit and save - changes will be available to aider\n\n")
       (write-file filename))
-    (aidermacs--send-command (format "/read %s" filename))
+    (let ((command (aidermacs--prepare-file-paths-for-command "/read" (list 
filename))))
+      (aidermacs--send-command command))
     (find-file-other-window filename)
     (message "Created and added scratchpad to session: %s" filename)))
 
@@ -1027,7 +1045,8 @@ specific session."
                                 nil nil t initial))))
     (if (not (file-exists-p file))
         (message "File does not exist: %s" file)
-      (aidermacs--send-command (format "/read %s" file) nil t))))
+      (let ((command (aidermacs--prepare-file-paths-for-command "/read" (list 
file))))
+        (aidermacs--send-command command nil t)))))
 
 (defun aidermacs--is-comment-line (line)
   "Check if LINE is a comment line based on current buffer's comment syntax.

Reply via email to