Skip to content

Commit ed455cd

Browse files
author
troiganto
committed
feat(attach): add attachment links
1 parent c444981 commit ed455cd

File tree

3 files changed

+112
-2
lines changed

3 files changed

+112
-2
lines changed

lua/orgmode/attach/core.lua

+16-1
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

+39-1
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,11 @@ function OrgLinks:autocomplete(link)
6262
end
6363

6464
---@param headline OrgHeadline
65+
---@return string url
6566
function OrgLinks:store_link_to_headline(headline)
66-
self.stored_links[self:get_link_to_headline(headline)] = headline:get_title()
67+
local url = self:get_link_to_headline(headline)
68+
self.stored_links[url] = headline:get_title()
69+
return url
6770
end
6871

6972
---@param headline OrgHeadline
@@ -96,6 +99,41 @@ function OrgLinks:get_link_to_file(file)
9699
return ('file:%s::*%s'):format(file.filename, title)
97100
end
98101

102+
---@param params {attach_dir: string, original: string}
103+
---@return string | nil url
104+
function OrgLinks:store_link_to_attachment(params)
105+
local url = self:get_link_to_attachment(params)
106+
if url then
107+
self.stored_links[url] = vim.fs.basename(params.original)
108+
end
109+
return url
110+
end
111+
112+
---@param params {attach_dir: string, original: string}
113+
---@return string | nil url
114+
function OrgLinks:get_link_to_attachment(params)
115+
vim.validate({
116+
attach_dir = { params.attach_dir, 'string' },
117+
original = { params.original, 'string' },
118+
})
119+
local basename = vim.fs.basename(params.original)
120+
local choice = config.org_attach_store_link_p
121+
if choice == 'attached' then
122+
return string.format('attachment:%s', basename)
123+
elseif choice == 'file' then
124+
local attach_file = vim.fs.joinpath(params.attach_dir, basename)
125+
return string.format('file:%s', attach_file)
126+
elseif choice == 'original' then
127+
-- Sanity check: `original` might be a URL. Check for that and return it
128+
-- unmodified if yes.
129+
if params.original:match('^[A-Za-z]+://') then
130+
return params.original
131+
end
132+
return string.format('file:%s', params.original)
133+
end
134+
return nil
135+
end
136+
99137
---@param link_location string
100138
function OrgLinks:insert_link(link_location, desc)
101139
local selected_link = OrgHyperlink:new(link_location)
+57
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)