Skip to content

Commit 0f821b2

Browse files
alecStewart1Alec Stewart
andauthored
feat(capture): have headline in templates take a string or a function that returns a string. (#1133)
Co-authored-by: Alec Stewart <alec-stewart@pm.me>
1 parent b3b58f7 commit 0f821b2

4 files changed

Lines changed: 62 additions & 7 deletions

File tree

docs/configuration.org

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -916,9 +916,10 @@ Templates have the following fields:
916916
- =target= (=string?=) --- name of the file to which the capture content
917917
will be added. If the target is not specified, the content will be
918918
added to the [[#org_default_notes_file][org_default_notes_file]] file
919-
- =headline= (=string?=) --- title of the headline after which the
920-
capture content will be added. If no headline is specified, the
921-
content will be appended to the end of the file
919+
- =headline= (=string|fun():string?=) --- title of the headline after which the
920+
capture content will be added. If a function is provided, it will be called during
921+
refile and must return the headline title as string. If no headline is specified,
922+
the content will be appended to the end of the file
922923
- =datetree (boolean | { time_prompt?: boolean, reversed?: boolean, tree_type: 'day' | 'month' | 'week' | 'custom' })=
923924
Create a [[https://orgmode.org/manual/Template-elements.html#FOOT84][date tree]] with current day in the target file and put the capture content there.
924925
- =true= - Create ascending datetree (newer dates go to end) with the current date

lua/orgmode/capture/init.lua

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,9 +587,23 @@ function Capture:_get_refile_vars(capture_window)
587587

588588
opts.destination_file = self.files:get(file)
589589
if opts.template.headline then
590-
opts.destination_headline = opts.destination_file:find_headline_by_title(opts.template.headline)
590+
local template_headline = opts.template.headline
591+
if type(template_headline) == 'function' then
592+
local ok, resolved_headline = pcall(template_headline)
593+
if not ok then
594+
utils.echo_error('Failed to resolve capture template headline')
595+
return false
596+
end
597+
template_headline = resolved_headline
598+
end
599+
if type(template_headline) ~= 'string' then
600+
utils.echo_error('Capture template headline function must return a string')
601+
return false
602+
end
603+
604+
opts.destination_headline = opts.destination_file:find_headline_by_title(template_headline)
591605
if not opts.destination_headline then
592-
utils.echo_error(('Refile headline "%s" does not exist in "%s"'):format(opts.template.headline, file))
606+
utils.echo_error(('Refile headline "%s" does not exist in "%s"'):format(template_headline, file))
593607
return false
594608
end
595609
end

lua/orgmode/capture/template/init.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ local expansions = {
8383
---@field template? string|string[]
8484
---@field target? string
8585
---@field datetree? OrgCaptureTemplateDatetree
86-
---@field headline? string
86+
---@field headline? string|fun():string
8787
---@field regexp? string
8888
---@field properties? OrgCaptureTemplateProperties
8989
---@field subtemplates? table<string, OrgCaptureTemplate>
@@ -102,7 +102,7 @@ function Template:new(opts)
102102
vim.validate('template', opts.template, { 'string', 'table' }, true)
103103
vim.validate('target', opts.target, 'string', true)
104104
vim.validate('regexp', opts.regexp, 'string', true)
105-
vim.validate('headline', opts.headline, 'string', true)
105+
vim.validate('headline', opts.headline, { 'string', 'function' }, true)
106106
vim.validate('properties', opts.properties, 'table', true)
107107
vim.validate('subtemplates', opts.subtemplates, 'table', true)
108108
vim.validate('datetree', opts.datetree, { 'boolean', 'table' }, true)

tests/plenary/capture/capture_spec.lua

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,4 +380,44 @@ describe('Capture', function()
380380
'* barbar',
381381
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
382382
end)
383+
384+
it('resolves function headline in template', function()
385+
local destination_file = helpers.create_file({
386+
'* dynamic title',
387+
'* barbar',
388+
})
389+
390+
local capture_file = helpers.create_file({ '* baz' })
391+
local item = capture_file:get_headlines()[1]
392+
local template = Template:new({
393+
target = destination_file.filename,
394+
headline = function()
395+
return 'dynamic title'
396+
end,
397+
})
398+
local capture_window = CaptureWindow:new({ template = template })
399+
---@diagnostic disable-next-line: invisible
400+
capture_window._bufnr = capture_file:bufnr()
401+
402+
---@diagnostic disable-next-line: invisible
403+
local opts = org.capture:_get_refile_vars(capture_window)
404+
assert.are.same(destination_file.filename, opts.destination_file.filename)
405+
assert.are.same('dynamic title', opts.destination_headline:get_title())
406+
407+
---@diagnostic disable-next-line: invisible
408+
org.capture:_refile_from_capture_buffer({
409+
destination_file = destination_file,
410+
source_file = capture_file,
411+
source_headline = item,
412+
destination_headline = opts.destination_headline,
413+
template = template,
414+
capture_window = capture_window,
415+
})
416+
vim.cmd('edit ' .. vim.fn.fnameescape(destination_file.filename))
417+
assert.are.same({
418+
'* dynamic title',
419+
'** baz',
420+
'* barbar',
421+
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
422+
end)
383423
end)

0 commit comments

Comments
 (0)