branch: elpa/gptel
commit f8f6d5dff13bda79e0331c3a9eb9b3e59adf98ae
Author: Karthik Chikmagalur <karthikchikmaga...@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>

    gptel-rewrite: Start rewrite without setting up transient
    
    To reduce the friction of using gptel-rewrite, don't invoke the
    transient menu unless the user asks for it.  Instead, read a
    rewrite instruction and start the rewrite immediately.
    
    If no region is selected and there are pending rewrites, display
    the rewrite menu.  This behavior is unchanged from before.
    
    * gptel-rewrite.el (gptel--rewrite-read-message, gptel-rewrite)
    (gptel--infix-rewrite-extra): New function
    `gptel--rewrite-read-message' to read the rewrite instruction and
    start the rewrite automatically if required.
    
    * gptel-transient.el (gptel--read-with-prefix-help,
    gptel--infix-add-directive): Minor changes to the usage of the
    help string `gptel--read-with-prefix-help'.
    
    * NEWS: Document `gptel-rewrite' behavior change.
---
 NEWS               |   7 ++++
 gptel-rewrite.el   | 111 ++++++++++++++++++++++++++++++++++++-----------------
 gptel-transient.el |   7 ++--
 3 files changed, 86 insertions(+), 39 deletions(-)

diff --git a/NEWS b/NEWS
index ec6f1493ab8..39030dfea7b 100644
--- a/NEWS
+++ b/NEWS
@@ -38,6 +38,13 @@
 
 ** New features and UI changes
 
+- ~gptel-rewrite~ now no longer pops up a Transient menu.  Instead, it
+  reads a rewrite instruction and starts the rewrite immediately.  This
+  is intended to reduce the friction of using ~gptel-rewrite~.  You can
+  still bring up the Transient menu by pressing =M-RET= instead of =RET=
+  when supplying the rewrite instruction.  If no region is selected and
+  there are pending rewrites, the rewrite menu is displayed.
+
 - New command ~gptel-gh-login~ to authenticate with GitHub Copilot.  The
   authentication step happens automatically when you use gptel, so
   invoking it manually is not required.  But you can use this command to
diff --git a/gptel-rewrite.el b/gptel-rewrite.el
index 240cd19f315..bca6ae9f49c 100644
--- a/gptel-rewrite.el
+++ b/gptel-rewrite.el
@@ -252,6 +252,66 @@ the changed regions. BUF is the (current) buffer."
           (gptel--rewrite-accept ovs newbuf)))
       newbuf)))
 
+(defun gptel--rewrite-read-message (prompt &optional _ history)
+  "Read a rewrite message from the minibuffer with custom keybindings for
+cycling, editing, and submitting the gptel rewrite.
+
+PROMPT is the prompt string to display.  HISTORY, if provided, is the
+input history list."
+  (let* ((rewrite-directive
+          (car-safe (gptel--parse-directive gptel--rewrite-directive 'raw)))
+         (cb (current-buffer))
+         (cycle-prefix (lambda () (interactive)
+                         (gptel--read-with-prefix rewrite-directive)
+                         (goto-char (point-max))))
+         (set-rewrite-message
+          (lambda ()
+            (let ((message (buffer-substring-no-properties
+                            (minibuffer-prompt-end) (point-max))))
+              (with-current-buffer cb (setq gptel--rewrite-message message))
+              (setf (alist-get 'gptel--infix-rewrite-extra transient-history)
+                    (delete-dups (cons message transient--history))))))
+         (start-rewrite-maybe
+          (lambda () (interactive)
+            (if transient--prefix    ;Called from transient? Don't start 
rewrite
+                (run-at-time 0 nil #'transient-setup 'gptel-rewrite)
+              (run-at-time 0 nil #'gptel--suffix-rewrite 
gptel--rewrite-message))
+            (when (minibufferp)
+              (funcall set-rewrite-message)
+              (minibuffer-quit-recursive-edit))))
+         (start-transient
+          (lambda () (interactive)
+            (run-at-time 0 nil #'transient-setup 'gptel-rewrite)
+            (when (minibufferp)
+              (funcall set-rewrite-message)
+              (minibuffer-quit-recursive-edit))))
+         (edit-in-buffer
+          (lambda () (interactive)
+            (let ((offset (- (point) (minibuffer-prompt-end))))
+              (gptel--edit-directive 'gptel--rewrite-message
+                :prompt rewrite-directive :initial (minibuffer-contents)
+                :buffer cb :setup (lambda () (ignore-errors (forward-char 
offset)))
+                ;; FIXME: We would like to (conditionally) start the rewrite
+                ;; here.  We can't because this callback is always called, even
+                ;; when quitting the edit buffer.
+                :callback
+                (lambda ()
+                  (run-at-time 0 nil #'transient-setup 'gptel-rewrite)
+                  (push (buffer-local-value 'gptel--rewrite-message cb)
+                        (alist-get 'gptel--infix-rewrite-extra 
transient-history))
+                  (when (minibufferp) (minibuffer-quit-recursive-edit)))))))
+         (minibuffer-local-map
+          (make-composed-keymap (define-keymap
+                                  "TAB" cycle-prefix "<tab>" cycle-prefix
+                                  "C-c C-e" edit-in-buffer
+                                  "<remap> <exit-minibuffer>" 
start-rewrite-maybe
+                                  "M-RET" start-transient)
+                                minibuffer-local-map)))
+    (minibuffer-with-setup-hook cycle-prefix
+      (read-string
+       prompt (or gptel--rewrite-message "Rewrite: ")
+       history))))
+
 ;; * Rewrite action functions
 
 (defun gptel--rewrite-reject (&optional ovs)
@@ -576,11 +636,20 @@ By default, gptel uses the directive associated with the 
`rewrite'
         'json)))]]
   (interactive)
   (gptel--rewrite-sanitize-overlays)
