Skip to content

Commit

Permalink
feat(links)!: Use refactor links structure (#803)
Browse files Browse the repository at this point in the history
* feat(links)!: Use refactor links structure

* fix(hyperlink): Fix jumping to file

* fix(hyperlink): Do not attempt to search for expression if it's file only path
  • Loading branch information
kristijanhusak authored Sep 18, 2024
1 parent e3500ad commit c5940d3
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 145 deletions.
5 changes: 2 additions & 3 deletions lua/orgmode/api/file.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---@diagnostic disable: invisible
local OrgHeadline = require('orgmode.api.headline')
local Hyperlinks = require('orgmode.org.hyperlinks')
local org = require('orgmode')

---@class OrgApiFile
Expand Down Expand Up @@ -112,12 +111,12 @@ function OrgFile:get_link()
-- do remote edit
return org.files
:update_file(filename, function(file)
return Hyperlinks.get_link_to_file(file)
return org.links:get_link_to_file(file)
end)
:wait()
end

return Hyperlinks.get_link_to_file(self._file)
return org.links:get_link_to_file(self._file)
end

return OrgFile
5 changes: 2 additions & 3 deletions lua/orgmode/api/headline.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ local PriorityState = require('orgmode.objects.priority_state')
local Date = require('orgmode.objects.date')
local Calendar = require('orgmode.objects.calendar')
local Promise = require('orgmode.utils.promise')
local Hyperlinks = require('orgmode.org.hyperlinks')
local org = require('orgmode')

---@class OrgApiHeadline
Expand Down Expand Up @@ -281,12 +280,12 @@ function OrgHeadline:get_link()
-- do remote edit
return org.files
:update_file(filename, function(_)
return Hyperlinks.get_link_to_headline(self._section)
return org.links:get_link_to_headline(self._section)
end)
:wait()
end

return Hyperlinks.get_link_to_headline(self._section)
return org.links:get_link_to_headline(self._section)
end

return OrgHeadline
4 changes: 2 additions & 2 deletions lua/orgmode/api/init.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---@diagnostic disable: invisible
local OrgFile = require('orgmode.api.file')
local OrgHeadline = require('orgmode.api.headline')
local Hyperlinks = require('orgmode.org.hyperlinks')
local orgmode = require('orgmode')

---@class OrgApiRefileOpts
Expand Down Expand Up @@ -110,7 +109,8 @@ end
--- @param link_location string
--- @return boolean
function OrgApi.insert_link(link_location)
Hyperlinks.insert_link(link_location)
orgmode.links:insert_link(link_location)
return true
end

return OrgApi
6 changes: 3 additions & 3 deletions lua/orgmode/files/file.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local Headline = require('orgmode.files.headline')
local ts = vim.treesitter
local config = require('orgmode.config')
local Block = require('orgmode.files.elements.block')
local Link = require('orgmode.org.hyperlinks.link')
local Hyperlink = require('orgmode.org.links.hyperlink')
local Range = require('orgmode.files.elements.range')
local Memoize = require('orgmode.utils.memoize')

Expand Down Expand Up @@ -722,7 +722,7 @@ function OrgFile:get_archive_file_location()
end

memoize('get_links')
---@return OrgLink[]
---@return OrgHyperlink[]
function OrgFile:get_links()
self:parse(true)
local ts_query = ts_utils.get_query([[
Expand All @@ -736,7 +736,7 @@ function OrgFile:get_links()
for _, match in ts_query:iter_captures(self.root, self:_get_source()) do
local line = match:start()
if not processed_lines[line] then
vim.list_extend(links, Link.all_from_line(self.lines[line + 1], line + 1))
vim.list_extend(links, Hyperlink.all_from_line(self.lines[line + 1], line + 1))
processed_lines[line] = true
end
end
Expand Down
7 changes: 2 additions & 5 deletions lua/orgmode/org/autocompletion/sources/hyperlinks.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
local Hyperlinks = require('orgmode.org.hyperlinks')
local Link = require('orgmode.org.hyperlinks.link')
---@class OrgCompletionHyperlinks:OrgCompletionSource
---@field completion OrgCompletion
---@field private pattern vim.regex
Expand All @@ -24,11 +22,10 @@ function OrgCompletionHyperlinks:get_start(context)
return self.pattern:match_str(context.line)
end

---@param context OrgCompletionContext
---@return string[]
function OrgCompletionHyperlinks:get_results(context)
local link = Link:new(context.base)
local result, mapper = Hyperlinks.find_matching_links(link.url)
return mapper(result)
return self.completion.links:autocomplete(context.base)
end

return OrgCompletionHyperlinks
13 changes: 12 additions & 1 deletion lua/orgmode/org/links/types/headline_search.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@ function OrgLinkHeadlineSearch:follow(link)
end

local file = self.files:load_file_sync(opts.file_path)
local is_file_only = opts.type == 'file' and not opts.target

if file then
if is_file_only then
return link_utils.goto_file(file)
end

local pattern = ('<<<?(%s[^>]*)>>>?'):format(opts.headline_text):lower()
local headlines = file:find_headlines_matching_search_term(pattern, true)
if #headlines == 0 then
Expand All @@ -44,7 +49,13 @@ function OrgLinkHeadlineSearch:follow(link)
)
end

return link_utils.open_file_and_search(opts.file_path, opts.headline_text)
local search_text = opts.headline_text

if is_file_only then
search_text = ''
end

return link_utils.open_file_and_search(opts.file_path, search_text)
end

---@param link string
Expand Down
7 changes: 6 additions & 1 deletion lua/orgmode/org/links/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function link_utils.goto_oneof_headlines(headlines, file_path, error_message)
end

---@param file_path string
---@param search_text string
---@param search_text string | nil
---@return boolean
function link_utils.open_file_and_search(file_path, search_text)
if not file_path or file_path == '' then
Expand All @@ -68,6 +68,11 @@ function link_utils.open_file_and_search(file_path, search_text)
if file_path ~= utils.current_file_path() then
vim.cmd(('edit %s'):format(file_path))
end

if not search_text or search_text == '' then
return true
end

local result = vim.fn.search(search_text, 'W')
if result == 0 then
utils.echo_warning(string.format('No match found for expression: %s', search_text))
Expand Down
98 changes: 8 additions & 90 deletions lua/orgmode/org/mappings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local Calendar = require('orgmode.objects.calendar')
local Date = require('orgmode.objects.date')
local EditSpecial = require('orgmode.objects.edit_special')
local Help = require('orgmode.objects.help')
local Hyperlinks = require('orgmode.org.hyperlinks')
local OrgHyperlink = require('orgmode.org.links.hyperlink')
local PriorityState = require('orgmode.objects.priority_state')
local TodoState = require('orgmode.objects.todo_state')
local config = require('orgmode.config')
Expand Down Expand Up @@ -785,18 +785,20 @@ end
-- Inserts a new link after the cursor position or modifies the link the cursor is
-- currently on
function OrgMappings:insert_link()
local link_location = vim.fn.OrgmodeInput('Links: ', '', Hyperlinks.autocomplete_links)
local link_location = vim.fn.OrgmodeInput('Links: ', '', function(arg_lead)
return self.links:autocomplete(arg_lead)
end)
if vim.trim(link_location) == '' then
utils.echo_warning('No Link selected')
return
end

Hyperlinks.insert_link(link_location)
self.links:insert_link(link_location)
end

function OrgMappings:store_link()
local headline = self.files:get_closest_headline()
Hyperlinks.store_link_to_headline(headline)
self.links:store_link_to_headline(headline)
return utils.echo_info('Stored: ' .. headline:get_title())
end

Expand Down Expand Up @@ -861,7 +863,7 @@ function OrgMappings:add_note()
end

function OrgMappings:open_at_point()
local link = Hyperlinks.get_link_under_cursor()
local link = OrgHyperlink.at_cursor()
if not link then
local date = self:_get_date_under_cursor()
if date then
Expand All @@ -870,91 +872,7 @@ function OrgMappings:open_at_point()
return
end

-- handle external links (non-org or without org-specific line target)

if link.url:is_id() then
local id = link.url:get_id() or ''
local files = self.files:find_files_with_property('id', id)
if #files > 0 then
if #files > 1 then
utils.echo_warning(string.format('Multiple files found with id: %s, jumping to first one found', id))
end
vim.cmd(('edit %s'):format(files[1].filename))
return
end

local headlines = self.files:find_headlines_with_property('id', id)
if #headlines == 0 then
return utils.echo_warning(string.format('No headline found with id: %s', id))
end
if #headlines > 1 then
return utils.echo_warning(string.format('Multiple headlines found with id: %s', id))
end
local headline = headlines[1]
return self:_goto_headline(headline)
end

if link.url:is_file_line_number() then
local line_number = link.url:get_line_number() or 0
local file_path = link.url:get_file() or utils.current_file_path()
local cmd = string.format('edit +%s %s', line_number, fs.get_real_path(file_path))
vim.cmd(cmd)
return vim.cmd([[normal! zv]])
end

if link.url:is_external_url() then
if vim.ui['open'] then
return vim.ui.open(link.url:to_string())
end
if not vim.g.loaded_netrwPlugin then
return utils.echo_warning('Netrw plugin must be loaded in order to open urls.')
end
return vim.fn['netrw#BrowseX'](link.url:to_string(), vim.fn['netrw#CheckIfRemote']())
end

if link.url:is_file_only() then
local file_path = link.url:get_file()
local cmd = file_path and string.format('edit %s', fs.get_real_path(file_path)) or ''
vim.cmd(cmd)
vim.cmd([[normal! zv]])
end

if link.url.protocol and not link.url:is_supported_protocol() then
utils.echo_warning(string.format('Unsupported link protocol: %q', link.url.protocol))
return
end

local headlines = Hyperlinks.find_matching_links(link.url)
local current_headline = self.files:get_closest_headline_or_nil()
if current_headline then
headlines = vim.tbl_filter(function(headline)
return not current_headline:is_same(headline)
end, headlines)
end
if #headlines == 0 then
return
end
local headline = headlines[1]
if #headlines > 1 then
local longest_headline = utils.reduce(headlines, function(acc, h)
return math.max(acc, h:get_headline_line_content():len())
end, 0)
local options = {}
for i, h in ipairs(headlines) do
table.insert(
options,
string.format('%d) %-' .. longest_headline .. 's (%s)', i, h:get_headline_line_content(), h.file.filename)
)
end
vim.cmd([[echo "Multiple targets found. Select target:"]])
local choice = vim.fn.inputlist(options)
if choice < 1 or choice > #headlines then
return
end
headline = headlines[choice]
end

return self:_goto_headline(headline)
return self.links:follow(link.url:to_string())
end

function OrgMappings:export()
Expand Down
43 changes: 6 additions & 37 deletions tests/plenary/ui/mappings/hyperlink_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,11 @@ describe('Hyperlink mappings', function()
vim.cmd([[norm ,ols]])
assert.are.same({
[('file:%s::*headline of target id'):format(target_file.filename)] = 'headline of target id',
}, require('orgmode.org.hyperlinks').stored_links)
---@diagnostic disable-next-line: invisible
}, require('orgmode').links.stored_links)
end)

it('should store link to a headline with id', function()
require('orgmode.org.hyperlinks').stored_links = {}
local org = require('orgmode').setup({
org_id_link_to_org_use_id = true,
})
Expand All @@ -123,9 +123,12 @@ describe('Hyperlink mappings', function()
})

org:init()
---@diagnostic disable-next-line: invisible
require('orgmode').links.stored_links = {}
vim.fn.cursor(4, 10)
vim.cmd([[norm ,ols]])
local stored_links = require('orgmode.org.hyperlinks').stored_links
---@diagnostic disable-next-line: invisible
local stored_links = require('orgmode').links.stored_links
local keys = vim.tbl_keys(stored_links)
local values = vim.tbl_values(stored_links)
assert.is.True(keys[1]:match('^id:' .. OrgId.uuid_pattern .. '.*$') ~= nil)
Expand Down Expand Up @@ -207,38 +210,4 @@ describe('Hyperlink mappings', function()
vim.cmd([[norm ,oo]])
assert.is.same(' --> eleven <--', vim.api.nvim_get_current_line())
end)

it('should follow link to certain line (nvim-orgmode compatibility)', function()
local target_file = helpers.create_file({
'* Test hyperlink',
' - some',
' - boiler',
' - plate',
'** some headline',
' - more',
' - boiler',
' - plate',
' -> 9',
' -> 10',
' --> eleven <--',
' -> 12',
' -> 13',
' -> 14',
' -> 15 <--',
})
vim.cmd([[norm w]])
assert.is.truthy(target_file)
if not target_file then
return
end
local dir = vim.fs.dirname(target_file.filename)
local url = target_file.filename:gsub(dir, '.')
helpers.create_file({
string.format('This [[%s +11][link]] should bring us to the 11th line.', url),
})
vim.cmd([[norm w]])
vim.fn.cursor(1, 10)
vim.cmd([[norm ,oo]])
assert.is.same(' --> eleven <--', vim.api.nvim_get_current_line())
end)
end)

0 comments on commit c5940d3

Please sign in to comment.