Skip to content

Commit 7a54a50

Browse files
committed
feat(attach): add attachment links
1 parent 00c29b8 commit 7a54a50

File tree

3 files changed

+110
-2
lines changed

3 files changed

+110
-2
lines changed

lua/orgmode/attach/core.lua

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ function AttachCore:attach(node, file, opts)
429429
return nil
430430
end
431431
node:add_auto_tag()
432+
local link = self.links:store_link_to_attachment({ attach_dir = attach_dir, original = file })
433+
vim.fn.setreg(vim.v.register, link)
432434
return basename
433435
end)
434436
end)
@@ -455,6 +457,14 @@ function AttachCore:attach_buffer(node, bufnr, opts)
455457
local data = table.concat(vim.api.nvim_buf_get_lines(bufnr, 0, -1, false), '\n')
456458
return utils.writefile(attach_file, data, { excl = true }):next(function()
457459
node:add_auto_tag()
460+
-- Ignore all errors here, this is just to determine whether we can store
461+
-- a link to `bufname`.
462+
local bufname_exists = vim.uv.fs_stat(bufname)
463+
local link = self.links:store_link_to_attachment({
464+
attach_dir = attach_dir,
465+
original = bufname_exists and bufname or attach_file,
466+
})
467+
vim.fn.setreg(vim.v.register, link)
458468
return basename
459469
end)
460470
end)
@@ -482,7 +492,10 @@ function AttachCore:attach_many(node, files, opts)
482492
.mapSeries(function(to_be_attached)
483493
local basename = basename_safe(to_be_attached)
484494
local attach_file = vim.fs.joinpath(attach_dir, basename)
485-
return attach(to_be_attached, attach_file)
495+
return attach(to_be_attached, attach_file):next(function(success)
496+
self.links:store_link_to_attachment({ attach_dir = attach_dir, original = to_be_attached })
497+
return success
498+
end)
486499
end, files)
487500
---@param successes boolean[]
488501
:next(function(successes)

lua/orgmode/org/links/init.lua

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,11 @@ function OrgLinks:autocomplete(link)
7676
end
7777

7878
---@param headline OrgHeadline
79+
---@return string url
7980
function OrgLinks:store_link_to_headline(headline)
80-
self.stored_links[self:get_link_to_headline(headline)] = headline:get_title()
81+
local url = self:get_link_to_headline(headline)
82+
self.stored_links[url] = headline:get_title()
83+
return url
8184
end
8285

8386
---@param headline OrgHeadline
@@ -110,6 +113,41 @@ function OrgLinks:get_link_to_file(file)
110113
return ('file:%s::*%s'):format(file.filename, title)
111114
end
112115

116+
---@param params {attach_dir: string, original: string}
117+
---@return string | nil url
118+
function OrgLinks:store_link_to_attachment(params)
119+
local url = self:get_link_to_attachment(params)
120+
if url then
121+
self.stored_links[url] = vim.fs.basename(params.original)
122+
end
123+
return url
124+
end
125+
126+
---@param params {attach_dir: string, original: string}
127+
---@return string | nil url
128+
function OrgLinks:get_link_to_attachment(params)
129+
vim.validate({
130+
attach_dir = { params.attach_dir, 'string' },
131+
original = { params.original, 'string' },
132+
})
133+
local basename = vim.fs.basename(params.original)
134+
local choice = config.org_attach_store_link_p
135+
if choice == 'attached' then
136+
return string.format('attachment:%s', basename)
137+
elseif choice == 'file' then
138+
local attach_file = vim.fs.joinpath(params.attach_dir, basename)
139+
return string.format('file:%s', attach_file)
140+
elseif choice == 'original' then
141+
-- Sanity check: `original` might be a URL. Check for that and return it
142+
-- unmodified if yes.
143+
if params.original:match('^[A-Za-z]+://') then
144+
return params.original
145+
end
146+
return string.format('file:%s', params.original)
147+
end
148+
return nil
149+
end
150+
113151
---@param link_location string
114152
function OrgLinks:insert_link(link_location, desc)
115153
local selected_link = OrgHyperlink:new(link_location)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---@class OrgLinkAttachment:OrgLinkType
2+
---@field private attach OrgAttach
3+
local OrgLinkAttachment = {}
4+
OrgLinkAttachment.__index = OrgLinkAttachment
5+
6+
---@param opts { attach: OrgAttach }
7+
function OrgLinkAttachment:new(opts)
8+
local this = setmetatable({
9+
attach = opts.attach,
10+
}, OrgLinkAttachment)
11+
return this
12+
end
13+
14+
---@return string
15+
function OrgLinkAttachment:get_name()
16+
return 'attachment'
17+
end
18+
19+
---@param link string
20+
---@return boolean
21+
function OrgLinkAttachment:follow(link)
22+
local opts = self:_parse(link)
23+
if not opts then
24+
return false
25+
end
26+
self.attach:open(opts.basename, opts.node)
27+
return true
28+
end
29+
30+
---@param link string
31+
---@return string[]
32+
function OrgLinkAttachment:autocomplete(link)
33+
local opts = self:_parse(link)
34+
if not opts then
35+
return {}
36+
end
37+
local complete = self.attach:make_completion({ node = opts.node })
38+
return vim.tbl_map(function(name)
39+
return 'attachment:' .. name
40+
end, complete(opts.basename))
41+
end
42+
43+
---@private
44+
---@param link string
45+
---@return { node: OrgAttachNode, basename: string } | nil
46+
function OrgLinkAttachment:_parse(link)
47+
local basename = link:match('^attachment:(.+)$')
48+
if not basename then
49+
return nil
50+
end
51+
return {
52+
node = self.attach:get_current_node(),
53+
basename = basename,
54+
}
55+
end
56+
57+
return OrgLinkAttachment

0 commit comments

Comments
 (0)