diff --git a/lua/orgmode/org/hyperlinks/init.lua b/lua/orgmode/org/hyperlinks/init.lua index 2dc6a5d7a..a1e163d3b 100644 --- a/lua/orgmode/org/hyperlinks/init.lua +++ b/lua/orgmode/org/hyperlinks/init.lua @@ -24,20 +24,13 @@ function Hyperlinks.find_by_filepath(url) return {} end --TODO integrate with orgmode.utils.fs or orgmode.objects.url - local file_base_no_start_path = vim.pesc(file_base:gsub('^%./', '') .. '') - local is_relative_path = file_base:match('^%./') - local current_file_directory = vim.pesc(fs.get_current_file_dir()) local valid_filenames = {} for _, f in ipairs(filenames) do - if is_relative_path then - local match = f:match('^' .. current_file_directory .. '/(' .. file_base_no_start_path .. '.*%.org)$') - if match then - table.insert(valid_filenames, './' .. match) - end - else - if f:find('^' .. file_base) then - table.insert(valid_filenames, f) + if f:find('^' .. file_base) then + if url.realpath then + f = f:gsub(file_base, url.path) end + table.insert(valid_filenames, f) end end diff --git a/lua/orgmode/org/hyperlinks/url.lua b/lua/orgmode/org/hyperlinks/url.lua index f1bc5c3b6..cc7ea900e 100644 --- a/lua/orgmode/org/hyperlinks/url.lua +++ b/lua/orgmode/org/hyperlinks/url.lua @@ -1,3 +1,4 @@ +local fs = require('orgmode.utils.fs') ---@alias OrgUrlPathType 'file' | 'headline' | 'custom-id' | 'id' | 'external-url' | 'plain' | nil ---@alias OrgUrlTargetType 'headline' | 'custom-id' | 'line-number' | 'unknown' | nil @@ -116,7 +117,7 @@ function Url:get_file() if not self:is_file() then return nil end - return self.path + return self.realpath or self.path end ---@return string | nil @@ -246,8 +247,12 @@ function Url:_parse_path_type() return end - if first_char == '.' and (self.path:sub(1, 3) == '../' or self.path:sub(1, 2) == './') then + if + (first_char == '.' and (self.path:sub(1, 3) == '../' or self.path:sub(1, 2) == './')) + or (first_char == '~' and self.path:sub(2, 2) == '/') + then self.path_type = 'file' + self.realpath = fs.get_real_path(self.path) or self.path return end diff --git a/lua/orgmode/utils/fs.lua b/lua/orgmode/utils/fs.lua index cf2329e8d..a131773b7 100644 --- a/lua/orgmode/utils/fs.lua +++ b/lua/orgmode/utils/fs.lua @@ -30,6 +30,10 @@ function M.get_real_path(filepath) return false end local real = vim.loop.fs_realpath(substituted) + if filepath:sub(-1, -1) == '/' then + -- make sure if filepath gets a trailing slash, the realpath gets one, too. + real = real .. '/' + end return real or false end diff --git a/tests/plenary/helpers.lua b/tests/plenary/helpers.lua index 3f7ca69f8..9df05d9f8 100644 --- a/tests/plenary/helpers.lua +++ b/tests/plenary/helpers.lua @@ -35,8 +35,38 @@ local function create_file_instance(lines, filename) return file end +---@return table +local function create_agenda_files(filenames, contents) + -- NOTE: content is only 1 line for 1 file + local temp_fname = vim.fn.tempname() + local temp_dir = vim.fn.fnamemodify(temp_fname, ':p:h') + -- clear temp dir + vim.fn.delete(temp_dir .. '/*', 'rf') + local files = {} + local agenda_files = {} + for i, filename in ipairs(filenames) do + local fname = temp_dir .. '/' .. filename + fname = vim.fn.fnamemodify(fname, ':p') + if fname then + local dir = vim.fn.fnamemodify(fname, ':p:h') + vim.fn.mkdir(dir, 'p') + vim.fn.writefile({ contents[i] }, fname) + files[filename] = fname + table.insert(agenda_files, fname) + end + end + local cfg = vim.tbl_extend('force', { + org_agenda_files = agenda_files, + }, {}) + local org = orgmode.setup(cfg) + org:init() + return files +end + return { + load_file = load_file, create_file = create_file, create_file_instance = create_file_instance, create_agenda_file = create_agenda_file, + create_agenda_files = create_agenda_files, } diff --git a/tests/plenary/org/autocompletion_spec.lua b/tests/plenary/org/autocompletion_spec.lua index c04bc1556..4465eaa90 100644 --- a/tests/plenary/org/autocompletion_spec.lua +++ b/tests/plenary/org/autocompletion_spec.lua @@ -339,6 +339,39 @@ describe('Autocompletion', function() { menu = '[Org]', word = 'Title without anchor' }, }, result) end) + + it('should work on relative paths', function() + local files = helpers.create_agenda_files({ + 'a.org', + 'b/c.org', + }, { + '[[./ ', + '[[../ ', + }) + helpers.load_file(files['b/c.org']) + vim.fn.cursor({ 1, 6 }) + + assert.are.same({ + { menu = '[Org]', word = '../a.org' }, + { menu = '[Org]', word = '../b/c.org' }, + }, org.completion:omnifunc(0, '../')) + end) + it('should work on relative paths', function() + local files = helpers.create_agenda_files({ + 'a.org', + 'b/c.org', + }, { + '[[./ ', + '[[../ ', + }) + helpers.load_file(files['a.org']) + vim.fn.cursor({ 1, 5 }) + + assert.are.same({ + { menu = '[Org]', word = './a.org' }, + { menu = '[Org]', word = './b/c.org' }, + }, org.completion:omnifunc(0, './')) + end) end) end) end)