Skip to content

Commit fb50c10

Browse files
authored
Extend API to get links to headline and org file (#768)
* feat(api): Extend API to get links Considers id links, if org-id-link-to-org-use-id is set. Creates ids on file and headline level if needed. * chore: Remove stale require * chore: tiny refactoring to align similar methods Adapt the style of get_link_to_headline to new get_link_to_file - avoid empty declaration of `id` - move initialization of `path` close to it's usage * refactor: make get_link member functions Simplify the code by providing member functions on org.api.file and org.api.headline. * fix: handle unloaded buffers --------- Co-authored-by: Sebastian Flügge <[email protected]>
1 parent 3fc5c6b commit fb50c10

File tree

5 files changed

+108
-6
lines changed

5 files changed

+108
-6
lines changed

lua/orgmode/api/file.lua

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
---@diagnostic disable: invisible
22
local OrgHeadline = require('orgmode.api.headline')
3+
local Hyperlinks = require('orgmode.org.hyperlinks')
4+
local org = require('orgmode')
35

46
---@class OrgApiFile
57
---@field category string current file category name. By default it's only filename without extension unless defined differently via #+CATEGORY directive
@@ -92,4 +94,30 @@ function OrgFile:get_closest_headline(cursor)
9294
return nil
9395
end
9496

97+
--- Get a link destination as string
98+
---
99+
--- Depending if org_id_link_to_org_use_id is set the format is
100+
---
101+
--- id:<uuid>::*title and the id is created if not existing
102+
--- or
103+
--- file:<filepath>::*title
104+
---
105+
--- The result is meant to be used as link_location for OrgApi.insert_link.
106+
--- @return string
107+
function OrgFile:get_link()
108+
local filename = self.filename
109+
local bufnr = vim.fn.bufnr(filename)
110+
111+
if bufnr == -1 or not vim.api.nvim_buf_is_loaded(bufnr) then
112+
-- do remote edit
113+
return org.files
114+
:update_file(filename, function(file)
115+
return Hyperlinks.get_link_to_file(file)
116+
end)
117+
:wait()
118+
end
119+
120+
return Hyperlinks.get_link_to_file(self._file)
121+
end
122+
95123
return OrgFile

lua/orgmode/api/headline.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local PriorityState = require('orgmode.objects.priority_state')
33
local Date = require('orgmode.objects.date')
44
local Calendar = require('orgmode.objects.calendar')
55
local Promise = require('orgmode.utils.promise')
6+
local Hyperlinks = require('orgmode.org.hyperlinks')
67
local org = require('orgmode')
78

89
---@class OrgApiHeadline
@@ -259,4 +260,30 @@ function OrgHeadline:_do_action(action)
259260
end)
260261
end
261262

263+
--- Get a link destination as string
264+
---
265+
--- Depending if org_id_link_to_org_use_id is set the format is
266+
---
267+
--- id:<uuid>::*title and the id is created if not existing
268+
--- or
269+
--- file:<filepath>::*title
270+
---
271+
--- The result is meant to be used as link_location for OrgApi.insert_link.
272+
--- @return string
273+
function OrgHeadline:get_link()
274+
local filename = self.file.filename
275+
local bufnr = vim.fn.bufnr(filename)
276+
277+
if bufnr == -1 or not vim.api.nvim_buf_is_loaded(bufnr) then
278+
-- do remote edit
279+
return org.files
280+
:update_file(filename, function(_)
281+
return Hyperlinks.get_link_to_headline(self._section)
282+
end)
283+
:wait()
284+
end
285+
286+
return Hyperlinks.get_link_to_headline(self._section)
287+
end
288+
262289
return OrgHeadline

lua/orgmode/api/init.lua

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
local OrgFile = require('orgmode.api.file')
33
local OrgHeadline = require('orgmode.api.headline')
44
local Hyperlinks = require('orgmode.org.hyperlinks')
5-
local Link = require('orgmode.org.hyperlinks.link')
65
local orgmode = require('orgmode')
76

87
---@class OrgApiRefileOpts
@@ -102,6 +101,12 @@ function OrgApi.refile(opts)
102101
end
103102

104103
--- Insert a link to a given location at the current cursor position
104+
---
105+
--- The expected format is
106+
--- <protocol>:<location>::<in_file_location>
107+
---
108+
--- If <in_file_location> is *<headline>, <headline> is used as prefilled description for the link.
109+
--- If <protocol> is id, this format can also be used to pass a prefilled description.
105110
--- @param link_location string
106111
--- @return boolean
107112
function OrgApi.insert_link(link_location)

lua/orgmode/files/file.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ end
669669

670670
memoize('get_category')
671671
--- Get the category name for this file
672+
--- If no category is set, the filename without extension is returned
672673
--- @return string
673674
function OrgFile:get_category()
674675
local category = self:_get_directive('category')
@@ -679,6 +680,19 @@ function OrgFile:get_category()
679680
return vim.fn.fnamemodify(self.filename, ':t:r') or ''
680681
end
681682

683+
memoize('get_title')
684+
--- Get the title for this file
685+
--- If no title is set, the filename without extension is returned
686+
--- @return string
687+
function OrgFile:get_title()
688+
local title = self:_get_directive('title')
689+
if title then
690+
return title
691+
end
692+
693+
return vim.fn.fnamemodify(self.filename, ':t:r') or ''
694+
end
695+
682696
memoize('get_opened_unfinished_headlines')
683697
---@return OrgHeadline[]
684698
function OrgFile:get_opened_unfinished_headlines()
@@ -729,6 +743,18 @@ function OrgFile:get_directive(directive_name)
729743
return self:_get_directive(directive_name)
730744
end
731745

746+
--- Get headline id or create a new one if it doesn't exist
747+
--- @return string
748+
function OrgFile:id_get_or_create()
749+
local id = self:get_property('id')
750+
if id then
751+
return id
752+
end
753+
local org_id = require('orgmode.org.id').new()
754+
self:set_property('ID', org_id)
755+
return org_id
756+
end
757+
732758
---@private
733759
---@return string | nil
734760
function OrgFile:_get_directive(directive_name)

lua/orgmode/org/hyperlinks/init.lua

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,32 @@ end
174174
---@param headline OrgHeadline
175175
---@param path? string
176176
function Hyperlinks.get_link_to_headline(headline, path)
177-
path = path or utils.current_file_path()
178177
local title = headline:get_title()
179-
local id
178+
180179
if config.org_id_link_to_org_use_id then
181-
id = headline:id_get_or_create()
180+
local id = headline:id_get_or_create()
181+
if id then
182+
return ('id:%s::*%s'):format(id, title)
183+
end
182184
end
183185

184-
if config.org_id_link_to_org_use_id and id then
185-
return ('id:%s::*%s'):format(id, title)
186+
path = path or utils.current_file_path()
187+
return ('file:%s::*%s'):format(path, title)
188+
end
189+
190+
---@param file OrgFile
191+
---@param path? string
192+
function Hyperlinks.get_link_to_file(file, path)
193+
local title = file:get_title()
194+
195+
if config.org_id_link_to_org_use_id then
196+
local id = file:id_get_or_create()
197+
if id then
198+
return ('id:%s::*%s'):format(id, title)
199+
end
186200
end
201+
202+
path = path or file.filename
187203
return ('file:%s::*%s'):format(path, title)
188204
end
189205

0 commit comments

Comments
 (0)