Skip to content

Commit 7e1204c

Browse files
committed
feat: initial support for workspaces
fixes zbirenbaum#375
1 parent 061fd4f commit 7e1204c

File tree

6 files changed

+138
-4
lines changed

6 files changed

+138
-4
lines changed

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This plugin is the pure lua replacement for [github/copilot.vim](https://github.
88
While using `copilot.vim`, for the first time since I started using neovim my laptop began to overheat. Additionally,
99
I found the large chunks of ghost text moving around my code, and interfering with my existing cmp ghost text disturbing.
1010
As lua is far more efficient and makes things easier to integrate with modern plugins, this repository was created.
11+
1112
</details>
1213

1314
## Install
@@ -88,6 +89,7 @@ require('copilot').setup({
8889
},
8990
copilot_node_command = 'node', -- Node.js version must be > 18.x
9091
copilot_model = "", -- Current LSP default is gpt-35-turbo, supports gpt-4o-copilot
92+
workspace_folders = {},
9193
server_opts_overrides = {},
9294
})
9395
```
@@ -111,7 +113,7 @@ require("copilot.panel").refresh()
111113

112114
### suggestion
113115

114-
When `auto_trigger` is `true`, copilot starts suggesting as soon as you enter insert mode.
116+
When `auto_trigger` is `true`, copilot starts suggesting as soon as you enter insert mode.
115117

116118
When `auto_trigger` is `false`, use the `next` or `prev` keymap to trigger copilot suggestion.
117119

@@ -210,6 +212,22 @@ require("copilot").setup {
210212
}
211213
```
212214

215+
### workspace_folders
216+
217+
Workspace folders improve Copilot's suggestions.
218+
By default, the root_dir is used as a wokspace_folder.
219+
220+
Additional folders can be added through the configuration as such:
221+
222+
```lua
223+
workspace_folders = {
224+
"/home/user/gits",
225+
"/home/user/projetsc",
226+
}
227+
```
228+
229+
They can also be added runtime, using the command `:Copilot workspace add [folderpath]` where `[folderpath]` is the workspace folder.
230+
213231
## Commands
214232

215233
`copilot.lua` defines the `:Copilot` command that can perform various actions. It has completion support, so try it out.

lua/copilot/client.lua

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,42 @@ local function prepare_client_config(overrides)
186186
["copilot/openURL"] = api.handlers["copilot/openURL"],
187187
}
188188

189+
local root_dir = vim.loop.cwd()
190+
if not root_dir then
191+
root_dir = vim.fn.getcwd()
192+
end
193+
194+
local workspace_folders = {
195+
--- @type workspace_folder
196+
{
197+
uri = vim.uri_from_fname(root_dir),
198+
-- important to keep root_dir as-is for the name as lsp.lua uses this to check the workspace has not changed
199+
name = root_dir,
200+
},
201+
}
202+
203+
local config_workspace_folders = config.get("workspace_folders") --[[@as table<string>]]
204+
205+
for _, config_workspace_folder in ipairs(config_workspace_folders) do
206+
if config_workspace_folder ~= "" then
207+
table.insert(
208+
workspace_folders,
209+
--- @type workspace_folder
210+
{
211+
uri = vim.uri_from_fname(config_workspace_folder),
212+
name = config_workspace_folder,
213+
}
214+
)
215+
end
216+
end
217+
189218
return vim.tbl_deep_extend("force", {
190219
cmd = {
191220
node,
192221
agent_path,
193222
"--stdio",
194223
},
195-
root_dir = vim.loop.cwd(),
224+
root_dir = root_dir,
196225
name = "copilot",
197226
capabilities = capabilities,
198227
get_language_id = function(_, filetype)
@@ -237,6 +266,7 @@ local function prepare_client_config(overrides)
237266
init_options = {
238267
copilotIntegrationId = "vscode-chat",
239268
},
269+
workspace_folders = workspace_folders,
240270
}, overrides)
241271
end
242272

@@ -250,6 +280,7 @@ function M.setup()
250280

251281
is_disabled = false
252282

283+
M.id = nil
253284
vim.api.nvim_create_augroup(M.augroup, { clear = true })
254285

