branch: elpa/aidermacs commit 4ed1f8ddb652de9389683f8038efad5a90d6b4b0 Merge: b4a771c777 389d69fddb Author: Matthew Zeng <matthew...@posteo.net> Commit: GitHub <nore...@github.com>
Merge pull request #51 from milanglacier/refactor/vterm-aider-mode Refactor/vterm aider mode --- aidermacs-backend-comint.el | 26 +++++++++----- aidermacs-backend-vterm.el | 85 +++++++++++++++++++++++---------------------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/aidermacs-backend-comint.el b/aidermacs-backend-comint.el index 22609d2597..403036f8d6 100644 --- a/aidermacs-backend-comint.el +++ b/aidermacs-backend-comint.el @@ -297,11 +297,7 @@ BUFFER-NAME is the name for the aidermacs buffer." (add-hook 'kill-buffer-hook #'aidermacs--comint-cleanup-hook nil t) (add-hook 'comint-output-filter-functions #'aidermacs-fontify-blocks 100 t) (add-hook 'comint-output-filter-functions #'aidermacs--comint-output-filter) - (advice-add 'comint-interrupt-subjob :around #'aidermacs--cleanup-temp-files-on-interrupt-comint) - (let ((local-map (make-sparse-keymap))) - (set-keymap-parent local-map comint-mode-map) - (define-key local-map (kbd aidermacs-comint-multiline-newline-key) #'comint-accumulate) - (use-local-map local-map)) + (aidermacs-comint-mode 1) (font-lock-add-keywords nil aidermacs-font-lock-keywords t))))) (defun aidermacs--send-command-comint (buffer command) @@ -338,13 +334,25 @@ The output is collected and passed to the current callback." (aidermacs--store-output (with-current-buffer output-buffer (buffer-string)))))) -(defun aidermacs--cleanup-temp-files-on-interrupt-comint (orig-fun &rest args) - "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) +(defun aidermacs-comint-interrupt-subjob () + "Run `aidermacs--cleanup-temp-buffers' after interrupting a comint subjob." + (interactive) + (comint-interrupt-subjob) (when (aidermacs--is-aidermacs-buffer-p) (aidermacs--cleanup-temp-buffers))) +(defvar aidermacs-comint-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd aidermacs-comint-multiline-newline-key) #'comint-accumulate) + (define-key map (kbd "C-c C-c") #'aidermacs-comint-interrupt-subjob) + map) + "Keymap used when `aidermacs-comint-mode' is enabled.") + +(define-minor-mode aidermacs-comint-mode + "Minor mode for vterm backend buffer used by aidermacs." + :init-value nil + :keymap aidermacs-comint-mode-map) + (provide 'aidermacs-backend-comint) ;;; aidermacs-backend-comint.el ends here diff --git a/aidermacs-backend-vterm.el b/aidermacs-backend-vterm.el index 79ca291a7e..56c784675f 100644 --- a/aidermacs-backend-vterm.el +++ b/aidermacs-backend-vterm.el @@ -45,6 +45,9 @@ (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 evil-define-minor-mode-key "evil-core") + (defvar-local aidermacs--vterm-active-timer nil "Store the active timer for vterm output processing.") @@ -85,10 +88,8 @@ If the finish sequence is detected, store the output via (should-check (> prompt-point last-check)) ;; Simplified pattern that just looks for a shell prompt (expected aidermacs-prompt-regexp)) - ;; Update the last check point (setq aidermacs--vterm-last-check-point prompt-point) - (when should-check (let* ((seq-start (or (save-excursion (goto-char prompt-point) @@ -100,13 +101,10 @@ If the finish sequence is detected, store the output via (prompt-line-end (min (+ seq-start 200) (point-max))) (prompt-line (buffer-substring-no-properties seq-start prompt-line-end)) (output (buffer-substring-no-properties start-point seq-start))) - ;; Parse output for files (aidermacs--parse-output-for-files output) - ;; If we found a shell prompt indicating output finished (when (string-match-p expected prompt-line) - (setq-local aidermacs--vterm-processing-command nil) (aidermacs--store-output (string-trim output)) (let ((edited-files (aidermacs--detect-edited-files))) ;; Check if any files were edited and show ediff if needed @@ -118,43 +116,30 @@ If the finish sequence is detected, store the output via (set-process-filter proc orig-filter) (aidermacs--maybe-cancel-active-timer (process-buffer proc)))))))))) -(defvar-local aidermacs--vterm-processing-command nil - "Flag to indicate if we're currently processing a command.") - -(defun aidermacs--vterm-output-advice (orig-fun &rest args) +(defun aidermacs--vterm-capture-output () "Capture vterm output until the finish sequence appears. ORIG-FUN is the original function being advised. ARGS are its arguments. This sets a temporary process filter that checks for the finish sequence after each output chunk, reducing the need for timers." - (if (and (aidermacs--is-aidermacs-buffer-p) - (not (string-empty-p aidermacs--last-command))) + (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) - (when (and args (car args) (stringp (car args))) - (setq aidermacs--last-command (car args))) - ;; Set flag that we're processing a command - (setq aidermacs--vterm-processing-command t) ;; 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 () - ; Check if we're still in a valid state - (aidermacs--vterm-check-finish-sequence-repeated proc orig-filter start-point)))) - (apply orig-fun args))) - (apply orig-fun args))) + (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. @@ -181,14 +166,7 @@ BUFFER-NAME is the name for the vterm buffer." (setq-local vterm-max-scrollback 1000 aidermacs--vterm-active-timer nil aidermacs--vterm-last-check-point nil) - (advice-add 'vterm-send-return :around #'aidermacs--vterm-output-advice) - (advice-add 'vterm-send-return :before #'aidermacs--vterm-capture-keyboard-input) - (advice-add 'vterm--self-insert :after #'aidermacs--cleanup-temp-files-on-interrupt-vterm) - ;; Set up multi-line keybinding - (let ((map (make-sparse-keymap))) - (set-keymap-parent map (current-local-map)) - (define-key map (kbd aidermacs-vterm-multiline-newline-key) #'aidermacs-vterm-insert-newline) - (use-local-map map)) + (aidermacs-vterm-mode 1) ;; Add cleanup hook (add-hook 'kill-buffer-hook #'aidermacs--vterm-cleanup nil t)))) buffer-name) @@ -201,13 +179,24 @@ BUFFER is the target buffer to send to. COMMAND is the text to send." (aidermacs--maybe-cancel-active-timer) ;; Only process if we have a non-empty command (when (and command (not (string-empty-p (string-trim command)))) - ;; Set processing flag to true before sending command - (setq-local aidermacs--vterm-processing-command t) - ;; Store the command for tracking + ;; Store the command and reset output (setq-local aidermacs--last-command command) ;; Send the command (vterm-send-string command) - (vterm-send-return)))) + (aidermacs-vterm-send-return)))) + +(defun aidermacs-vterm-send-return () + "Send return to the aidermacs vterm buffer, and process the output." + (interactive) + (aidermacs--vterm-capture-keyboard-input) + (aidermacs--vterm-capture-output) + (vterm-send-return)) + +(defun aidermacs-vterm-send-C-c () + "Send C-c to the aidermacs vterm buffer, and clenaup." + (interactive) + (vterm-send-C-c) + (aidermacs--cleanup-temp-files-on-interrupt-vterm)) (defun aidermacs-vterm-insert-newline () "Insert a newline in vterm without sending the command." @@ -234,20 +223,32 @@ BUFFER is the target buffer to send to. COMMAND is the text to send." (defun aidermacs--vterm-cleanup () "Clean up vterm resources when buffer is killed." (aidermacs--maybe-cancel-active-timer) - (setq-local aidermacs--vterm-last-check-point nil) - (setq-local aidermacs--vterm-processing-command nil) - (advice-remove 'vterm-send-return #'aidermacs--vterm-capture-keyboard-input)) + (setq-local aidermacs--vterm-last-check-point nil)) -(defun aidermacs--cleanup-temp-files-on-interrupt-vterm (&rest _args) +(defun aidermacs--cleanup-temp-files-on-interrupt-vterm () "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")) - ;; Reset processing flag when user interrupts - (setq-local aidermacs--vterm-processing-command nil) + (when (aidermacs--is-aidermacs-buffer-p) ;; Cancel any active timer (aidermacs--maybe-cancel-active-timer) (aidermacs--cleanup-temp-buffers))) +(defvar aidermacs-vterm-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd aidermacs-vterm-multiline-newline-key) #'aidermacs-vterm-insert-newline) + (define-key map (kbd "RET") #'aidermacs-vterm-send-return) + (define-key map (kbd "<return>") #'aidermacs-vterm-send-return) + (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))) + map) + "Keymap used when `aidermacs-vterm-mode' is enabled.") + +(define-minor-mode aidermacs-vterm-mode + "Minor mode for vterm backend buffer used by aidermacs." + :init-value nil + :keymap aidermacs-vterm-mode-map) + (provide 'aidermacs-backend-vterm) ;;; aidermacs-backend-vterm.el ends here