[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/gptel 5d093f2135 10/20: gptel-context: Support for files a
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/gptel 5d093f2135 10/20: gptel-context: Support for files as context |
Date: |
Sun, 23 Jun 2024 00:59:53 -0400 (EDT) |
branch: elpa/gptel
commit 5d093f2135dcf69c8493183902e5b932b0aa2c2b
Author: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Commit: karthink <karthikchikmagalur@gmail.com>
gptel-context: Support for files as context
* gptel-context.el (gptel-context-confirm,
gptel-context--buffer-setup, gptel-context--string-default,
gptel-context--insert-file-string, gptel-context--collect,
gptel-context-add, gptel-context-add-file): Support for adding
files to gptel's context.
* gptel-transient.el (gptel-menu, gptel--suffix-context-buffer,
gptel-context--add-region, gptel-context--add-buffer,
gptel-context--add-file): menu changes for adding files to
context.
* gptel.el (gptel--create-prompt, gptel-request,
gptel-context--overlay-alist, gptel-context--alist):
Rename `gptel-context--overlay-alist` to `gptel-context--alist`
since it is no longer a list of overlays.
* gptel-transient.el (gptel--suffix-context-buffer): Adjust for
renaming.
* gptel-context.el (gptel-context-confirm,
gptel-context--buffer-setup, gptel-context--string-default,
gptel-context--collect, gptel-context--make-overlay,
gptel-context-add-file, gptel-context-string-function): Adjust for
renaming, and improve docstrings involving the use of
`gptel-context--alist`.
* gptel-context.el (gptel-context-confirm, gptel-context-add-file,
gptel-context-add, gptel-add-file): Alias `gptel-context-add-file`
to `gptel-add-file`. Add support for dired buffers to `gptel-add`.
* gptel-transient.el (gptel--suffix-context-add-file): Adjust for
renaming.
* gptel-context.el (gptel-context-add-file): Handle missing files
gracefully.
Fix invalid format string in gptel-context-add-file
---
gptel-context.el | 145 +++++++++++++++++++++++++++++++++++------------------
gptel-transient.el | 45 ++++++++++++-----
gptel.el | 15 ++++--
3 files changed, 139 insertions(+), 66 deletions(-)
diff --git a/gptel-context.el b/gptel-context.el
index 3625022dc9..8f5740df1d 100644
--- a/gptel-context.el
+++ b/gptel-context.el
@@ -32,6 +32,7 @@
(require 'cl-lib)
(declare-function gptel-menu "gptel-transient")
+(declare-function dired-get-marked-files "dired")
(defface gptel-context-highlight-face
'((t :inherit header-line))
@@ -54,14 +55,16 @@ This is used in gptel context buffers."
(defcustom gptel-context-string-function #'gptel-context--string-default
"Function to format the context string sent with the gptel request.
-This function receives one argument, an alist of context overlays
+This function receives one argument, an alist of contexts
organized by buffer. It should return a string containing the
formatted context and any additional comments you wish to
include.
-The alist of context overlays is structured as follows:
+Each gptel \"context\" is either a file path or an overlay in a
+buffer. The alist of contexts is structured as follows:
((buffer1 . (overlay1 overlay2)
+ (\"path/to/file\")
(buffer2 . (overlay3 overlay4 overlay5))))
Each overlay covers a buffer region containing the
@@ -76,21 +79,17 @@ context chunk. This is accessible as, for example:
(defun gptel-context-add (&optional arg)
"Add context to gptel in a DWIM fashion.
-When called without prefix argument ARG:
-
- If a region is selected, add the selected region to the
-context.
-
-- If there is a gptel context under point, remove it.
+ context. If there is already a gptel context at point, remove it
+ instead.
-- Otherwise add the current buffer to the context.
+- If in Dired, add marked files or file at point to the context.
+ With negative prefix ARG, remove them from the context instead.
-Otherwise:
+- Otherwise add the current buffer to the context. With positive
+ prefix ARG, prompt for a buffer name and add it to the context.
-- When ARG is positive, prompt for a buffer name and add it to
- the context.
-
-- When ARG is negative, removes all gptel contexts from the
+- With negative prefix ARG, remove all gptel contexts from the
current buffer."
(interactive "P")
(cond
@@ -101,6 +100,12 @@ Otherwise:
(region-end))
(deactivate-mark)
(message "Current region added as context."))
+ ;; If in dired
+ ((derived-mode-p 'dired-mode)
+ (mapc (if (and arg (< (prefix-numeric-value arg) 0))
+ #'gptel-context-remove
+ #'gptel-context-add-file)
+ (dired-get-marked-files)))
;; No region is selected, and ARG is positive.
((and arg (> (prefix-numeric-value arg) 0))
(let ((buffer-name (read-buffer "Choose buffer to add as context: " nil
t)))
@@ -129,27 +134,46 @@ Otherwise:
(gptel-context--add-region (current-buffer) (point-min) (point-max) t)
(message "Current buffer added as context.")))))
-;;;###autoload (autoload 'gptel-add "gptel-context" "Add or remove context to
gptel's requests." t)
+;;;###autoload (autoload 'gptel-add "gptel-context" "Add/remove regions or
buffers from gptel's context." t)
(defalias 'gptel-add #'gptel-context-add)
+(defun gptel-context-add-file (path)
+ "Add the file at PATH to the gptel context.
+
+PATH should be readable as text."
+ (interactive "fChoose file to add to context: ")
+ (condition-case nil
+ ;; Check if file is binary
+ (if (with-temp-buffer ;; (create-file-buffer file)
+ (insert-file-contents path nil 1 512 'replace)
+ (eq buffer-file-coding-system 'no-conversion))
+ (message "Ignoring unsupported binary file \"%s\"." path)
+ (cl-pushnew (list path) gptel-context--alist :test #'equal)
+ (message "File \"%s\" added to context." path)
+ path)
+ (file-missing (message "File \"%s\" does not exist." path))))
+
+;;;###autoload (autoload 'gptel-add-file "gptel-context" "Add files to gptel's
context." t)
+(defalias 'gptel-add-file #'gptel-context-add-file)
+
(defun gptel-context-remove (&optional context)
"Remove the CONTEXT overlay from the contexts list.
If CONTEXT is nil, removes the context at point.
If selection is active, removes all contexts within selection."
- (interactive)
(cond
((overlayp context)
(delete-overlay context))
+ ((stringp context) ;file
+ (setf (alist-get context gptel-context--alist nil 'remove #'equal)
+ nil))
((region-active-p)
- (let ((contexts (gptel-context--in-region (current-buffer)
- (region-beginning)
- (region-end))))
- (when contexts
- (cl-loop for ctx in contexts do (delete-overlay ctx)))))
+ (when-let ((contexts (gptel-context--in-region (current-buffer)
+ (region-beginning)
+ (region-end))))
+ (cl-loop for ctx in contexts do (delete-overlay ctx))))
(t
- (let ((ctx (gptel-context--at-point)))
- (when ctx
- (delete-overlay ctx))))))
+ (when-let ((ctx (gptel-context--at-point)))
+ (delete-overlay ctx)))))
(defun gptel-context--make-overlay (start end &optional advance)
"Highlight the region from START to END."
@@ -158,7 +182,7 @@ If selection is active, removes all contexts within
selection."
(overlay-put overlay 'face 'gptel-context-highlight-face)
(overlay-put overlay 'gptel-context t)
(push overlay (alist-get (current-buffer)
- gptel-context--overlay-alist))
+ gptel-context--alist))
overlay))
;;;###autoload
@@ -203,15 +227,15 @@ START and END signify the region delimiters."
(defun gptel-context--collect ()
"Get the list of all active context overlays."
;; Get only the non-degenerate overlays, collect them, and update the
overlays variable.
- (let ((overlay-alist
- (cl-loop for (buf . ovs) in gptel-context--overlay-alist
- when (buffer-live-p buf)
- for updated-ovs = (cl-loop for ov in ovs
- when (overlay-start ov)
- collect ov)
- when updated-ovs
- collect (cons buf updated-ovs))))
- (setq gptel-context--overlay-alist overlay-alist)))
+ (setq gptel-context--alist
+ (cl-loop for (buf . ovs) in gptel-context--alist
+ if (buffer-live-p buf)
+ if (cl-loop for ov in ovs when (overlay-start ov) collect
ov)
+ collect (cons buf it) into elements
+ end
+ else if (file-exists-p buf)
+ collect (list buf) into elements
+ finally return elements)))
(defun gptel-context--insert-buffer-string (buffer contexts)
"Insert at point a context string from all CONTEXTS in BUFFER."
@@ -252,16 +276,26 @@ START and END signify the region delimiters."
(insert "\n..."))
(insert "\n```")))
+(defun gptel-context--insert-file-string (path)
+ "Insert at point the contents of the file at PATH as context."
+ (insert (format "In file `%s`:" (file-name-nondirectory path))
+ "\n\n```\n")
+ (insert-file-contents path)
+ (goto-char (point-max))
+ (insert "\n```\n"))
+
(defun gptel-context--string-default (context-alist)
"Format the aggregated gptel context as annotated markdown fragments.
Returns a string. CONTEXT-ALIST is a structure containing
-context overlays, see `gptel-context--overlay-alist'."
+context overlays, see `gptel-context--alist'."
(with-temp-buffer
(insert "Request context:\n\n")
(cl-loop for (buf . ovs) in context-alist
+ if (bufferp buf)
do (gptel-context--insert-buffer-string buf ovs)
- (insert "\n\n")
+ else do (gptel-context--insert-file-string buf)
+ do (insert "\n\n")
finally return (buffer-string))))
;;;###autoload
@@ -301,27 +335,42 @@ context overlays, see `gptel-context--overlay-alist'."
(propertize "C-c C-k" 'face 'help-key-binding) ": cancel, "
(propertize "q" 'face 'help-key-binding) ": quit"))
(save-excursion
- (let ((contexts gptel-context--overlay-alist))
+ (let ((contexts gptel-context--alist))
(if (length> contexts 0)
(let (beg ov l1 l2)
(pcase-dolist (`(,buf . ,ovs) contexts)
- (dolist (source-ov ovs)
- (with-current-buffer buf
- (setq l1 (line-number-at-pos (overlay-start source-ov))
- l2 (line-number-at-pos (overlay-end source-ov))))
+ (if (bufferp buf)
+ ;; It's a buffer with some overlay(s)
+ (dolist (source-ov ovs)
+ (with-current-buffer buf
+ (setq l1 (line-number-at-pos (overlay-start
source-ov))
+ l2 (line-number-at-pos (overlay-end
source-ov))))
+ (insert (make-separator-line)
+ (propertize (format "In buffer %s (lines
%d-%d):\n\n"
+ (buffer-name buf) l1 l2)
+ 'face 'bold))
+ (setq beg (point))
+ (insert-buffer-substring
+ buf (overlay-start source-ov) (overlay-end source-ov))
+ (setq ov (make-overlay beg (point)))
+ (overlay-put ov 'gptel-context source-ov)
+ (overlay-put ov 'gptel-overlay t)
+ (overlay-put ov 'evaporate t)
+ (insert "\n"))
+ ;; BUF is a file path, not a buffer
(insert (make-separator-line)
- (propertize (format "In buffer %s (lines
%d-%d):\n\n"
- (buffer-name buf) l1 l2)
+ (propertize (format "In file %s:\n\n"
(file-name-nondirectory buf))
'face 'bold))
(setq beg (point))
- (insert-buffer-substring
- buf (overlay-start source-ov) (overlay-end source-ov))
+ (insert-file-contents buf)
+ (goto-char (point-max))
(setq ov (make-overlay beg (point)))
- (overlay-put ov 'gptel-context source-ov)
+ (overlay-put ov 'gptel-context buf)
(overlay-put ov 'gptel-overlay t)
- (insert "\n")))
+ (overlay-put ov 'evaporate t)
+ (insert "\n\n")))
(goto-char (point-min)))
- (insert "There are no active contexts in any buffer.")))))
+ (insert "There are no active gptel contexts.")))))
(display-buffer (current-buffer)
`((display-buffer-reuse-window
display-buffer-reuse-mode-window
@@ -418,7 +467,7 @@ If non-nil, indicates backward movement.")
"Confirm pending operations and return to gptel's menu."
(interactive)
;; Delete all the context overlays that have been marked for deletion.
- (mapc #'delete-overlay
+ (mapc #'gptel-context-remove
(delq nil (mapcar (lambda (ov)
(and
(overlay-get ov 'gptel-context-deletion-mark)
diff --git a/gptel-transient.el b/gptel-transient.el
index 195cd737f2..5d24b62cad 100644
--- a/gptel-transient.el
+++ b/gptel-transient.el
@@ -290,11 +290,13 @@ Also format its value in the Transient menu."
"Instructions"
("s" "Set system message" gptel-system-prompt :transient t)
(gptel--infix-add-directive)]
- [""
+ [:pad-keys t
+ ""
"Context"
(gptel--infix-use-context)
(gptel--suffix-context-add-region)
(gptel--suffix-context-add-buffer)
+ (gptel--suffix-context-add-file)
(gptel--suffix-context-buffer)]]
[["Request Parameters"
:pad-keys t
@@ -593,7 +595,7 @@ querying the LLM."
:set-value #'gptel--set-with-scope
:display-if-true "Yes"
:display-if-false "No"
- :key "-r")
+ :key "-d")
;; ** Infix for the refactor/rewrite system message
@@ -926,16 +928,21 @@ When LOCAL is non-nil, set the system message only in the
current buffer."
"Display all contexts from all buffers & files."
:transient 'transient--do-exit
:key "C"
- :if (lambda () gptel-context--overlay-alist)
+ :if (lambda () gptel-context--alist)
:description
(lambda ()
- (let* ((contexts (and gptel-context--overlay-alist
(gptel-context--collect)))
- (buffer-count (length contexts))
- (ov-count (if (> buffer-count 0)
- (cl-loop for (_ . ovs) in contexts
- sum (length ovs))
- 0)))
- (concat "Inspect context "
+ (pcase-let*
+ ((contexts (and gptel-context--alist (gptel-context--collect)))
+ (buffer-count (length contexts))
+ (`(,file-count ,ov-count)
+ (if (> buffer-count 0)
+ (cl-loop for (buf-file . ovs) in contexts
+ if (bufferp buf-file)
+ sum (length ovs) into ov-count
+ else count (stringp buf-file) into file-count
+ finally return (list file-count ov-count))
+ (list 0 0))))
+ (concat "Inspect "
(format
(propertize "(%s)" 'face 'transient-delimiter)
(propertize
@@ -961,7 +968,7 @@ When LOCAL is non-nil, set the system message only in the
current buffer."
(transient-define-suffix gptel--suffix-context-add-region ()
"Add current region to gptel's context."
:transient 'transient--do-stay
- :key "cr"
+ :key "-r"
:if (lambda () (or (use-region-p)
(and (fboundp 'gptel-context--at-point)
(gptel-context--at-point))))
@@ -978,10 +985,22 @@ When LOCAL is non-nil, set the system message only in the
current buffer."
(transient-define-suffix gptel--suffix-context-add-buffer ()
"Add a buffer to gptel's context."
:transient 'transient--do-stay
- :key "cb"
+ :key "-b"
:description "Add a buffer to context"
(interactive)
- (gptel-add '(4)))
+ (gptel-add '(4))
+ (transient-setup))
+
+(declare-function gptel-add-file "gptel-context")
+
+(transient-define-suffix gptel--suffix-context-add-file ()
+ "Add a file to gptel's context."
+ :transient 'transient--do-stay
+ :key "-f"
+ :description "Add a file to context"
+ (interactive)
+ (call-interactively #'gptel-add-file)
+ (transient-setup))
;; ** Suffixes for rewriting/refactoring
diff --git a/gptel.el b/gptel.el
index 3820619704..dec2a44ed3 100644
--- a/gptel.el
+++ b/gptel.el
@@ -539,8 +539,13 @@ Currently supported options are:
(defvar-local gptel--old-header-line nil)
-(defvar gptel-context--overlay-alist nil
- "Alist of buffers and their corresponding context chunks.")
+(defvar gptel-context--alist nil
+ "List of gptel's context sources.
+
+Each entry is of the form
+ (buffer . (overlay1 overlay2 ...))
+or
+ (\"path/to/file\").")
;; Utility functions
@@ -931,7 +936,7 @@ Model parameters can be let-bound around calls to this
function."
(declare (indent 1))
(let* ((gptel--system-message
;Add context chunks to system message if required
- (if (and gptel-context--overlay-alist
+ (if (and gptel-context--alist
(eq gptel-use-context 'system))
(gptel-context--wrap system)
system))
@@ -1082,7 +1087,7 @@ recent exchanges.
If the region is active limit the prompt to the region contents
instead.
-If `gptel-context--overlay-alist' is non-nil and the additional
+If `gptel-context--alist' is non-nil and the additional
context needs to be included with the user prompt, add it.
If PROMPT-END (a marker) is provided, end the prompt contents
@@ -1105,7 +1110,7 @@ there."
(gptel--parse-buffer gptel-backend max-entries)))))
;; Inject context chunks into the last user prompt if required
;; NOTE: prompts is modified in place
- (when (and gptel-context--overlay-alist
+ (when (and gptel-context--alist
(eq gptel-use-context 'user)
(> (length prompts) 0))
(gptel--wrap-user-prompt gptel-backend prompts))
- [nongnu] elpa/gptel updated (44780a408a -> df0b424ea1), ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel ef9684206a 01/20: gptel-context: Add contexter, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel b10cd98e07 02/20: gptel-context: Implement DWIM features, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel 382b409176 03/20: gptel-transient: Simplify context buffer, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel f6306b5b15 08/20: gptel-transient: Update menu for context actions, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel 5d093f2135 10/20: gptel-context: Support for files as context,
ELPA Syncer <=
- [nongnu] elpa/gptel 0787592609 12/20: gptel-context: Fix context deletion overlay bug, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel 0abaefed38 13/20: gptel-context: Fix narrowing bug when inserting context, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel c81284479f 18/20: gptel-transient: Move context items around, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel 883b5e608a 17/20: gptel-context: Extra newlines before separator-line, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel df0b424ea1 20/20: gptel-ollama: Add num_ctx option, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel ef44164614 19/20: README: Update for context features, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel 56f9fc5e72 04/20: gptel-transient: Make gptel-lisp-variable more flexible, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel cbb49f92d3 05/20: gptel-context: Add gptel-context--wrap, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel 2b1dbf77b1 09/20: gptel-context: Make overlays front/rear-advance, ELPA Syncer, 2024/06/23
- [nongnu] elpa/gptel 70e3053c42 14/20: gptel-context: Clean up context buffer setup, ELPA Syncer, 2024/06/23