Skip to content

Commit 4912a8e

Browse files
committed
feat: refresh jdtls build path on new java files
A java file created in-editor isn't on jdtls' build path until the project configuration is refreshed, so go-to-definition returns nothing on it (find-references still works off the search index). Mark buffers created in-editor (BufNewFile, or unsaved file absent on disk when setup runs lazily) and fire java/projectConfigurationUpdate on their first write. Controlled by the update_config_on_new_file option (default on); update_project_config gains bufnr and silent params.
1 parent 15df9eb commit 4912a8e

4 files changed

Lines changed: 62 additions & 4 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ require("jc").setup({
6363
autoformat_on_save = false, -- format java buffers on save
6464
debug_backend = nil, -- "dap" | "vimspector" | nil (auto-detect)
6565
basedir = nil, -- data dir, default ~/.local/share/jc.nvim
66+
update_config_on_new_file = true, -- refresh jdtls build path on new java files
6667
on_attach = nil, -- function(client, bufnr) extra hook
6768
})
6869
```
@@ -71,6 +72,13 @@ The legacy `g:jc_default_mappings`, `g:jc_autoformat_on_save`,
7172
`g:jc_debug_backend` and `g:jc_basedir` variables still work as a
7273
fallback when the corresponding option is not passed to `setup`.
7374

75+
A java file created in-editor isn't on jdtls' build path until the project
76+
configuration is refreshed, so go-to-definition returns nothing on it (while
77+
find-references still works off the search index). With
78+
`update_config_on_new_file` (default `true`), jc.nvim detects such files and
79+
fires `:JCutilUpdateConfig` for them on first write automatically. Set it to
80+
`false` to refresh manually.
81+
7482
## What it adds over plain nvim-jdtls
7583

7684
| Feature | nvim-jdtls | jc.nvim |

doc/jc.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Call `setup` (or use the `opts` table of lazy.nvim): >lua
5858
autoformat_on_save = false, -- format java buffers on save
5959
debug_backend = nil, -- "dap" | "vimspector" | nil = auto
6060
basedir = nil, -- data dir, ~/.local/share/jc.nvim
61+
update_config_on_new_file = true, -- refresh build path on new java files
6162
on_attach = nil, -- function(client, bufnr) extra hook
6263
})
6364
<

lua/jc.lua

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ local user_on_attach = function(_, _) end
55

66
local default_config = {
77
keys_prefix = "<leader>j",
8+
-- refresh the jdtls build path when a java file is created in-editor, so
9+
-- go-to-definition resolves on it without a manual :JCutilUpdateConfig
10+
update_config_on_new_file = true,
811
}
912

1013
-- setup(opts) is the single configuration entry point; these opts are
@@ -56,6 +59,46 @@ function M.setup(args)
5659
end,
5760
})
5861

62+
-- Newly created java files aren't on jdtls' build path until the project
63+
-- configuration is refreshed, so go-to-definition returns nothing on them
64+
-- (find-references still works off the search index). Mark files created
65+
-- in-editor (BufNewFile = path absent on disk) and fire a
66+
-- projectConfigurationUpdate on their first write so gd resolves.
67+
if M.config.update_config_on_new_file ~= false then
68+
vim.api.nvim_create_autocmd("BufNewFile", {
69+
group = group,
70+
pattern = "*.java",
71+
callback = function(a)
72+
vim.b[a.buf].jc_new_java_file = true
73+
end,
74+
})
75+
-- setup may run lazily on FileType, after BufNewFile already fired for the
76+
-- buffer that triggered loading; mark it now if it's an unsaved new file
77+
local cur = vim.api.nvim_get_current_buf()
78+
if vim.bo[cur].filetype == "java" then
79+
local name = vim.api.nvim_buf_get_name(cur)
80+
if name ~= "" and vim.fn.filereadable(name) == 0 then
81+
vim.b[cur].jc_new_java_file = true
82+
end
83+
end
84+
vim.api.nvim_create_autocmd("BufWritePost", {
85+
group = group,
86+
pattern = "*.java",
87+
callback = function(a)
88+
if not vim.b[a.buf].jc_new_java_file then
89+
return
90+
end
91+
vim.b[a.buf].jc_new_java_file = nil
92+
-- defer so jdtls processes didSave before we refresh the build path
93+
vim.defer_fn(function()
94+
if vim.api.nvim_buf_is_valid(a.buf) then
95+
require("jc.jdtls").update_project_config(a.buf, { silent = true })
96+
end
97+
end, 200)
98+
end,
99+
})
100+
end
101+
59102
-- jdtls may already be attached when setup runs (lazy-loaded plugin,
60103
-- session restore) — hook into the existing clients too
61104
for _, client in ipairs(vim.lsp.get_clients({ name = "jdtls" })) do

lua/jc/jdtls.lua

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,20 @@ end
261261
-- jdt.ls declares java/projectConfigurationUpdate as a JsonNotification:
262262
-- there is never a response, so send a notification (nvim-jdtls sends a
263263
-- request and its success therefore looks like "nothing happened")
264-
function M.update_project_config()
264+
function M.update_project_config(bufnr, opts)
265+
bufnr = bufnr or 0
266+
opts = opts or {}
265267
local client = lsp.get_jdtls_client()
266268
if not client then
267-
vim.notify("jc: no jdtls client attached", vim.log.levels.ERROR)
269+
if not opts.silent then
270+
vim.notify("jc: no jdtls client attached", vim.log.levels.ERROR)
271+
end
268272
return
269273
end
270-
client:notify("java/projectConfigurationUpdate", { uri = vim.uri_from_bufnr(0) })
271-
vim.notify("jc: project configuration update requested", vim.log.levels.INFO)
274+
client:notify("java/projectConfigurationUpdate", { uri = vim.uri_from_bufnr(bufnr) })
275+
if not opts.silent then
276+
vim.notify("jc: project configuration update requested", vim.log.levels.INFO)
277+
end
272278
end
273279

274280
local function data_dir_from_args(args)

0 commit comments

Comments
 (0)