Skip to content

gptel: Improve handling of read only buffers #644

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 40 additions & 10 deletions gptel-transient.el
Original file line number Diff line number Diff line change
Expand Up @@ -319,22 +319,53 @@ which see."
(let* ((transient-current-command (oref transient--prefix command))
(transient-current-suffixes transient--suffixes))
(transient-args transient-current-command))))
(lbeg (line-number-at-pos (if (use-region-p) (region-beginning)
(reg (use-region-p))
(lbeg (line-number-at-pos (if reg (region-beginning)
(point-min))))
(lend (line-number-at-pos (if (use-region-p) (region-end)
(lend (line-number-at-pos (if reg (region-end)
(point))))
(ltext (ptv (if (> lend lbeg)
(format " (lines %d-%d)" lbeg lend)
(format " (line %d)" lbeg))))
(dest) (context))
(pt-r/o (or buffer-read-only
(and (get-char-property (point) 'read-only)
(get-char-property (point) 'front-sticky))
(and (> (point) 1)
(get-char-property (1- (point)) 'read-only)
(not (get-char-property (1- (point)) 'rear-nonsticky)))))
(re-r/o (when reg
(or buffer-read-only
(and (get-char-property (region-end) 'read-only)
(get-char-property (region-end) 'front-sticky))
(and (> (point) 1)
(get-char-property (1- (region-end)) 'read-only)
(not (get-char-property (1- (region-end)) 'rear-nonsticky))))))
(reg-r/o (when reg (unless pt-r/o
(let ((e (region-end)))
(save-excursion
(goto-char (region-beginning))
(when-let ((m (text-property-search-forward 'read-only)))
(< (prop-match-beginning m) e))))))))
(setq dest (cond
((member "e" args) (ptv "echo area"))
((member "k" args) (ptv "kill-ring"))
((cl-some (lambda (s)
(and (stringp s) (memq (aref s 0) '(?g ?b))
(not (equal (substring s 1) (buffer-name)))
(concat (pth "buffer ") (ptv (substring s 1)))))
args))))
args))
(pt-r/o (concat (pth "buffer ")
(ptv gptel--read-only-response-buffer)
(pth " (point read-only)")))
(re-r/o (concat (pth "buffer ")
(ptv gptel--read-only-response-buffer)
(pth (concat " (region "
(unless (member "i" args) "end ")
"read-only)"))))
((and (member "i" args) reg-r/o)
(concat (pth "buffer ")
(ptv gptel--read-only-response-buffer)
(pth " (region read-only)")))))
(setq context
(and gptel-context--alist
(let ((lc (length gptel-context--alist)))
Expand Down Expand Up @@ -367,16 +398,15 @@ which see."
(if dest (concat (pth ", response to ") dest)
(concat (pth ", insert response at point")))))
((member "i" args)
(let* ((reg (use-region-p))
(src (ptv (if reg "selection" (buffer-name)))))
(let* ((src (ptv (if reg "region" (buffer-name)))))
(if dest (concat (pth "Send ") src ltext context (pth ", with response to ")
(ptv dest) (pth "; kill") ltext
(and (not reg) (concat (pth " in ") src)))
dest (unless (or pt-r/o reg-r/o) (concat (pth "; kill") ltext
(and (not reg) (concat (pth " in ") src)))))
(concat (pth "Replace ") src ltext (pth " with response")
(and context
(concat (pth " ( with") (substring context 11) " )"))))))
((use-region-p)
(concat (pth "Send ") (ptv "selection") ltext
(reg
(concat (pth "Send ") (ptv "region") ltext
context (if dest (concat (pth ", with response to ") dest)
(concat (pth ", insert response at region end")))))
(t (concat (pth "Send ") (ptv (buffer-name)) ltext
Expand Down
8 changes: 6 additions & 2 deletions gptel.el
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,9 @@ buffer."
(with-current-buffer (plist-get (gptel-fsm-info fsm) :buffer)
(gptel--update-status " Waiting..." 'warning)))

(defconst gptel--read-only-response-buffer "*LLM response*"
"Name of fall-back buffer when the source buffer is read-only.")

(defun gptel--handle-pre-insert (fsm)
"Tasks before inserting the LLM response for state FSM.

Expand All @@ -1834,9 +1837,10 @@ the request succeeded)."
(when (with-current-buffer (plist-get info :buffer)
(or buffer-read-only
(get-char-property start-marker 'read-only)))
(message "Buffer is read only, displaying reply in buffer \"*LLM response*\"")
(message "Buffer is read-only, displaying reply in buffer \"%s\""
gptel--read-only-response-buffer)
(display-buffer
(with-current-buffer (get-buffer-create "*LLM response*")
(with-current-buffer (get-buffer-create gptel--read-only-response-buffer)
(visual-line-mode 1)
(goto-char (point-max))
(move-marker start-marker (point) (current-buffer))
Expand Down