gptel-transient: Add refactor transient
* gptel-transient.el: Add `gptel-rewrite-menu' (accessible via the main `gptel-menu') to rewrite/refactor the selected region, including the choice to Ediff it linewise/wordwise afterwards.
This commit is contained in:
parent
c6abda6f0f
commit
937c754e57
1 changed files with 108 additions and 0 deletions
|
@ -69,6 +69,18 @@ Or is it the other way around?"
|
||||||
(gptel--suffix-send-existing)
|
(gptel--suffix-send-existing)
|
||||||
(gptel--suffix-send-new)
|
(gptel--suffix-send-new)
|
||||||
("RET" "Send prompt" gptel-send)]])
|
("RET" "Send prompt" gptel-send)]])
|
||||||
|
[:description gptel--refactor-or-rewrite
|
||||||
|
:if use-region-p
|
||||||
|
("r"
|
||||||
|
;;FIXME: Transient complains if I use `gptel--refactor-or-rewrite' here. It
|
||||||
|
;;reads this function as a suffix instead of a function that returns the
|
||||||
|
;;description.
|
||||||
|
(lambda () (if (derived-mode-p 'prog-mode)
|
||||||
|
"Refactor" "Rewrite"))
|
||||||
|
gptel-rewrite-menu)]
|
||||||
|
["Send" (gptel--suffix-send)]])
|
||||||
|
|
||||||
|
;; ** Prefix for setting the system prompt.
|
||||||
|
|
||||||
(transient-define-prefix gptel-system-prompt ()
|
(transient-define-prefix gptel-system-prompt ()
|
||||||
"Change the system prompt to send ChatGPT.
|
"Change the system prompt to send ChatGPT.
|
||||||
|
@ -108,6 +120,27 @@ Customize `gptel-directives' for task-specific prompts."
|
||||||
(alist-get 'chat gptel-directives)))
|
(alist-get 'chat gptel-directives)))
|
||||||
:transient t)])
|
:transient t)])
|
||||||
|
|
||||||
|
(transient-define-prefix gptel-rewrite-menu ()
|
||||||
|
"Rewrite or refactor text region using ChatGPT."
|
||||||
|
[:description
|
||||||
|
(lambda ()
|
||||||
|
(format "Directive: %s"
|
||||||
|
(truncate-string-to-width
|
||||||
|
(or gptel--rewrite-message (gptel--rewrite-message))
|
||||||
|
(max (- (window-width) 14) 20) nil nil t)))
|
||||||
|
(gptel--infix-rewrite-prompt)]
|
||||||
|
[[:description "Diff Options"
|
||||||
|
("-w" "Wordwise diff" "-w")]
|
||||||
|
[:description
|
||||||
|
(lambda () (if (derived-mode-p 'prog-mode)
|
||||||
|
"Refactor" "Rewrite"))
|
||||||
|
(gptel--suffix-rewrite)
|
||||||
|
(gptel--suffix-rewrite-and-replace)
|
||||||
|
(gptel--suffix-rewrite-and-ediff)]]
|
||||||
|
(interactive)
|
||||||
|
(unless gptel--rewrite-message
|
||||||
|
(setq gptel--rewrite-message (gptel--rewrite-message)))
|
||||||
|
(transient-setup 'gptel-rewrite-menu))
|
||||||
;; TODO: Switch to dynamic Transient menus (below) once there's a new Transient release
|
;; TODO: Switch to dynamic Transient menus (below) once there's a new Transient release
|
||||||
;; (transient-define-prefix gptel-system-prompt ()
|
;; (transient-define-prefix gptel-system-prompt ()
|
||||||
;; "Change the system prompt to send ChatGPT."
|
;; "Change the system prompt to send ChatGPT."
|
||||||
|
@ -216,6 +249,19 @@ will get progressively longer!"
|
||||||
(buf (call-interactively #'gptel)))
|
(buf (call-interactively #'gptel)))
|
||||||
(and (bufferp buf)
|
(and (bufferp buf)
|
||||||
(with-current-buffer buf (gptel-send)))))
|
(with-current-buffer buf (gptel-send)))))
|
||||||
|
(transient-define-infix gptel--infix-rewrite-prompt ()
|
||||||
|
"Chat directive (system message) to use for rewriting or refactoring."
|
||||||
|
:description (lambda () (if (derived-mode-p 'prog-mode)
|
||||||
|
"Set directives for refactor"
|
||||||
|
"Set directives for rewrite"))
|
||||||
|
:format "%k %d"
|
||||||
|
:class 'transient-lisp-variable
|
||||||
|
:variable 'gptel--rewrite-message
|
||||||
|
:key "h"
|
||||||
|
:prompt "Set directive for rewrite: "
|
||||||
|
:reader (lambda (prompt _ history)
|
||||||
|
(read-string
|
||||||
|
prompt (gptel--rewrite-message) history)))
|
||||||
|
|
||||||
(transient-define-suffix gptel--suffix-system-message ()
|
(transient-define-suffix gptel--suffix-system-message ()
|
||||||
"Set directives sent to ChatGPT."
|
"Set directives sent to ChatGPT."
|
||||||
|
@ -258,5 +304,67 @@ will get progressively longer!"
|
||||||
(body-function . ,#'select-window)))
|
(body-function . ,#'select-window)))
|
||||||
(call-interactively #'gptel-menu))))))
|
(call-interactively #'gptel-menu))))))
|
||||||
|
|
||||||
|
(transient-define-suffix gptel--suffix-rewrite ()
|
||||||
|
"Rewrite or refactor region contents."
|
||||||
|
:key "r"
|
||||||
|
:description #'gptel--refactor-or-rewrite
|
||||||
|
(interactive)
|
||||||
|
(let* ((prompt (buffer-substring-no-properties
|
||||||
|
(region-beginning) (region-end)))
|
||||||
|
(stream gptel-stream)
|
||||||
|
(gptel--system-message gptel--rewrite-message))
|
||||||
|
(gptel-request prompt :stream stream)))
|
||||||
|
|
||||||
|
(transient-define-suffix gptel--suffix-rewrite-and-replace ()
|
||||||
|
"Refactor region contents and replace it."
|
||||||
|
:key "R"
|
||||||
|
:description (lambda () (concat (gptel--refactor-or-rewrite) " in place"))
|
||||||
|
(interactive)
|
||||||
|
(let* ((prompt (buffer-substring-no-properties
|
||||||
|
(region-beginning) (region-end)))
|
||||||
|
(stream gptel-stream)
|
||||||
|
(gptel--system-message gptel--rewrite-message))
|
||||||
|
(kill-region (region-beginning) (region-end))
|
||||||
|
(message "Original text saved to kill-ring.")
|
||||||
|
(gptel-request prompt :stream stream :in-place t)))
|
||||||
|
|
||||||
|
(transient-define-suffix gptel--suffix-rewrite-and-ediff (args)
|
||||||
|
"Refactoring or rewrite region contents and run Ediff."
|
||||||
|
:key "E"
|
||||||
|
:description (lambda () (concat (gptel--refactor-or-rewrite) " and Ediff"))
|
||||||
|
(interactive (list (transient-args transient-current-command)))
|
||||||
|
(let* ((prompt (buffer-substring-no-properties
|
||||||
|
(region-beginning) (region-end)))
|
||||||
|
(gptel--system-message gptel--rewrite-message))
|
||||||
|
(message "Waiting for response... ")
|
||||||
|
(gptel-request
|
||||||
|
prompt
|
||||||
|
:context (cons (region-beginning) (region-end))
|
||||||
|
:callback
|
||||||
|
(lambda (response info)
|
||||||
|
(if (not response)
|
||||||
|
(message "ChatGPT response error: %s" (plist-get info :status))
|
||||||
|
(let* ((gptel-buffer (plist-get info :buffer))
|
||||||
|
(gptel-bounds (plist-get info :context))
|
||||||
|
(buffer-mode
|
||||||
|
(buffer-local-value 'major-mode gptel-buffer)))
|
||||||
|
(pcase-let ((`(,new-buf ,new-beg ,new-end)
|
||||||
|
(with-current-buffer (get-buffer-create "*gptel-rewrite-Region.B-*")
|
||||||
|
(erase-buffer)
|
||||||
|
(funcall buffer-mode)
|
||||||
|
(insert response)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(list (current-buffer) (point-min) (point-max)))))
|
||||||
|
(require 'ediff)
|
||||||
|
(apply
|
||||||
|
#'ediff-regions-internal
|
||||||
|
(get-buffer (ediff-make-cloned-buffer gptel-buffer "-Region.A-"))
|
||||||
|
(car gptel-bounds) (cdr gptel-bounds)
|
||||||
|
new-buf new-beg new-end
|
||||||
|
nil
|
||||||
|
(if (transient-arg-value "-w" args)
|
||||||
|
(list 'ediff-regions-wordwise 'word-wise nil)
|
||||||
|
(list 'ediff-regions-linewise nil nil))))))))))
|
||||||
|
|
||||||
(provide 'gptel-transient)
|
(provide 'gptel-transient)
|
||||||
;;; gptel-transient.el ends here
|
;;; gptel-transient.el ends here
|
||||||
|
|
Loading…
Add table
Reference in a new issue