Skip to content

Commit 7a22f74

Browse files
fix(treesitter): Allow tree-sitter grammar installation outside of orgmode folder
1 parent 15d66ea commit 7a22f74

File tree

2 files changed

+96
-65
lines changed

2 files changed

+96
-65
lines changed

lua/orgmode/health.lua

+12-15
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,25 @@ function M.check_has_treesitter()
1616
return h.error('Treesitter grammar is not installed. Run `:Org install_treesitter_grammar` to install it.')
1717
end
1818

19-
if not version_info.install_location then
19+
if #version_info.parser_locations > 1 then
2020
local list = vim.tbl_map(function(parser)
2121
return ('- `%s`'):format(parser)
22-
end, version_info.conflicting_parsers)
23-
return h.error(
24-
('Installed org parser found in incorrect location. Run `:Org install_treesitter_grammar` to install it in correct location and remove the conflicting parsers from these locations:\n%s'):format(
22+
end, version_info.parser_locations)
23+
return h.warn(
24+
('Multiple org parsers found in these locations:\n%s\nDelete unused ones to avoid conflicts.'):format(
2525
table.concat(list, '\n')
2626
)
2727
)
2828
end
2929

30+
if not version_info.installed_in_orgmode_dir then
31+
return h.ok(
32+
('Tree-sitter grammar is installed, but not by nvim-orgmode plugin. Any issues or version mismatch will need to be handled manually.\nIf you want nvim-orgmode to manage the parser installation (recommended), remove the installed parser at "%s" and restart Neovim.'):format(
33+
version_info.parser_locations[1]
34+
)
35+
)
36+
end
37+
3038
if version_info.outdated then
3139
return h.error('Treesitter grammar is out of date. Run `:Org install_treesitter_grammar` to update it.')
3240
end
@@ -40,17 +48,6 @@ function M.check_has_treesitter()
4048
)
4149
end
4250

43-
if #version_info.conflicting_parsers > 0 then
44-
local list = vim.tbl_map(function(parser)
45-
return ('- `%s`'):format(parser)
46-
end, version_info.conflicting_parsers)
47-
return h.warn(
48-
('Conflicting org parser(s) found in these locations:\n%s\nRemove them to avoid conflicts.'):format(
49-
table.concat(list, '\n')
50-
)
51-
)
52-
end
53-
5451
return h.ok(('Treesitter grammar installed (version %s)'):format(version_info.installed_version))
5552
end
5653

lua/orgmode/utils/treesitter/install.lua

+84-50
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ local required_version = '2.0.0'
99

1010
function M.install()
1111
local version_info = M.get_version_info()
12+
1213
if not version_info.installed then
1314
return M.run('install')
1415
end
1516

16-
-- Parser found but in invalid location
17-
if not version_info.install_location then
18-
local result = M.run('install')
19-
M.notify_conflicting_parsers(version_info.conflicting_parsers)
20-
return result
17+
if #version_info.parser_locations > 1 then
18+
M.notify_conflicting_parsers(version_info.parser_locations)
19+
end
20+
21+
if not version_info.installed_in_orgmode_dir then
22+
return false
2123
end
2224

2325
if version_info.outdated then
@@ -28,26 +30,22 @@ function M.install()
2830
return M.reinstall()
2931
end
3032

31-
M.notify_conflicting_parsers(version_info.conflicting_parsers)
32-
3333
return false
3434
end
3535

3636
function M.notify_conflicting_parsers(conflicting_parsers)
37-
if #conflicting_parsers > 0 then
38-
local list = vim.tbl_map(function(parser)
39-
return ('- `%s`'):format(parser)
40-
end, conflicting_parsers)
41-
utils.notify(
42-
('Conflicting org parser(s) found in these locations:\n%s\nRemove them to avoid conflicts.'):format(
43-
table.concat(list, '\n')
44-
),
45-
{
46-
level = 'warn',
47-
timeout = 5000,
48-
}
49-
)
50-
end
37+
local list = vim.tbl_map(function(parser)
38+
return ('- `%s`'):format(parser)
39+
end, conflicting_parsers)
40+
utils.notify(
41+
('Multiple org parsers found in these locations:\n%s\nDelete unused ones to avoid conflicts.'):format(
42+
table.concat(list, '\n')
43+
),
44+
{
45+
level = 'warn',
46+
timeout = 5000,
47+
}
48+
)
5149
end
5250

5351
function M.reinstall()
@@ -57,13 +55,12 @@ end
5755
function M.get_version_info()
5856
local result = {
5957
installed = false,
60-
correct_location = false,
61-
install_location = nil,
6258
installed_version = nil,
6359
outdated = false,
6460
required_version = required_version,
6561
version_mismatch = false,
66-
conflicting_parsers = {},
62+
parser_locations = {},
63+
installed_in_orgmode_dir = false,
6764
}
6865

6966
if M.not_installed() then
@@ -73,13 +70,8 @@ function M.get_version_info()
7370
result.installed = true
7471

