@@ -92,6 +92,9 @@ listed in `.gitignore' in a Git repository) will not be added to the context."
92
92
:group 'gptel
93
93
:type 'boolean )
94
94
95
+ (defvar-local gptel-context--project-files nil
96
+ " Cache of project files for the current directory." )
97
+
95
98
(defun gptel-context-add (&optional arg confirm )
96
99
" Add context to gptel in a DWIM fashion.
97
100
@@ -127,24 +130,20 @@ listed in `.gitignore' in a Git repository) will not be added to the context."
127
130
(remove-p (< (prefix-numeric-value arg) 0 ))
128
131
(action-fn (if remove-p
129
132
#'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 )))
134
134
(when (or remove-p (null dirs) (null confirm)
135
135
(y-or-n-p (format " Recursively add files from %d director%s ? "
136
136
(length dirs)
137
137
(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 ))))
143
141
; ; If in an image buffer
144
142
((and (derived-mode-p 'image-mode )
145
143
(gptel--model-capable-p 'media )
146
144
(buffer-file-name )
147
145
(not (gptel-context--skip-p (buffer-file-name ))))
146
+ (gptel-context--ensure-project-files default-directory)
148
147
(funcall (if (and arg (< (prefix-numeric-value arg) 0 ))
149
148
#'gptel-context-remove
150
149
#'gptel-context-add-file )
@@ -211,22 +210,17 @@ Return PATH if added, nil if ignored."
211
210
(message " Ignoring unsupported binary file \" %s \" . " path)
212
211
nil ))
213
212
214
- (defun gptel-context--add-directory (path action &optional project-files )
213
+ (defun gptel-context--add-directory (path action )
215
214
" 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)))
223
217
(dolist (file (directory-files-recursively path " ." t ))
224
218
(unless (file-directory-p file)
225
219
(if (and gptel-context-restrict-to-project-files
226
220
root
227
221
(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)
230
224
(pcase-exhaustive action
231
225
('add
232
226
(if (gptel--file-binary-p file)
@@ -237,26 +231,25 @@ PROJECT-FILES is a list of all files in the current project."
237
231
(when (eq action 'remove )
238
232
(message " Directory \" %s \" removed from context. " path))))
239
233
240
- (defun gptel-context-add-file (path &optional project-files )
234
+ (defun gptel-context-add-file (path )
241
235
" Add the file at PATH to the gptel context.
242
236
243
237
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."
247
239
(interactive " fChoose file to add to context: " )
240
+ (gptel-context--ensure-project-files path)
248
241
(cond ((file-directory-p path)
249
- (gptel-context--add-directory path 'add project-files ))
242
+ (gptel-context--add-directory path 'add ))
250
243
((and gptel-context-restrict-to-project-files
251
244
(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))))
254
247
(let ((root (project-root project)))
255
248
(and (file-in-directory-p path root)
256
- (not (member path project-files)))))
249
+ (not (member path gptel-context-- project-files)))))
257
250
; ; Otherwise check individually
258
251
(gptel-context--skip-p path)))
259
- (gptel-context--message-skipped path project-files ))
252
+ (gptel-context--message-skipped path))
260
253
((gptel--file-binary-p path)
261
254
(gptel-context--add-binary-file path))
262
255
(t (gptel-context--add-text-file path))))
@@ -266,6 +259,20 @@ PROJECT-FILES is a list of all files in the current project."
266
259
267
260
; ;; project-related functions
268
261
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
+
269
276
(defun gptel-context--get-project-files (dir )
270
277
" Return a list of files in the project DIR, or nil if no project is found."
271
278
(when-let ((project (project-current nil dir)))
@@ -278,13 +285,12 @@ PROJECT-FILES is a list of all files in the current project."
278
285
(when-let* ((project (project-current nil file)))
279
286
(not (member file (gptel-context--get-project-files (project-root project)))))))
280
287
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."
284
290
(let* ((type (if (file-directory-p file) " directory" " file" ))
285
291
(reminder (format " To include this file, unset %S . "
286
292
'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)))
288
294
(rel-file (file-relative-name file (project-root project))))
289
295
(message " Skipping %s \" %s \" in project \" %s \" . %s "
290
296
type rel-file (project-name project) reminder)
0 commit comments