Skip to content

Commit 15df9eb

Browse files
committed
fix: invalidate project path cache on project switch
path.lua cached the first project's dirs forever and settings.lua resolved the workspace dir at module load, so switching projects in one session kept using the first project's paths. Key path.lua's cache by the detected project root and resolve settings paths per call.
1 parent f74562a commit 15df9eb

3 files changed

Lines changed: 74 additions & 15 deletions

File tree

lua/jc/path.lua

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
11
local M = {}
2-
local paths = nil
2+
3+
-- derived dirs are memoized per project root, so switching between
4+
-- projects in one session yields the right paths (the old code cached
5+
-- the first project forever)
6+
local cache = {}
37

48
local function locate_buffer(project_root_file)
59
if vim.fn.filereadable(project_root_file) == 1 then
610
vim.cmd("lcd " .. vim.fn.fnamemodify(project_root_file, ":h"))
711
end
812
end
913

10-
local function find_project_path()
11-
local result = {
14+
local function find_project_path(project_root_file)
15+
local project_name = vim.fn.substitute(project_root_file, "[\\/:;.]", "_", "g")
16+
return {
1217
data_dir = vim.fn["project_root#get_basedir"]("data"),
13-
project_root_file = vim.fn["project_root#find"](),
18+
project_root_file = project_root_file,
19+
workspace_dir = vim.fn["project_root#get_basedir"]("workspaces") .. project_name .. "/",
1420
}
15-
16-
local project_name = vim.fn.substitute(result.project_root_file, "[\\/:;.]", "_", "g")
17-
result.workspace_dir = vim.fn["project_root#get_basedir"]("workspaces") .. project_name .. "/"
18-
return result
1921
end
2022

2123
function M.get_project_dirs()
24+
local project_root_file = vim.fn["project_root#find"]()
25+
local paths = cache[project_root_file]
2226
if not paths then
23-
paths = find_project_path()
27+
paths = find_project_path(project_root_file)
28+
cache[project_root_file] = paths
2429
end
25-
locate_buffer(paths.project_root_file)
30+
locate_buffer(project_root_file)
2631
return paths
2732
end
2833

lua/jc/settings.lua

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
local M = {}
22

3-
local project_name = vim.fn["project_root#get_name"]()
4-
local workspace_dir = vim.fn["project_root#get_basedir"]("workspaces") .. project_name
3+
-- resolved per call: the project (and thus the workspace dir) can change
4+
-- within one session, so this must not be cached at module load
5+
local function project_file(name)
6+
local project_name = vim.fn["project_root#get_name"]()
7+
return vim.fn["project_root#get_basedir"]("workspaces") .. project_name .. "." .. name
8+
end
59

610
function M.read_project(name, default)
711
local result = default
8-
local file_name = workspace_dir .. "." .. name
12+
local file_name = project_file(name)
913
if vim.fn.filereadable(file_name) == 1 then
1014
local file = io.open(file_name)
1115
if file then
@@ -17,8 +21,7 @@ function M.read_project(name, default)
1721
end
1822

1923
function M.write_project(name, value)
20-
local file_name = workspace_dir .. "." .. name
21-
local file = io.open(file_name, "w+")
24+
local file = io.open(project_file(name), "w+")
2225
if file then
2326
file:write(value)
2427
file:close()

tests/jc/path_spec.lua

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
describe("path cache invalidation", function()
2+
local path, settings
3+
4+
-- create a temp dir with a pom.xml so project_root#find resolves it
5+
local function make_project()
6+
local dir = vim.fn.tempname()
7+
vim.fn.mkdir(dir, "p")
8+
vim.fn.writefile({ "<project/>" }, dir .. "/pom.xml")
9+
vim.fn.writefile({ "class A {}" }, dir .. "/A.java")
10+
return dir
11+
end
12+
13+
local root = vim.fn.getcwd()
14+
15+
before_each(function()
16+
-- editing a project file triggers an lcd into it; restore cwd so the
17+
-- relative runtimepath ('.') keeps resolving jc.* modules
18+
vim.cmd("cd " .. root)
19+
vim.g.jc_basedir = vim.fn.tempname()
20+
package.loaded["jc.path"] = nil
21+
package.loaded["jc.settings"] = nil
22+
path = require("jc.path")
23+
settings = require("jc.settings")
24+
end)
25+
26+
it("returns different workspace dirs for different projects", function()
27+
local p1 = make_project()
28+
vim.cmd("edit " .. p1 .. "/A.java")
29+
local ws1 = path.get_workspace_dir()
30+
31+
local p2 = make_project()
32+
vim.cmd("edit " .. p2 .. "/A.java")
33+
local ws2 = path.get_workspace_dir()
34+
35+
assert.are_not.equal(ws1, ws2)
36+
end)
37+
38+
it("settings follow the active project", function()
39+
local p1 = make_project()
40+
vim.cmd("edit " .. p1 .. "/A.java")
41+
settings.write_project("debug-port", "5005")
42+
43+
local p2 = make_project()
44+
vim.cmd("edit " .. p2 .. "/A.java")
45+
-- the second project hasn't stored anything yet
46+
assert.are.equal("9000", settings.read_project("debug-port", "9000"))
47+
48+
vim.cmd("edit " .. p1 .. "/A.java")
49+
assert.are.equal("5005", settings.read_project("debug-port", "9000"))
50+
end)
51+
end)

0 commit comments

Comments
 (0)