Skip to content

Commit f96d8e6

Browse files
committed
feat: ability to switch between js (default) and binary server type
1 parent 3e7a5c2 commit f96d8e6

File tree

6 files changed

+174
-14
lines changed

6 files changed

+174
-14
lines changed

README.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ require('copilot').setup({
110110
trace_lsp_progress = false,
111111
log_lsp_messages = false,
112112
},
113-
copilot_node_command = 'node', -- Node.js version must be > 18.x
113+
copilot_node_command = 'node', -- Node.js version must be > 20
114114
workspace_folders = {},
115115
copilot_model = "", -- Current LSP default is gpt-35-turbo, supports gpt-4o-copilot
116116
root_dir = function()
@@ -129,7 +129,10 @@ require('copilot').setup({
129129

130130
return true
131131
end,
132-
lsp_binary = nil,
132+
server = {
133+
type = "nodejs", -- "nodejs" | "binary"
134+
custom_server_filepath = nil,
135+
},
133136
server_opts_overrides = {},
134137
})
135138
```
@@ -280,6 +283,16 @@ When `log_lsp_messages` is true, LSP log messages (`window/logMessage`) events w
280283

281284
Careful turning on all logging features as the log files may get very large over time, and are not pruned by the application.
282285

286+
### copilot_node_command
287+
288+
Use this field to provide the path to a specific node version such as one installed by nvm. Node.js version must be 20 or newer.
289+
290+
Example:
291+
292+
```lua
293+
copilot_node_command = vim.fn.expand("$HOME") .. "/.config/nvm/versions/node/v20.0.1/bin/node", -- Node.js version must be > 20
294+
```
295+
283296
### server_opts_overrides
284297

285298
Override copilot lsp client settings. The `settings` field is where you can set the values of the options defined in [SettingsOpts.md](./SettingsOpts.md).
@@ -344,15 +357,22 @@ require("copilot").setup {
344357
}
345358
```
346359

347-
### lsp_binary
360+
### server
361+
362+
> [!CAUTION] > `"binary"` mode is still very much experimental, please report any issues you encounter.
348363
349-
This allows you to specify the path to the copilot lsp binary.
350-
This will disable the download of the binary and use the one specified.
364+
`type` can be either `"nodejs"` or `"binary"`. The binary version will be downloaded if used.
365+
366+
`custom_server_filepath` is used to specify the path of either the path (filename included) of the `js` file if using `"nodejs"` or the path to the binary if using `"binary"`.
367+
When using `"binary"`, the download process will be disabled and the binary will be used directly.
351368
example:
352369

353370
```lua
354371
require("copilot").setup {
355-
lsp_binary = "/home/user/.local/bin/copilot-language-server",
372+
server = {
373+
type = "nodejs",
374+
custom_server_filepath = "/home/user/copilot-lsp/language-server.js",,
375+
},
356376
}
357377
```
358378

lua/copilot/client.lua

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local config = require("copilot.config")
33
local util = require("copilot.util")
44
local logger = require("copilot.logger")
55
local lsp_binary = require("copilot.lsp_binary")
6+
local lsp_nodesj = require("copilot.lsp_nodejs")
67

78
local is_disabled = false
89

@@ -18,6 +19,14 @@ local M = {
1819
initialized = false,
1920
---@type copilot_should_attach
2021
should_attach = nil,
22+
---@type string<'nodejs', 'binary'>
23+
---@class copilot_config_server
24+
server = {
25+
---@type string<'nodejs', 'binary'>
26+
type = "nodejs",
27+
---@type string|nil
28+
custom_server_filepath = nil,
29+
},
2130
}
2231

2332
---@param id integer
@@ -195,14 +204,25 @@ end
195204

196205
local function prepare_client_config(overrides)
197206
if lsp_binary.initialization_failed then
198-
M.startup_error = "initializatino of copilot-language-server failed"
207+
M.startup_error = "initialization of copilot-language-server failed"
199208
return
200209
end
201210

202-
local server_path = lsp_binary.get_copilot_server_info().absolute_filepath
203-
204211
M.startup_error = nil
205212

213+
local server_path = nil
214+
local node_cmd = ""
215+
if M.server.type == "nodejs" then
216+
node_cmd = lsp_nodesj.node_command
217+
server_path = lsp_nodesj.get_server_path()
218+
elseif M.server.type == "binary" then
219+
server_path = lsp_binary.get_server_path()
220+
end
221+
222+
if M.server.custom_server_filepath and vim.fn.filereadable(M.server.custom_server_filepath) then
223+
server_path = M.server.custom_server_filepath
224+
end
225+
206226
local capabilities = vim.lsp.protocol.make_client_capabilities() --[[@as copilot_capabilities]]
207227
capabilities.window.showDocument.support = true
208228

@@ -266,6 +286,7 @@ local function prepare_client_config(overrides)
266286
-- LSP config, not to be confused with config.lua
267287
return vim.tbl_deep_extend("force", {
268288
cmd = {
289+
node_cmd,
269290
server_path,
270291
"--stdio",
271292
},
@@ -310,7 +331,6 @@ local function prepare_client_config(overrides)
310331
end,
311332
handlers = get_handlers(),
312333
init_options = {
313-
copilotIntegrationId = "vscode-chat", -- can be safely removed with copilot v1.291
314334
editorInfo = editor_info.editorInfo,
315335
editorPluginInfo = editor_info.editorPluginInfo,
316336
},
@@ -321,8 +341,15 @@ local function prepare_client_config(overrides)
321341
end
322342

323343
function M.setup()
324-
M.config = prepare_client_config(config.get("server_opts_overrides"))
325344
M.should_attach = config.get("should_attach") --[[@as copilot_should_attach|nil]]
345+
local server_config = config.get("server") --[[@as copilot_config_server]]
346+
local node_command = config.get("copilot_node_command") --[[@as string|nil]]
347+
M.server = vim.tbl_deep_extend("force", M.server, server_config)
348+
if M.server.type == "nodejs" then
349+
lsp_nodesj.setup(node_command, M.server.custom_server_filepath)
350+
end
351+
352+
M.config = prepare_client_config(config.get("server_opts_overrides"))
326353

327354
if not M.config then
328355
is_disabled = true

lua/copilot/config.lua

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,14 @@ local default_config = {
7575

7676
return true
7777
end,
78-
---@type string|nil
79-
lsp_binary = nil,
78+
copilot_node_command = "node",
79+
---@class copilot_config_server
80+
server = {
81+
---@type string<'nodejs', 'binary'>
82+
type = "nodejs",
83+
---@type string|nil
84+
custom_server_filepath = nil,
85+
},
8086
}
8187

8288
local mod = {

lua/copilot/lsp_binary.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,12 @@ function M.get_copilot_server_info()
321321
return M.copilot_server_info
322322
end
323323

324+
---@return string
325+
function M.get_server_path()
326+
return M.get_copilot_server_info().absolute_filepath
327+
end
328+
329+
---@param filepath string|nil
324330
function M.setup(filepath)
325331
if not filepath then
326332
return M

lua/copilot/lsp_nodejs.lua

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
local logger = require("copilot.logger")
2+
3+
local M = {
4+
---@class copilot_nodejs_server_info
5+
---@type string
6+
node_command = nil,
7+
---@type string
8+
server_path = nil,
9+
}
10+
11+
---@return string node_version
12+
---@return nil|string node_version_error
13+
function M.get_node_version()
14+
if not M.node_version then
15+
local cmd = { M.node_command, "--version" }
16+
local cmd_output_table = vim.fn.executable(M.node_command) == 1 and vim.fn.systemlist(cmd, nil, 0) or { "" }
17+
local cmd_output = cmd_output_table[#cmd_output_table]
18+
local cmd_exit_code = vim.v.shell_error
19+
20+
local node_version = string.match(cmd_output, "^v(%S+)") or ""
21+
local node_version_major = tonumber(string.match(node_version, "^(%d+)%.")) or 0
22+
23+
if node_version_major == 0 then
24+
M.node_version_error = table.concat({
25+
"Could not determine Node.js version",
26+
"-----------",
27+
"(exit code) " .. tostring(cmd_exit_code),
28+
" (output) " .. cmd_output,
29+
"-----------",
30+
}, "\n")
31+
elseif node_version_major < 20 then
32+
M.node_version_error = string.format("Node.js version 20 or newer required but found %s", node_version)
33+
end
34+
35+
M.node_version = node_version or ""
36+
end
37+
38+
return M.node_version, M.node_version_error
39+
end
40+
41+
---@return boolean
42+
function M.validate_node_version()
43+
local _, node_version_error = M.get_node_version()
44+
45+
if node_version_error then
46+
logger.error(node_version_error)
47+
return false
48+
end
49+
50+
return true
51+
end
52+
53+
function M.node_exists()
54+
local node_exists = vim.fn.executable(M.node_command) == 1
55+
56+
if not node_exists then
57+
logger.error("node.js is not installed or not in PATH")
58+
return false
59+
end
60+
61+
return true
62+
end
63+
64+
---@param server_path? string
65+
---@return boolean
66+
function M.init_agent_path(server_path)
67+
local agent_path = server_path or vim.api.nvim_get_runtime_file("copilot/js/language-server.js", false)[1]
68+
69+
if not agent_path or vim.fn.filereadable(agent_path) == 0 then
70+
logger.error(string.format("could not find server (bad install?) : %s", tostring(agent_path)))
71+
return false
72+
end
73+
74+
M.server_path = agent_path
75+
return true
76+
end
77+
78+
---@return string|nil
79+
function M.get_server_path()
80+
if not M.server_path then
81+
logger.error("server path is not set")
82+
return nil
83+
end
84+
85+
return M.server_path
86+
end
87+
88+
---@param node_command? string
89+
---@param custom_server_path? string
90+
---@return boolean
91+
function M.setup(node_command, custom_server_path)
92+
M.node_command = node_command or "node"
93+
94+
if not M.node_exists() or not M.validate_node_version() or not M.init_agent_path(custom_server_path) then
95+
return false
96+
end
97+
98+
return true
99+
end
100+
101+
return M

lua/copilot/util.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function M.get_editor_info()
1919
editorPluginInfo = {
2020
name = "copilot.lua",
2121
-- reflects version of github/copilot-language-server-release
22-
version = "1.292.0",
22+
version = "1.294.0",
2323
},
2424
}
2525
return info

0 commit comments

Comments
 (0)