77--- @field end_row number
88--- @field end_col number
99
10- --- @class CopilotChat.context.outline : CopilotChat.copilot.embed
11- --- @field symbols table<string , CopilotChat.context.symbol>
10+ --- @class CopilotChat.context.embed
11+ --- @field content string
12+ --- @field filename string
13+ --- @field filetype string
14+ --- @field original string ?
15+ --- @field symbols table<string , CopilotChat.context.symbol> ?
16+ --- @field embedding table<number> ?
1217
1318local async = require (' plenary.async' )
1419local log = require (' plenary.log' )
1520local utils = require (' CopilotChat.utils' )
21+ local file_cache = {}
1622
1723local M = {}
1824
@@ -79,10 +85,10 @@ local function spatial_distance_cosine(a, b)
7985end
8086
8187--- Rank data by relatedness to the query
82- --- @param query CopilotChat.copilot .embed
83- --- @param data table<CopilotChat.copilot .embed>
88+ --- @param query CopilotChat.context .embed
89+ --- @param data table<CopilotChat.context .embed>
8490--- @param top_n number
85- --- @return table<CopilotChat.copilot .embed>
91+ --- @return table<CopilotChat.context .embed>
8692local function data_ranked_by_relatedness (query , data , top_n )
8793 data = vim .tbl_map (function (item )
8894 return vim .tbl_extend (
101107
102108--- Rank data by symbols
103109--- @param query string
104- --- @param data table<CopilotChat.context.outline >
110+ --- @param data table<CopilotChat.context.embed >
105111--- @param top_n number
106112local function data_ranked_by_symbols (query , data , top_n )
107113 local query_terms = {}
@@ -193,22 +199,15 @@ end
193199--- Build an outline and symbols from a string
194200--- @param content string
195201--- @param filename string
196- --- @param ft string ?
197- --- @return CopilotChat.context.outline
198- function M .outline (content , filename , ft )
199- ft = ft or ' text'
200-
202+ --- @param ft string
203+ --- @return CopilotChat.context.embed
204+ local function build_outline (content , filename , ft )
201205 local output = {
202206 filename = filename ,
203207 filetype = ft ,
204208 content = content ,
205- symbols = {},
206209 }
207210
208- if ft == ' raw' then
209- return output
210- end
211-
212211 local lang = vim .treesitter .language .get_lang (ft )
213212 local ok , parser = false , nil
214213 if lang then
@@ -224,6 +223,7 @@ function M.outline(content, filename, ft)
224223
225224 local root = parser :parse ()[1 ]:root ()
226225 local lines = vim .split (content , ' \n ' )
226+ local symbols = {}
227227 local outline_lines = {}
228228 local depth = 0
229229
@@ -239,7 +239,7 @@ function M.outline(content, filename, ft)
239239 table.insert (outline_lines , string.rep (' ' , depth ) .. signature_start )
240240
241241 -- Store symbol information
242- table.insert (output . symbols , {
242+ table.insert (symbols , {
243243 name = name ,
244244 signature = signature_start ,
245245 type = type ,
@@ -269,15 +269,45 @@ function M.outline(content, filename, ft)
269269 if # outline_lines > 0 then
270270 output .original = content
271271 output .content = table.concat (outline_lines , ' \n ' )
272+ output .symbols = symbols
272273 end
273274
274275 return output
275276end
276277
278+ --- Get data for a file
279+ --- @param filename string
280+ --- @param filetype string
281+ --- @return CopilotChat.context.embed ?
282+ local function get_file (filename , filetype )
283+ local modified = utils .file_mtime (filename )
284+ if not modified then
285+ return nil
286+ end
287+
288+ local cached = file_cache [filename ]
289+ if cached and cached .modified >= modified then
290+ return cached .outline
291+ end
292+
293+ local content = utils .read_file (filename )
294+ if content then
295+ local outline = build_outline (content , filename , filetype )
296+ file_cache [filename ] = {
297+ outline = outline ,
298+ modified = modified ,
299+ }
300+
301+ return outline
302+ end
303+
304+ return nil
305+ end
306+
277307--- Get list of all files in workspace
278308--- @param winnr number ?
279309--- @param with_content boolean ?
280- --- @return table<CopilotChat.copilot .embed>
310+ --- @return table<CopilotChat.context .embed>
281311function M .files (winnr , with_content )
282312 local cwd = utils .win_cwd (winnr )
283313 local files = utils .scan_dir (cwd , {
@@ -291,24 +321,22 @@ function M.files(winnr, with_content)
291321 if with_content then
292322 async .util .scheduler ()
293323
294- files = vim .tbl_map (function (file )
295- return {
296- name = utils .filepath (file ),
297- ft = utils .filetype (file ),
298- }
299- end , files )
300- files = vim .tbl_filter (function (file )
301- return file .ft ~= nil
302- end , files )
324+ files = vim .tbl_filter (
325+ function (file )
326+ return file .ft ~= nil
327+ end ,
328+ vim .tbl_map (function (file )
329+ return {
330+ name = utils .filepath (file ),
331+ ft = utils .filetype (file ),
332+ }
333+ end , files )
334+ )
303335
304336 for _ , file in ipairs (files ) do
305- local content = utils .read_file (file .name )
306- if content then
307- table.insert (out , {
308- content = content ,
309- filename = file .name ,
310- filetype = file .ft ,
311- })
337+ local file_data = get_file (file .name , file .ft )
338+ if file_data then
339+ table.insert (out , file_data )
312340 end
313341 end
314342
@@ -338,28 +366,20 @@ end
338366
339367--- Get the content of a file
340368--- @param filename string
341- --- @return CopilotChat.copilot .embed ?
369+ --- @return CopilotChat.context .embed ?
342370function M .file (filename )
343- local content = utils .read_file (filename )
344- if not content then
345- return nil
346- end
347-
348371 async .util .scheduler ()
349- if not utils .filetype (filename ) then
372+ local ft = utils .filetype (filename )
373+ if not ft then
350374 return nil
351375 end
352376
353- return {
354- content = content ,
355- filename = utils .filepath (filename ),
356- filetype = utils .filetype (filename ),
357- }
377+ return get_file (utils .filepath (filename ), ft )
358378end
359379
360380--- Get the content of a buffer
361381--- @param bufnr ? number
362- --- @return CopilotChat.copilot .embed ?
382+ --- @return CopilotChat.context .embed ?
363383function M .buffer (bufnr )
364384 async .util .scheduler ()
365385 bufnr = bufnr or vim .api .nvim_get_current_buf ()
@@ -373,17 +393,17 @@ function M.buffer(bufnr)
373393 return nil
374394 end
375395
376- return {
377- content = table.concat (content , ' \n ' ),
378- filename = utils .filepath (vim .api .nvim_buf_get_name (bufnr )),
379- filetype = vim .bo [bufnr ].filetype ,
380- }
396+ return build_outline (
397+ table.concat (content , ' \n ' ),
398+ utils .filepath (vim .api .nvim_buf_get_name (bufnr )),
399+ vim .bo [bufnr ].filetype
400+ )
381401end
382402
383403--- Get current git diff
384404--- @param type string ?
385405--- @param winnr number
386- --- @return CopilotChat.copilot .embed ?
406+ --- @return CopilotChat.context .embed ?
387407function M .gitdiff (type , winnr )
388408 type = type or ' unstaged'
389409 local cwd = utils .win_cwd (winnr )
411431
412432--- Return contents of specified register
413433--- @param register string ?
414- --- @return CopilotChat.copilot .embed ?
434+ --- @return CopilotChat.context .embed ?
415435function M .register (register )
416436 register = register or ' +'
417437 local lines = vim .fn .getreg (register )
@@ -429,19 +449,14 @@ end
429449--- Filter embeddings based on the query
430450--- @param copilot CopilotChat.Copilot
431451--- @param prompt string
432- --- @param embeddings table<CopilotChat.copilot .embed>
433- --- @return table<CopilotChat.copilot .embed>
452+ --- @param embeddings table<CopilotChat.context .embed>
453+ --- @return table<CopilotChat.context .embed>
434454function M .filter_embeddings (copilot , prompt , embeddings )
435455 -- If we dont need to embed anything, just return directly
436456 if # embeddings < MULTI_FILE_THRESHOLD then
437457 return embeddings
438458 end
439459
440- -- Map embeddings to outlines
441- embeddings = vim .tbl_map (function (embed )
442- return M .outline (embed .content , embed .filename , embed .filetype )
443- end , embeddings )
444-
445460 -- Rank embeddings by symbols
446461 embeddings = data_ranked_by_symbols (prompt , embeddings , TOP_SYMBOLS )
447462 log .debug (' Ranked data:' , # embeddings )
0 commit comments