Skip to content

Commit 4b99e1e

Browse files
committed
gptel-context: Store project files in a local variable
1 parent 578fb5f commit 4b99e1e

File tree

1 file changed

+38
-32
lines changed

1 file changed

+38
-32
lines changed

gptel-context.el

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ listed in `.gitignore' in a Git repository) will not be added to the context."
9292
:group 'gptel
9393
:type 'boolean)
9494

95+
(defvar-local gptel-context--project-files nil
96+
"Cache of project files for the current directory.")
97+
9598
(defun gptel-context-add (&optional arg confirm)
9699
"Add context to gptel in a DWIM fashion.
97100
@@ -127,24 +130,20 @@ listed in `.gitignore' in a Git repository) will not be added to the context."
127130
(remove-p (< (prefix-numeric-value arg) 0))
128131
(action-fn (if remove-p
129132
#'gptel-context-remove
130-
#'gptel-context-add-file))
131-
(project-files (and (not remove-p)
132-
gptel-context-restrict-to-project-files
133-
(gptel-context--get-project-files default-directory))))
133+
#'gptel-context-add-file)))
134134
(when (or remove-p (null dirs) (null confirm)
135135
(y-or-n-p (format "Recursively add files from %d director%s? "
136136
(length dirs)
137137
(if (= (length dirs) 1) "y" "ies"))))
138-
(if project-files
139-
(mapc (lambda (file)
140-
(gptel-context-add-file file project-files))
141-
files)
142-
(mapc action-fn files)))))
138+
(unless remove-p
139+
(gptel-context--ensure-project-files default-directory))
140+
(mapc action-fn files))))
143141
;; If in an image buffer
144142
((and (derived-mode-p 'image-mode)
145143
(gptel--model-capable-p 'media)
146144
(buffer-file-name)
147145
(not (gptel-context--skip-p (buffer-file-name))))
146+
(gptel-context--ensure-project-files default-directory)
148147
(funcall (if (and arg (< (prefix-numeric-value arg) 0))
149148
#'gptel-context-remove
150149
#'gptel-context-add-file)
@@ -211,22 +210,17 @@ Return PATH if added, nil if ignored."
211210
(message "Ignoring unsupported binary file \"%s\"." path)
212211
nil))
213212

214-
(defun gptel-context--add-directory (path action &optional project-files)
213+
(defun gptel-context--add-directory (path action)
215214
"Process all files in directory at PATH according to ACTION.
216-
ACTION should be either `add' or `remove'.
217-
218-
PROJECT-FILES is a list of all files in the current project."
219-
(let* ((project-files (or project-files
220-
(and (eq action 'add)
221-
(gptel-context--get-project-files path))))
222-
(root (car-safe project-files)))
215+
ACTION should be either `add' or `remove'."
216+
(let* ((root (car-safe gptel-context--project-files)))
223217
(dolist (file (directory-files-recursively path "." t))
224218
(unless (file-directory-p file)
225219
(if (and gptel-context-restrict-to-project-files
226220
root
227221
(eq action 'add)
228-
(not (member file project-files)))
229-
(gptel-context--message-skipped file project-files)
222+
(not (member file gptel-context--project-files)))
223+
(gptel-context--message-skipped file)
230224
(pcase-exhaustive action
231225
('add
232226
(if (gptel--file-binary-p file)
@@ -237,26 +231,25 @@ PROJECT-FILES is a list of all files in the current project."
237231
(when (eq action 'remove)
238232
(message "Directory \"%s\" removed from context." path))))
239233

240-
(defun gptel-context-add-file (path &optional project-files)
234+
(defun gptel-context-add-file (path)
241235
"Add the file at PATH to the gptel context.
242236
243237
If PATH is a directory, recursively add all files in it. PATH should
244-
be readable as text.
245-
246-
PROJECT-FILES is a list of all files in the current project."
238+
be readable as text."
247239
(interactive "fChoose file to add to context: ")
240+
(gptel-context--ensure-project-files path)
248241
(cond ((file-directory-p path)
249-
(gptel-context--add-directory path 'add project-files))
242+
(gptel-context--add-directory path 'add))
250243
((and gptel-context-restrict-to-project-files
251244
(not (file-remote-p path))
252-
(if project-files
253-
(when-let ((project (project-current nil (car-safe project-files))))
245+
(if gptel-context--project-files
246+
(when-let ((project (project-current nil (car-safe gptel-context--project-files))))
254247
(let ((root (project-root project)))
255248
(and (file-in-directory-p path root)
256-
(not (member path project-files)))))
249+
(not (member path gptel-context--project-files)))))
257250
;; Otherwise check individually
258251
(gptel-context--skip-p path)))
259-
(gptel-context--message-skipped path project-files))
252+
(gptel-context--message-skipped path))
260253
((gptel--file-binary-p path)
261254
(gptel-context--add-binary-file path))
262255
(t (gptel-context--add-text-file path))))
@@ -266,6 +259,20 @@ PROJECT-FILES is a list of all files in the current project."
266259

267260
;;; project-related functions
268261

262+
(defun gptel-context--ensure-project-files (path)
263+
"Ensure project files are loaded for PATH if needed.
264+
PATH can be a file or directory.
265+
266+
Only loads project files if `gptel-context-restrict-to-project-files' is non-nil
267+
and `gptel-context--project-files' is not already set."
268+
(unless gptel-context--project-files
269+
(when gptel-context-restrict-to-project-files
270+
(setq gptel-context--project-files
271+
(gptel-context--get-project-files
272+
(if (and path (file-directory-p path))
273+
path
274+
(file-name-directory (or path default-directory))))))))
275+
269276
(defun gptel-context--get-project-files (dir)
270277
"Return a list of files in the project DIR, or nil if no project is found."
271278
(when-let ((project (project-current nil dir)))
@@ -278,13 +285,12 @@ PROJECT-FILES is a list of all files in the current project."
278285
(when-let* ((project (project-current nil file)))
279286
(not (member file (gptel-context--get-project-files (project-root project)))))))
280287

281-
(defun gptel-context--message-skipped (file &optional project-files)
282-
"Message that FILE is skipped because it is not a project file.
283-
PROJECT-FILES is a list of all files in the current project."
288+
(defun gptel-context--message-skipped (file)
289+
"Message that FILE is skipped because it is not a project file."
284290
(let* ((type (if (file-directory-p file) "directory" "file"))
285291
(reminder (format "To include this file, unset %S."
286292
'gptel-context-restrict-to-project-files)))
287-
(if-let* ((project (project-current nil (car-safe project-files)))
293+
(if-let* ((project (project-current nil (car-safe gptel-context--project-files)))
288294
(rel-file (file-relative-name file (project-root project))))
289295
(message "Skipping %s \"%s\" in project \"%s\". %s"
290296
type rel-file (project-name project) reminder)

0 commit comments

Comments
 (0)