gptel: Insert response below point, not at point-max

gptel.el (gptel--update-header-line, gptel-send, gptel--playback,
gptel--create-prompt): Add helper function to update the header-line,
and only call when `gptel-mode' is on.  Use markers to track where the
response should be inserted, and insert it after (point) by default.
This commit is contained in:
Karthik Chikmagalur 2023-03-10 22:27:31 -08:00
parent 9f8fc0e519
commit a3109a4b68

View file

@ -119,6 +119,12 @@ return the transformed string."
(defvar-local gptel--temperature 1.0) (defvar-local gptel--temperature 1.0)
(defvar-local gptel--num-messages-to-send nil) (defvar-local gptel--num-messages-to-send nil)
(defun gptel--update-header-line (msg face)
(and header-line-format
(setf (nth 1 header-line-format)
(propertize msg 'face face))
(force-mode-line-update)))
(defsubst gptel--numberize (val) (defsubst gptel--numberize (val)
"Ensure VAL is a number." "Ensure VAL is a number."
(if (stringp val) (string-to-number val) val)) (if (stringp val) (string-to-number val) val))
@ -129,12 +135,10 @@ return the transformed string."
(if (and arg (require 'gptel-transient nil t)) (if (and arg (require 'gptel-transient nil t))
(call-interactively #'gptel-send-menu) (call-interactively #'gptel-send-menu)
(message "Querying ChatGPT...") (message "Querying ChatGPT...")
(and header-line-format (gptel--update-header-line " Waiting..." 'warning)
(setf (nth 1 header-line-format) (let* ((response-pt (point-marker))
(propertize " Waiting..." 'face 'warning)) (gptel-buffer (current-buffer))
(force-mode-line-update)) (full-prompt (gptel--create-prompt response-pt))
(let* ((gptel-buffer (current-buffer))
(full-prompt (gptel--create-prompt))
(response (aio-await (response (aio-await
(funcall (funcall
(if gptel-use-curl (if gptel-use-curl
@ -149,38 +153,40 @@ return the transformed string."
(save-excursion (save-excursion
(put-text-property 0 (length content-str) 'gptel 'response content-str) (put-text-property 0 (length content-str) 'gptel 'response content-str)
(message "Querying ChatGPT... done.") (message "Querying ChatGPT... done.")
(goto-char (point-max)) (goto-char response-pt)
(display-buffer (current-buffer) (display-buffer (current-buffer)
'((display-buffer-reuse-window '((display-buffer-reuse-window
display-buffer-use-some-window))) display-buffer-use-some-window)))
(unless (bobp) (insert "\n\n")) (unless (bobp) (insert-before-markers-and-inherit "\n\n"))
(if gptel-playback (if gptel-playback
(gptel--playback (current-buffer) content-str (point)) (gptel--playback gptel-buffer content-str response-pt)
(let ((p (point))) (let ((p (point)))
(insert content-str) (insert content-str)
(pulse-momentary-highlight-region p (point)))) (pulse-momentary-highlight-region p (point)))
(insert "\n\n" gptel-prompt-string) (when gptel-mode
(unless gptel-playback (insert "\n\n" gptel-prompt-string)
(setf (nth 1 header-line-format) (gptel--update-header-line " Ready" 'success))))
(propertize " Ready" 'face 'success))))) (goto-char (- (point) 2)))
(and header-line-format (gptel--update-header-line
(setf (nth 1 header-line-format) (format " Response Error: %s" status-str) 'error)))))
(propertize (format " Response Error: %s" status-str)
'face 'error)))))))
(defun gptel--create-prompt () (defun gptel--create-prompt (&optional prompt-end)
"Return a full conversation prompt from the contents of this buffer. "Return a full conversation prompt from the contents of this buffer.
If `gptel--num-messages-to-send' is set, limit to that many If `gptel--num-messages-to-send' is set, limit to that many
recent exchanges. recent exchanges.
If the region is active limit the prompt to the region contents If the region is active limit the prompt to the region contents
instead." instead.
If PROMPT-END (a marker) is provided, end the prompt contents
there."
(save-excursion (save-excursion
(save-restriction (save-restriction
(when (use-region-p) (if (use-region-p)
(narrow-to-region (region-beginning) (region-end))) (progn (narrow-to-region (region-beginning) (region-end))
(goto-char (point-max)) (goto-char (point-max)))
(goto-char (or prompt-end (point-max))))
(let ((max-entries (and gptel--num-messages-to-send (let ((max-entries (and gptel--num-messages-to-send
(* 2 (gptel--numberize (* 2 (gptel--numberize
gptel--num-messages-to-send)))) gptel--num-messages-to-send))))
@ -374,7 +380,7 @@ Begin at START-PT."
(let ((handle (gensym "gptel-change-group-handle--")) (let ((handle (gensym "gptel-change-group-handle--"))
(playback-timer (gensym "gptel--playback-")) (playback-timer (gensym "gptel--playback-"))
(content-length (length content-str)) (content-length (length content-str))
(idx 0) (pt (make-marker))) (idx 0) (pt (copy-marker start-pt t)))
(setf (symbol-value handle) (prepare-change-group buf)) (setf (symbol-value handle) (prepare-change-group buf))
(activate-change-group (symbol-value handle)) (activate-change-group (symbol-value handle))
(setf (symbol-value playback-timer) (setf (symbol-value playback-timer)
@ -384,18 +390,16 @@ Begin at START-PT."
(with-current-buffer buf (with-current-buffer buf
(if (>= content-length idx) (if (>= content-length idx)
(progn (progn
(when (= idx 0) (set-marker pt start-pt))
(goto-char pt) (goto-char pt)
(insert-before-markers-and-inherit (insert
(cl-subseq (cl-subseq
content-str idx content-str idx
(min content-length (+ idx 16)))) (min content-length (+ idx 16))))
(setq idx (+ idx 16))) (setq idx (+ idx 16)))
(when start-pt (goto-char (- start-pt 2))) (when gptel-mode
(and header-line-format (insert "\n\n" gptel-prompt-string)
(setf (nth 1 header-line-format) (gptel--update-header-line " Ready" 'success))
(propertize " Ready" 'face 'success)) (when start-pt (goto-char (marker-position start-pt)))
(force-mode-line-update))
(accept-change-group (symbol-value handle)) (accept-change-group (symbol-value handle))
(undo-amalgamate-change-group (symbol-value handle)) (undo-amalgamate-change-group (symbol-value handle))
(cancel-timer (symbol-value playback-timer))))))) (cancel-timer (symbol-value playback-timer)))))))