@@ -19,7 +19,7 @@ local M = {
1919local function store_client_id (id )
2020 if M .id and M .id ~= id then
2121 if vim .lsp .get_client_by_id (M .id ) then
22- error (" unexpectedly started multiple copilot server " )
22+ error (" unexpectedly started multiple copilot servers " )
2323 end
2424 end
2525
@@ -98,8 +98,22 @@ function M.buf_attach(force)
9898 return
9999 end
100100
101- local client_id = lsp_start (M .config )
102- store_client_id (client_id )
101+ if not M .config then
102+ vim .notify (" [Copilot] Cannot attach: configuration not initialized" , vim .log .levels .ERROR )
103+ return
104+ end
105+
106+ local ok , client_id_or_err = pcall (lsp_start , M .config )
107+ if not ok then
108+ vim .notify (string.format (" [Copilot] Failed to start LSP client: %s" , client_id_or_err ), vim .log .levels .ERROR )
109+ return
110+ end
111+
112+ if client_id_or_err then
113+ store_client_id (client_id_or_err )
114+ else
115+ vim .notify (" [Copilot] LSP client failed to start (no client ID returned)" , vim .log .levels .ERROR )
116+ end
103117end
104118
105119function M .buf_detach ()
@@ -166,8 +180,8 @@ local function prepare_client_config(overrides)
166180 end
167181
168182 local agent_path = vim .api .nvim_get_runtime_file (" copilot/dist/language-server.js" , false )[1 ]
169- if vim .fn .filereadable (agent_path ) == 0 then
170- local err = string.format (" Could not find agent .js (bad install?) : %s" , agent_path )
183+ if not agent_path or vim .fn .filereadable (agent_path ) == 0 then
184+ local err = string.format (" Could not find language-server .js (bad install?) : %s" , tostring ( agent_path ) )
171185 vim .notify (" [Copilot] " .. err , vim .log .levels .ERROR )
172186 M .startup_error = err
173187 return
@@ -179,6 +193,9 @@ local function prepare_client_config(overrides)
179193 capabilities .copilot = {
180194 openURL = true ,
181195 }
196+ capabilities .workspace = {
197+ workspaceFolders = true ,
198+ }
182199
183200 local handlers = {
184201 PanelSolution = api .handlers .PanelSolution ,
@@ -187,13 +204,42 @@ local function prepare_client_config(overrides)
187204 [" copilot/openURL" ] = api .handlers [" copilot/openURL" ],
188205 }
189206
207+ local root_dir = vim .loop .cwd ()
208+ if not root_dir then
209+ root_dir = vim .fn .getcwd ()
210+ end
211+
212+ local workspace_folders = {
213+ --- @type workspace_folder
214+ {
215+ uri = vim .uri_from_fname (root_dir ),
216+ -- important to keep root_dir as-is for the name as lsp.lua uses this to check the workspace has not changed
217+ name = root_dir ,
218+ },
219+ }
220+
221+ local config_workspace_folders = config .get (" workspace_folders" ) --[[ @as table<string>]]
222+
223+ for _ , config_workspace_folder in ipairs (config_workspace_folders ) do
224+ if config_workspace_folder ~= " " then
225+ table.insert (
226+ workspace_folders ,
227+ --- @type workspace_folder
228+ {
229+ uri = vim .uri_from_fname (config_workspace_folder ),
230+ name = config_workspace_folder ,
231+ }
232+ )
233+ end
234+ end
235+
190236 return vim .tbl_deep_extend (" force" , {
191237 cmd = {
192238 node ,
193239 agent_path ,
194- ' --stdio'
240+ " --stdio" ,
195241 },
196- root_dir = vim . loop . cwd () ,
242+ root_dir = root_dir ,
197243 name = " copilot" ,
198244 capabilities = capabilities ,
199245 get_language_id = function (_ , filetype )
@@ -205,8 +251,7 @@ local function prepare_client_config(overrides)
205251 end
206252
207253 vim .schedule (function ()
208- --- @type copilot_set_editor_info_params
209- local set_editor_info_params = util .get_editor_info ()
254+ local set_editor_info_params = util .get_editor_info () --[[ @as copilot_set_editor_info_params]]
210255 set_editor_info_params .editorConfiguration = util .get_editor_configuration ()
211256 set_editor_info_params .networkProxy = util .get_network_proxy ()
212257 local provider_url = config .get (" auth_provider_url" )
@@ -221,7 +266,7 @@ local function prepare_client_config(overrides)
221266 M .initialized = true
222267 end )
223268 end ,
224- on_exit = function (code , _signal , client_id )
269+ on_exit = function (code , _ , client_id )
225270 if M .id == client_id then
226271 vim .schedule (function ()
227272 M .teardown ()
@@ -239,6 +284,7 @@ local function prepare_client_config(overrides)
239284 init_options = {
240285 copilotIntegrationId = " vscode-chat" ,
241286 },
287+ workspace_folders = workspace_folders ,
242288 }, overrides )
243289end
244290
@@ -252,6 +298,7 @@ function M.setup()
252298
253299 is_disabled = false
254300
301+ M .id = nil
255302 vim .api .nvim_create_augroup (M .augroup , { clear = true })
256303
257304 vim .api .nvim_create_autocmd (" FileType" , {
@@ -276,4 +323,54 @@ function M.teardown()
276323 end
277324end
278325
326+ function M .add_workspace_folder (folder_path )
327+ if type (folder_path ) ~= " string" then
328+ vim .notify (" [Copilot] Workspace folder path must be a string" , vim .log .levels .ERROR )
329+ return false
330+ end
331+
332+ if vim .fn .isdirectory (folder_path ) ~= 1 then
333+ vim .notify (" [Copilot] Invalid workspace folder: " .. folder_path , vim .log .levels .ERROR )
334+ return false
335+ end
336+
337+ -- Normalize path
338+ folder_path = vim .fn .fnamemodify (folder_path , " :p" )
339+
340+ --- @type workspace_folder
341+ local workspace_folder = {
342+ uri = vim .uri_from_fname (folder_path ),
343+ name = folder_path ,
344+ }
345+
346+ local workspace_folders = config .get (" workspace_folders" ) --[[ @as table<string>]]
347+ if not workspace_folders then
348+ workspace_folders = {}
349+ end
350+
351+ for _ , existing_folder in ipairs (workspace_folders ) do
352+ if existing_folder == folder_path then
353+ return
354+ end
355+ end
356+
357+ table.insert (workspace_folders , { folder_path })
358+ config .set (" workspace_folders" , workspace_folders )
359+
360+ local client = M .get ()
361+ if client and client .initialized then
362+ client .notify (" workspace/didChangeWorkspaceFolders" , {
363+ event = {
364+ added = { workspace_folder },
365+ removed = {},
366+ },
367+ })
368+ vim .notify (" [Copilot] Added workspace folder: " .. folder_path , vim .log .levels .INFO )
369+ else
370+ vim .notify (" [Copilot] Workspace folder added for next session: " .. folder_path , vim .log .levels .INFO )
371+ end
372+
373+ return true
374+ end
375+
279376return M
0 commit comments