Skip to content

Commit 27117c7

Browse files
committed
feat(attach): add attachment links
1 parent 43f74e2 commit 27117c7

File tree

3 files changed

+112
-2
lines changed

3 files changed

+112
-2
lines changed

lua/orgmode/attach/core.lua

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ function AttachCore:attach(node, file, opts)
395395
return nil
396396
end
397397
node:toggle_auto_tag(true)
398+
local link = self.links:store_link_to_attachment({ attach_dir = attach_dir, original = file })
399+
vim.fn.setreg(vim.v.register, link)
398400
return basename
399401
end)
400402
end)
@@ -420,6 +422,8 @@ function AttachCore:attach_url(node, url, opts)
420422
return nil
421423
end
422424
node:toggle_auto_tag(true)
425+
local link = self.links:store_link_to_attachment({ attach_dir = attach_dir, original = url })
426+
vim.fn.setreg(vim.v.register, link)
423427
return basename
424428
end)
425429
end)
@@ -445,6 +449,14 @@ function AttachCore:attach_buffer(node, bufnr, opts)
445449
return nil
446450
end
447451
node:toggle_auto_tag(true)
452+
-- Ignore all errors here, this is just to determine whether we can store
453+
-- a link to `bufname`.
454+
local bufname_exists = vim.uv.fs_stat(bufname)
455+
local link = self.links:store_link_to_attachment({
456+
attach_dir = attach_dir,
457+
original = bufname_exists and bufname or attach_file,
458+
})
459+
vim.fn.setreg(vim.v.register, link)
448460
return basename
449461
end)
450462
end)
@@ -472,7 +484,10 @@ function AttachCore:attach_many(node, files, opts)
472484
.mapSeries(function(to_be_attached)
473485
local basename = basename_safe(to_be_attached)
474486
local attach_file = vim.fs.joinpath(attach_dir, basename)
475-
return attach(to_be_attached, attach_file)
487+
return attach(to_be_attached, attach_file):next(function(success)
488+
self.links:store_link_to_attachment({ attach_dir = attach_dir, original = to_be_attached })
489+
return success
490+
end)
476491
end, files)
477492
---@param successes boolean[]
478493
: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)