7572
local parser_locations = M.get_parser_locations()
76-
result.conflicting_parsers = parser_locations.conflicting_parsers
77-
78-
if not parser_locations.install_location then
79-
return result
80-
end
81-
82-
result.install_location = parser_locations.install_location
73+
result.parser_locations = parser_locations.parser_locations
74+
result.installed_in_orgmode_dir = parser_locations.installed_in_orgmode_dir
8375

8476
local installed_version = M.get_installed_version()
8577
result.installed_version = installed_version
@@ -90,23 +82,26 @@ function M.get_version_info()
9082
end
9183

9284
function M.get_parser_locations()
93-
local installed_org_parsers = vim.tbl_map(function(item)
94-
return vim.fn.fnamemodify(item, ':p')
95-
end, vim.api.nvim_get_runtime_file('parser/org.so', true))
96-
local parser_path = M.get_parser_path()
97-
local install_location = nil
98-
local conflicting_parsers = {}
99-
for _, parser in ipairs(installed_org_parsers) do
100-
if vim.fs.normalize(parser) == vim.fs.normalize(parser_path) then
101-
install_location = parser
102-
else
103-
table.insert(conflicting_parsers, parser)
85+
local runtime_files = vim.api.nvim_get_runtime_file('parser/org.so', true)
86+
local parser_locations = {}
87+
local valid_paths = {}
88+
for _, runtime_file in ipairs(runtime_files) do
89+
local path = vim.fn.fnamemodify(runtime_file, ':p')
90+
if not valid_paths[path] then
91+
valid_paths[path] = path
92+
table.insert(parser_locations, path)
10493
end
10594
end
10695

96+
local installed_in_orgmode_dir = false
97+
98+
if #parser_locations == 1 and vim.fs.normalize(parser_locations[1]) == vim.fs.normalize(M.get_parser_path()) then
99+
installed_in_orgmode_dir = true
100+
end
101+
107102
return {
108-
install_location = install_location,
109-
conflicting_parsers = conflicting_parsers,
103+
parser_locations = parser_locations,
104+
installed_in_orgmode_dir = installed_in_orgmode_dir,
110105
}
111106
end
112107

@@ -198,6 +193,41 @@ function M.exe(cmd, opts)
198193
end)
199194
end
200195

196+
-- Returns the move command based on the OS
197+
---@param from string
198+
---@param to string
199+
---@param cwd string
200+
---@param is_win boolean
201+
---@param shellslash boolean
202+
function M.select_mv_cmd(from, to, cwd, is_win, shellslash)
203+
if is_win then
204+
local function cmdpath(p)
205+
if shellslash then
206+
local r = p:gsub('/', '\\')
207+
return r
208+
end
209+
return p
210+
end
211+
212+
return {
213+
cmd = 'cmd',
214+
opts = {
215+
args = { '/C', 'move', '/Y', cmdpath(from), cmdpath(to) },
216+
cwd = cwd,
217+
},
218+
}
219+
end
220+
221+
return {
222+
cmd = 'mv',
223+
opts = {
224+
args = { '-f', from, to },
225+
cwd = cwd,
226+
},
227+
}
228+
end
229+
230+
-- Get path to the directory that holds the tree-sitter grammar.
201231
function M.get_path(url, type)
202232
local local_path = vim.fn.expand(url)
203233
local is_local_path = vim.fn.isdirectory(local_path) == 1
@@ -240,12 +270,14 @@ function M.run(type)
240270
end
241271

242272
local compiler_args = M.select_compiler_args(compiler)
243-
local path = nil
273+
local ts_grammar_dir = nil
244274
local lock_file = M.get_lock_file()
275+
local is_win = vim.fn.has('win32') == 1
276+
local shellslash = is_win and vim.opt.shellslash:get() or false
245277

246278
return M.get_path(url, type)
247279
:next(function(directory)
248-
path = directory
280+
ts_grammar_dir = directory
249281
return M.exe(compiler, {
250282
args = compiler_args,
251283
cwd = directory,
@@ -255,10 +287,12 @@ function M.run(type)
255287
if code ~= 0 then
256288
error('[orgmode] Failed to compile parser', 0)
257289
end
258-
local source = vim.fs.joinpath(path, 'parser.so')
259-
local copied, err = vim.uv.fs_copyfile(source, M.get_parser_path())
260-
if not copied then
261-
error('[orgmode] Failed to copy generated tree-sitter parser to runtime folder: ' .. err, 0)
290+
local move_cmd = M.select_mv_cmd('parser.so', M.get_parser_path(), ts_grammar_dir or '', is_win, shellslash)
291+
return M.exe(move_cmd.cmd, move_cmd.opts)
292+
end)
293+
:next(function(code)
294+
if code ~= 0 then
295+
error('[orgmode] Failed to move generated tree-sitter parser to runtime folder', 0)
262296
end
263297
return utils.writefile(lock_file, vim.json.encode({ version = required_version }))
264298
end)

0 commit comments

Comments
 (0)