-  (unless (or gptel--rewrite-overlays (use-region-p))
-    (user-error "`gptel-rewrite' requires an active region or rewrite in 
progress."))
-  (unless gptel--rewrite-message
-    (setq gptel--rewrite-message "Rewrite: "))
-  (transient-setup 'gptel-rewrite))
+  (cond
+   ((use-region-p)                      ;Start a/another rewrite
+    (let ((transient--history ;No transient reader, so We manage history 
ourselves
+           (alist-get 'gptel--infix-rewrite-extra transient-history)))
+      (gptel--rewrite-read-message
+       (concat "Instructions (" gptel--read-with-prefix-help
+               (format " %s%s) "
+                       (propertize "M-RET" 'face 'help-key-binding)
+                       (propertize ": More options" 'face 'default)))
+       nil (cons 'transient--history 1))))
+   (gptel--rewrite-overlays             ;Rewrite actions pending, show options
+    (transient-setup 'gptel-rewrite))
+   (t (user-error
+       "`gptel-rewrite' requires an active region or rewrite in progress."))))
 
 ;; * Transient infixes for rewriting
 
@@ -593,36 +662,8 @@ By default, gptel uses the directive associated with the 
`rewrite'
   :display-nil "(None)"
   :key "d"
   :format " %k %d %v"
-  :prompt (concat "Instructions " gptel--read-with-prefix-help)
-  :reader (lambda (prompt _ history)
-            (let* ((rewrite-directive
-                    (car-safe (gptel--parse-directive gptel--rewrite-directive
-                                                      'raw)))
-                   (cb (current-buffer))
-                   (cycle-prefix
-                    (lambda () (interactive)
-                      (gptel--read-with-prefix rewrite-directive)))
-                   (edit-in-buffer
-                    (lambda () (interactive)
-                      (let ((offset (- (point) (minibuffer-prompt-end))))
-                        (gptel--edit-directive 'gptel--rewrite-message
-                          :prompt rewrite-directive :initial 
(minibuffer-contents)
-                          :buffer cb :setup (lambda () (ignore-errors 
(forward-char offset)))
-                          :callback
-                          (lambda ()
-                            (run-at-time 0 nil #'transient-setup 
'gptel-rewrite)
-                            (push (buffer-local-value 'gptel--rewrite-message 
cb)
-                                  (alist-get 'gptel--infix-rewrite-extra 
transient-history))
-                            (when (minibufferp) 
(minibuffer-quit-recursive-edit)))))))
-                   (minibuffer-local-map
-                    (make-composed-keymap (define-keymap
-                                            "TAB" cycle-prefix "<tab>" 
cycle-prefix
-                                            "C-c C-e" edit-in-buffer)
-                                          minibuffer-local-map)))
-              (minibuffer-with-setup-hook cycle-prefix
-                (read-string
-                 prompt (or gptel--rewrite-message "Rewrite: ")
-                 history)))))
+  :prompt (concat "Instructions (" gptel--read-with-prefix-help ") ")
+  :reader #'gptel--rewrite-read-message)
 
 (transient-define-argument gptel--infix-rewrite-diff:-U ()
   :description "Context lines"
diff --git a/gptel-transient.el b/gptel-transient.el
index f6fba6e45a9..f99aca70d24 100644
--- a/gptel-transient.el
+++ b/gptel-transient.el
@@ -153,13 +153,12 @@ Meant to be called when `gptel-menu' is active."
 
 (defconst gptel--read-with-prefix-help
   (concat
-   (propertize "(" 'face 'default)
    (propertize "TAB" 'face 'help-key-binding)
    (propertize ": expand, " 'face 'default)
    (propertize "M-n" 'face 'help-key-binding)
    (propertize "/" 'face 'default)
    (propertize "M-p" 'face 'help-key-binding)
-   (propertize ": next/previous) " 'face 'default))
+   (propertize ": next/previous" 'face 'default))
   "Help string ;TODO: ")
 
 (defun gptel--read-with-prefix (prefix)
@@ -1324,8 +1323,8 @@ Or in an extended conversation:
   :display-nil 'none
   :overlay nil
   :argument ":"
-  :prompt (concat "Add instructions for next request only "
-                  gptel--read-with-prefix-help)
+  :prompt (concat "Add instructions for next request only ("
+                  gptel--read-with-prefix-help ") ")
   :reader (lambda (prompt initial history)
             (let* ((directive
                     (car-safe (gptel--parse-directive gptel--system-message 
'raw)))

Reply via email to