[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/gptel 48d9515c26 1/2: gptel-rewrite: Add a default rewrite
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/gptel 48d9515c26 1/2: gptel-rewrite: Add a default rewrite action |
Date: |
Mon, 25 Nov 2024 19:00:18 -0500 (EST) |
branch: elpa/gptel
commit 48d9515c269962ff2095a398a1dcfbb51720cef9
Author: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
gptel-rewrite: Add a default rewrite action
* gptel-rewrite.el (gptel--rewrite-prepare-buffer,
gptel-rewrite-default-action, gptel--rewrite-apply,
gptel--rewrite-diff, gptel--rewrite-ediff, gptel--rewrite-merge,
gptel--suffix-rewrite): Add a new user option,
`gptel-rewrite-default-action' to automatically run one of the
rewrite actions (diff, ediff, merge or replace) when receiving a
rewritten text region from an LLM. Handle the case where the
original buffer is killed before the response arrives.
---
gptel-rewrite.el | 193 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 115 insertions(+), 78 deletions(-)
diff --git a/gptel-rewrite.el b/gptel-rewrite.el
index a018f11518..31e8dc4e0f 100644
--- a/gptel-rewrite.el
+++ b/gptel-rewrite.el
@@ -46,6 +46,26 @@ for a particular major-mode."
:group 'gptel
:type 'hook)
+(defcustom gptel-rewrite-default-action nil
+ "Action to take when rewriting a text region using gptel.
+
+When the LLM response with the rewritten text is received, you can
+- merge it with the current region, possibly creating a merge conflict,
+- diff or ediff against the original region,
+- or accept it in place, overwriting the original region.
+
+If this option is nil (the default), gptel waits for an explicit
+command. Set it to the symbol merge, diff, ediff or replace to
+automatically do one of these things instead."
+ :group 'gptel
+ :type '(choice
+ (const :tag "Wait" nil)
+ (const :tag "Merge with current region" gptel--rewrite-merge)
+ (const :tag "Diff against current region" gptel--rewrite-diff)
+ (const :tag "Ediff against current region" gptel--rewrite-ediff)
+ (const :tag "Replace current region" gptel--rewrite-apply)
+ (function :tag "Custom action")))
+
(defface gptel-rewrite-highlight-face
'((((class color) (min-colors 88) (background dark))
:background "#041714" :extend t)
@@ -150,7 +170,7 @@ This is used for (e)diff purposes.
RESPONSE is the LLM response. OVS are the overlays specifying
the changed regions. BUF is the (current) buffer."
- (setq buf (or buf (current-buffer)))
+ (setq buf (or buf (overlay-buffer (or (car-safe ovs) ovs))))
(with-current-buffer buf
(let ((pmin (point-min))
(pmax (point-max))
@@ -171,7 +191,7 @@ the changed regions. BUF is the (current) buffer."
;; (delay-mode-hooks (funcall mode))
;; Apply the changes to the new buffer
(save-excursion
- (gptel--rewrite-apply ovs)))
+ (gptel--rewrite-apply ovs newbuf)))
newbuf)))
;; * Refactor action functions
@@ -186,64 +206,78 @@ the changed regions. BUF is the (current) buffer."
(remove-hook 'eldoc-documentation-functions 'gptel--rewrite-key-help
'local))
(message "Cleared pending LLM response(s)."))
-(defun gptel--rewrite-apply (&optional ovs)
- "Apply pending LLM responses in OVS or at point."
+(defun gptel--rewrite-apply (&optional ovs buf)
+ "Apply pending LLM responses in OVS or at point.
+
+BUF is the buffer to modify, defaults to the overlay buffer."
(interactive (list (gptel--rewrite-overlay-at)))
- (cl-loop for ov in (ensure-list ovs)
- for ov-beg = (overlay-start ov)
- for ov-end = (overlay-end ov)
- for response = (overlay-get ov 'gptel-rewrite)
- do (overlay-put ov 'before-string nil)
- (goto-char ov-beg)
- (delete-region ov-beg ov-end)
- (insert response))
- (message "Replaced region(s) with LLM output."))
+ (when-let* ((ov-buf (overlay-buffer (or (car-safe ovs) ovs)))
+ (buf (or buf ov-buf))
+ ((buffer-live-p buf)))
+ (with-current-buffer ov-buf
+ (cl-loop for ov in (ensure-list ovs)
+ for ov-beg = (overlay-start ov)
+ for ov-end = (overlay-end ov)
+ for response = (overlay-get ov 'gptel-rewrite)
+ do (overlay-put ov 'before-string nil)
+ (with-current-buffer buf
+ (goto-char ov-beg)
+ (delete-region ov-beg ov-end)
+ (insert response))))
+ (message "Replaced region(s) with LLM output in buffer: %s."
+ (buffer-name ov-buf))))
(defun gptel--rewrite-diff (&optional ovs switches)
"Diff pending LLM responses in OVS or at point."
(interactive (list (gptel--rewrite-overlay-at)))
- (let* ((buf (current-buffer))
- (newbuf (gptel--rewrite-prepare-buffer ovs))
- (diff-buf (diff-no-select
- (if-let ((buf-file (buffer-file-name buf)))
- (expand-file-name buf-file) buf)
- newbuf switches)))
- (with-current-buffer diff-buf
- (setq-local diff-jump-to-old-file t))
- (display-buffer diff-buf)))
+ (when-let* ((ov-buf (overlay-buffer (or (car-safe ovs) ovs)))
+ ((buffer-live-p ov-buf)))
+ (let* ((newbuf (gptel--rewrite-prepare-buffer ovs))
+ (diff-buf (diff-no-select
+ (if-let ((buf-file (buffer-file-name ov-buf)))
+ (expand-file-name buf-file) ov-buf)
+ newbuf switches)))
+ (with-current-buffer diff-buf
+ (setq-local diff-jump-to-old-file t))
+ (display-buffer diff-buf))))
(defun gptel--rewrite-ediff (&optional ovs)
"Ediff pending LLM responses in OVS or at point."
(interactive (list (gptel--rewrite-overlay-at)))
- (letrec ((newbuf (gptel--rewrite-prepare-buffer ovs))
- (cwc (current-window-configuration))
- (gptel--ediff-restore
- (lambda ()
- (when (window-configuration-p cwc)
- (set-window-configuration cwc))
- (remove-hook 'ediff-quit-hook gptel--ediff-restore))))
- (add-hook 'ediff-quit-hook gptel--ediff-restore)
- (ediff-buffers (current-buffer) newbuf)))
+ (when-let* ((ov-buf (overlay-buffer (or (car-safe ovs) ovs)))
+ ((buffer-live-p ov-buf)))
+ (letrec ((newbuf (gptel--rewrite-prepare-buffer ovs))
+ (cwc (current-window-configuration))
+ (gptel--ediff-restore
+ (lambda ()
+ (when (window-configuration-p cwc)
+ (set-window-configuration cwc))
+ (remove-hook 'ediff-quit-hook gptel--ediff-restore))))
+ (add-hook 'ediff-quit-hook gptel--ediff-restore)
+ (ediff-buffers ov-buf newbuf))))
(defun gptel--rewrite-merge (&optional ovs)
"Insert pending LLM responses in OVS as merge conflicts."
(interactive (list (gptel--rewrite-overlay-at)))
- (let ((changed))
- (dolist (ov (ensure-list ovs))
- (save-excursion
- (when-let (new-str (overlay-get ov 'gptel-rewrite))
- ;; Insert merge
- (goto-char (overlay-start ov))
- (unless (bolp) (insert "\n"))
- (insert-before-markers "<<<<<<< original\n")
- (goto-char (overlay-end ov))
- (unless (bolp) (insert "\n"))
- (insert
- "=======\n" new-str
- "\n>>>>>>> " (gptel-backend-name gptel-backend) "\n")
- (setq changed t))))
- (when changed (smerge-mode 1)))
- (gptel--rewrite-clear ovs))
+ (when-let* ((ov-buf (overlay-buffer (or (car-safe ovs) ovs)))
+ ((buffer-live-p ov-buf)))
+ (with-current-buffer ov-buf
+ (let ((changed))
+ (dolist (ov (ensure-list ovs))
+ (save-excursion
+ (when-let (new-str (overlay-get ov 'gptel-rewrite))
+ ;; Insert merge
+ (goto-char (overlay-start ov))
+ (unless (bolp) (insert "\n"))
+ (insert-before-markers "<<<<<<< original\n")
+ (goto-char (overlay-end ov))
+ (unless (bolp) (insert "\n"))
+ (insert
+ "=======\n" new-str
+ "\n>>>>>>> " (gptel-backend-name gptel-backend) "\n")
+ (setq changed t))))
+ (when changed (smerge-mode 1)))
+ (gptel--rewrite-clear ovs))))
;; * Transient Prefix for rewriting/refactoring
@@ -363,42 +397,45 @@ the changed regions. BUF is the (current) buffer."
(let ((buf (plist-get info :buffer))
(ov (plist-get info :context))
(action-str) (hint-str))
- (with-current-buffer buf
- (if (derived-mode-p 'prog-mode)
- (progn
- (setq action-str "refactor")
- (when (string-match-p "^```" response)
- (setq response (replace-regexp-in-string "^```.*$" ""
response))))
- (setq action-str "rewrite"))
- (setq hint-str (concat "[" (gptel-backend-name gptel-backend)
- ":" (gptel--model-name gptel-model) "] "
- (upcase action-str) " READY ✓\n"))
- (add-hook 'eldoc-documentation-functions
#'gptel--rewrite-key-help nil 'local)
- (overlay-put ov 'gptel-rewrite response)
- (overlay-put ov 'face 'gptel-rewrite-highlight-face)
- (overlay-put ov 'keymap gptel-rewrite-actions-map)
- (overlay-put ov 'before-string
- (concat (propertize
- " " 'display `(space :align-to (- right
,(1+ (length hint-str)))))
- (propertize hint-str 'face 'success)))
- (overlay-put
- ov 'help-echo
- (format "%s rewrite available:
+ (when (buffer-live-p buf)
+ (with-current-buffer buf
+ (if (derived-mode-p 'prog-mode)
+ (progn
+ (setq action-str "refactor")
+ (when (string-match-p "^```" response)
+ (setq response (replace-regexp-in-string "^```.*$" ""
response))))
+ (setq action-str "rewrite"))
+ (setq hint-str (concat "[" (gptel-backend-name gptel-backend)
+ ":" (gptel--model-name gptel-model) "] "
+ (upcase action-str) " READY ✓\n"))
+ (add-hook 'eldoc-documentation-functions
#'gptel--rewrite-key-help nil 'local)
+ (overlay-put ov 'gptel-rewrite response)
+ (overlay-put ov 'face 'gptel-rewrite-highlight-face)
+ (overlay-put ov 'keymap gptel-rewrite-actions-map)
+ (overlay-put ov 'before-string
+ (concat (propertize
+ " " 'display `(space :align-to (- right
,(1+ (length hint-str)))))
+ (propertize hint-str 'face 'success)))
+ (overlay-put
+ ov 'help-echo
+ (format "%s rewrite available:
- accept \\[gptel--rewrite-apply],
- clear \\[gptel--rewrite-clear],
- merge \\[gptel--accept-merge],
- diff \\[gptel--rewrite-diff],
- ediff \\[gptel--rewrite-ediff]"
- (propertize (concat (gptel-backend-name gptel-backend)
- ":" (gptel--model-name
gptel-model)))))
- (push ov gptel--rewrite-overlays))
- ;; Message user
- (message
- (concat
- "LLM %s output"
- (unless (eq (current-buffer) buf) (format " in buffer %s " buf))
- (substitute-command-keys " ready, \\[gptel-menu] to continue."))
- action-str)))))))
+ (propertize (concat (gptel-backend-name gptel-backend)
+ ":" (gptel--model-name
gptel-model)))))
+ (push ov gptel--rewrite-overlays))
+ (if (functionp gptel-rewrite-default-action)
+ (funcall gptel-rewrite-default-action ov)
+ ;; Message user
+ (message
+ (concat
+ "LLM %s output"
+ (unless (eq (current-buffer) buf) (format " in buffer %s "
buf))
+ (substitute-command-keys " ready, \\[gptel-menu] to
continue."))
+ action-str)))))))))
(transient-define-suffix gptel--suffix-rewrite-diff (&optional switches)
"Diff LLM output against buffer."