Skip to content

Commit d082dd5

Browse files
author
troiganto
committed
feat(attach): add config org_attach_dir_relative
This reverts commit 272da8c217455f2fde59411f59e5e51ea44a3125.
1 parent 1b610cd commit d082dd5

File tree

7 files changed

+106
-7
lines changed

7 files changed

+106
-7
lines changed

docs/configuration.org

+13-2
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,16 @@ be inherited.
11681168
The directory where attachments are stored. If this is a relative path, it
11691169
will be interpreted relative to the directory where the Org file lives.
11701170

1171+
*** org_attach_dir_relative
1172+
:PROPERTIES:
1173+
:CUSTOM_ID: org_attach_dir_relative
1174+
:END:
1175+
- Type: =boolean=
1176+
- Default: =false=
1177+
1178+
If =true=, whenever you add a =DIR= property to a headline, it is added as
1179+
a relative path. The default is to only add absolute paths.
1180+
11711181
*** org_attach_auto_tag
11721182
:PROPERTIES:
11731183
:CUSTOM_ID: org_attach_auto_tag
@@ -2996,8 +3006,9 @@ file).
29963006
Attaching a file puts it in a directory associated with the attachment node.
29973007
Based on [[#org_attach_preferred_new_method][org_attach_preferred_new_method]], this either uses the =ID= or
29983008
the =DIR= property. See also [[#org_attach_id_dir][org_attach_id_dir]],
2999-
[[#org_attach_id_to_path_function_list][org_attach_id_to_path_function_list]] and [[#org_attach_use_inheritance][org_attach_use_inheritance]] on how
3000-
to further customize the attachments directory.
3009+
[[#org_attach_dir_relative][org_attach_dir_relative]], [[#org_attach_id_to_path_function_list][org_attach_id_to_path_function_list]] and
3010+
[[#org_attach_use_inheritance][org_attach_use_inheritance]] on how to further customize the attachments
3011+
directory.
30013012

30023013
Attachment links are supported. A link like =[[attachment:file.txt]]=
30033014
looks up =file.txt= in the current node's attachments directory and opens

lua/orgmode/attach/core.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ end
254254
---Set the DIR node property and ask to move files there.
255255
---
256256
---The property defines the directory that is used for attachments
257-
---of the entry.
257+
---of the entry. Creates relative links if `org_attach_dir_relative'
258+
---is true.
258259
---
259260
---@param node OrgAttachNode
260261
---@param new_dir string

lua/orgmode/attach/init.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@ end
270270
---Set the DIR node property and ask to move files there.
271271
---
272272
---The property defines the directory that is used for attachments
273-
---of the entry.
273+
---of the entry. Creates relative links if `org_attach_dir_relative'
274+
---is true.
274275
---
275276
---@param node? OrgAttachNode
276277
---@return string | nil new_dir

lua/orgmode/attach/node.lua

+7-3
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,19 @@ end
178178

179179
---Set the attachment directory on the current node.
180180
---
181-
---In addition to `set_property()`, this also ensures that the path is always
182-
---absolute.
181+
---In addition to `set_property()`, this also adjusts the path to be relative,
182+
---if required by `org_attach_dir_relative`.
183183
---
184184
---@param dir string
185185
---@return string new_dir absolute attachment directory
186186
---@overload fun(): nil
187187
function AttachNode:set_dir(dir)
188188
if dir then
189-
dir = vim.fn.fnamemodify(dir, ':p')
189+
if config.org_attach_dir_relative then
190+
dir = fs_utils.make_relative(dir, vim.fs.dirname(self.file.filename))
191+
else
192+
dir = vim.fn.fnamemodify(dir, ':p')
193+
end
190194
end
191195
self:set_property('DIR', dir)
192196
return dir and self:_make_absolute(dir)

lua/orgmode/config/defaults.lua

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ local DefaultConfig = {
7272
[':noweb'] = 'no',
7373
},
7474
org_attach_id_dir = './data/',
75+
org_attach_dir_relative = false,
7576
org_attach_auto_tag = 'ATTACH',
7677
org_attach_preferred_new_method = 'id',
7778
org_attach_method = 'cp',

lua/orgmode/utils/fs.lua

+33
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,37 @@ function M.trim_common_root(paths)
6464
return result
6565
end
6666

67+
---@param filepath string an absolute path
68+
---@param base string an absolute path to an ancestor of filepath;
69+
--- here, `'.'` represents the current working directory, and
70+
--- *not* the current file's directory.
71+
---@return string filepath_relative_to_base
72+
function M.make_relative(filepath, base)
73+
vim.validate({
74+
filepath = { filepath, 'string', false },
75+
base = { base, 'string', false },
76+
})
77+
filepath = vim.fn.fnamemodify(filepath, ':p')
78+
base = vim.fn.fnamemodify(base, ':p')
79+
if base:sub(-1) ~= '/' then
80+
base = base .. '/'
81+
end
82+
local levels_up = 0
83+
for parent in vim.fs.parents(base) do
84+
if parent:sub(-1) ~= '/' then
85+
parent = parent .. '/'
86+
end
87+
if vim.startswith(filepath, parent) then
88+
filepath = filepath:sub(parent:len() + 1)
89+
if levels_up > 0 then
90+
return vim.fs.joinpath(string.rep('..', levels_up, '/'), filepath)
91+
end
92+
return vim.fs.joinpath('.', filepath)
93+
end
94+
levels_up = levels_up + 1
95+
end
96+
-- No common root, just return the absolute path.
97+
return filepath
98+
end
99+
67100
return M

tests/plenary/utils/fs_spec.lua

+48
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,51 @@ describe('get_real_path', function()
8686
assert.is.False(fs_utils.get_real_path('.'))
8787
end)
8888
end)
89+
90+
describe('make_relative', function()
91+
local path = fs_utils.get_real_path(file.filename) ---@cast path string
92+
local basename = vim.fs.basename(path)
93+
local dirname = vim.fs.dirname(path)
94+
local dirname_slash = vim.fs.joinpath(dirname, '')
95+
local root = path
96+
for parent in vim.fs.parents(path) do
97+
root = parent
98+
end
99+
100+
it('gets the basename', function()
101+
local expected = vim.fs.joinpath('.', basename)
102+
local actual = fs_utils.make_relative(path, dirname)
103+
assert.are.same(expected, actual)
104+
end)
105+
106+
it('gets the basename with trailing slash', function()
107+
local expected = vim.fs.joinpath('.', basename)
108+
local actual = fs_utils.make_relative(path, dirname_slash)
109+
assert.are.same(expected, actual)
110+
end)
111+
112+
it('works one level up', function()
113+
local parent_name = vim.fs.basename(dirname)
114+
local expected = vim.fs.joinpath('.', parent_name, basename)
115+
local actual = fs_utils.make_relative(path, vim.fs.dirname(dirname))
116+
assert.are.same(expected, actual)
117+
end)
118+
119+
it('works one level up with trailing slash', function()
120+
local parent_name = vim.fs.basename(dirname)
121+
local expected = vim.fs.joinpath('.', parent_name, basename)
122+
local actual = fs_utils.make_relative(path, vim.fs.dirname(dirname) .. '/')
123+
assert.are.same(expected, actual)
124+
end)
125+
126+
it('produces a relative path even at the root', function()
127+
local relpath = fs_utils.make_relative(path, root)
128+
assert(vim.endswith(path, relpath))
129+
end)
130+
131+
it('climbs up via ..', function()
132+
local relpath = fs_utils.make_relative(root, path)
133+
local only_cdup = vim.regex('\\V\\(../\\)\\+')
134+
assert(only_cdup:match_str(relpath))
135+
end)
136+
end)

0 commit comments

Comments
 (0)