255286
vim.api.nvim_create_autocmd("FileType", {
@@ -274,4 +305,54 @@ function M.teardown()
274305
end
275306
end
276307

308+
function M.add_workspace_folder(folder_path)
309+
if type(folder_path) ~= "string" then
310+
vim.notify("[Copilot] Workspace folder path must be a string", vim.log.levels.ERROR)
311+
return false
312+
end
313+
314+
if vim.fn.isdirectory(folder_path) ~= 1 then
315+
vim.notify("[Copilot] Invalid workspace folder: " .. folder_path, vim.log.levels.ERROR)
316+
return false
317+
end
318+
319+
-- Normalize path
320+
folder_path = vim.fn.fnamemodify(folder_path, ":p")
321+
322+
--- @type workspace_folder
323+
local workspace_folder = {
324+
uri = vim.uri_from_fname(folder_path),
325+
name = folder_path,
326+
}
327+
328+
local workspace_folders = config.get("workspace_folders") --[[@as table<string>]]
329+
if not workspace_folders then
330+
workspace_folders = {}
331+
end
332+
333+
for _, existing_folder in ipairs(workspace_folders) do
334+
if existing_folder == folder_path then
335+
return
336+
end
337+
end
338+
339+
table.insert(workspace_folders, { folder_path })
340+
config.set("workspace_folders", workspace_folders)
341+
342+
local client = M.get()
343+
if client and client.initialized then
344+
client.notify("workspace/didChangeWorkspaceFolders", {
345+
event = {
346+
added = { workspace_folder },
347+
removed = {},
348+
},
349+
})
350+
vim.notify("[Copilot] Added workspace folder: " .. folder_path, vim.log.levels.INFO)
351+
else
352+
vim.notify("[Copilot] Workspace folder added for next session: " .. folder_path, vim.log.levels.INFO)
353+
end
354+
355+
return true
356+
end
357+
277358
return M

lua/copilot/config.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ local default_config = {
4040
---@type string|nil
4141
auth_provider_url = nil,
4242
copilot_node_command = "node",
43+
---@type string[]
44+
workspace_folders = {},
4345
server_opts_overrides = {},
4446
}
4547

@@ -82,4 +84,14 @@ function mod.get(key)
8284
return mod.config
8385
end
8486

87+
---@param key string
88+
---@param value any
89+
function mod.set(key, value)
90+
if not mod.config then
91+
error("[Copilot] not initialized")
92+
end
93+
94+
mod.config[key] = value
95+
end
96+
8597
return mod

lua/copilot/init.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ local M = { setup_done = false }
22
local config = require("copilot.config")
33
local highlight = require("copilot.highlight")
44

5-
local create_cmds = function ()
5+
local create_cmds = function()
66
vim.api.nvim_create_user_command("CopilotDetach", function()
77
if require("copilot.client").buf_is_attached(0) then
88
vim.deprecate("':CopilotDetach'", "':Copilot detach'", "in future", "copilot.lua")
@@ -15,7 +15,7 @@ local create_cmds = function ()
1515
vim.cmd("Copilot disable")
1616
end, {})
1717

18-
vim.api.nvim_create_user_command("CopilotPanel", function ()
18+
vim.api.nvim_create_user_command("CopilotPanel", function()
1919
vim.deprecate("':CopilotPanel'", "':Copilot panel'", "in future", "copilot.lua")
2020
vim.cmd("Copilot panel")
2121
end, {})

lua/copilot/workspace.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
local mod = {}
2+
---@class workspace_folder
3+
---@field uri string The URI of the workspace folder
4+
---@field name string The name of the workspace folder
5+
function mod.add(opts)
6+
local folder = opts.args
7+
if not folder or folder == "" then
8+
error("Folder is required to add a workspace_folder")
9+
end
10+
11+
folder = vim.fn.fnamemodify(folder, ":p")
12+
13+
require("copilot.client").add_workspace_folder(folder)
14+
end
15+
16+
return mod

plugin/copilot.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local completion_store = {
33
auth = { "signin", "signout" },
44
panel = { "accept", "jump_next", "jump_prev", "open", "refresh" },
55
suggestion = { "accept", "accept_line", "accept_word", "dismiss", "next", "prev", "toggle_auto_trigger" },
6+
workspace = { "add" },
67
}
78

89
vim.api.nvim_create_user_command("Copilot", function(opts)
@@ -42,9 +43,15 @@ vim.api.nvim_create_user_command("Copilot", function(opts)
4243
return
4344
end
4445

46+
local remaining_args = ""
47+
if #params > 2 then
48+
remaining_args = table.concat(params, " ", 3)
49+
end
50+
4551
require("copilot.client").use_client(function()
4652
mod[action_name]({
4753
force = opts.bang,
54+
args = remaining_args,
4855
})
4956
end)
5057
end, {

0 commit comments

Comments
 (0)